LCOV - code coverage report
Current view: top level - svl/source/numbers - zformat.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1437 2518 57.1 %
Date: 2014-11-03 Functions: 69 99 69.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <stdio.h>
      21             : #include <ctype.h>
      22             : #include <float.h>
      23             : #include <errno.h>
      24             : #include <stdlib.h>
      25             : #include <comphelper/string.hxx>
      26             : #include <tools/debug.hxx>
      27             : #include <osl/diagnose.h>
      28             : #include <i18nlangtag/mslangid.hxx>
      29             : #include <rtl/math.hxx>
      30             : #include <rtl/instance.hxx>
      31             : #include <unotools/charclass.hxx>
      32             : #include <unotools/calendarwrapper.hxx>
      33             : #include <unotools/nativenumberwrapper.hxx>
      34             : #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
      35             : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
      36             : #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
      37             : #include <com/sun/star/i18n/AmPmValue.hpp>
      38             : 
      39             : #include <svl/zformat.hxx>
      40             : #include "zforscan.hxx"
      41             : 
      42             : #include "zforfind.hxx"
      43             : #include <svl/zforlist.hxx>
      44             : #include "numhead.hxx"
      45             : #include <unotools/digitgroupingiterator.hxx>
      46             : #include <svl/nfsymbol.hxx>
      47             : 
      48             : #include <cmath>
      49             : #include <boost/scoped_ptr.hpp>
      50             : 
      51             : using namespace svt;
      52             : 
      53             : namespace {
      54             : struct Gregorian : public rtl::StaticWithInit<const OUString, Gregorian>
      55             : {
      56          40 :     const OUString operator () ()
      57             :         {
      58          40 :             return OUString("gregorian");
      59             :         }
      60             : };
      61             : 
      62             : const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary...
      63             : const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value.
      64             : 
      65             : } // namespace
      66             : 
      67             : const double _D_MAX_U_LONG_ = (double) 0xffffffff;      // 4294967295.0
      68             : const sal_uInt16 _MAX_FRACTION_PREC = 3;
      69             : const double D_EPS = 1.0E-2;
      70             : 
      71             : const double _D_MAX_D_BY_100  = 1.7E306;
      72             : const double _D_MIN_M_BY_1000 = 2.3E-305;
      73             : 
      74             : static const sal_uInt8 cCharWidths[ 128-32 ] = {
      75             :     1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
      76             :     2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
      77             :     3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
      78             :     2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
      79             :     1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
      80             :     2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
      81             : };
      82             : 
      83             : // static
      84         246 : sal_Int32 SvNumberformat::InsertBlanks( OUStringBuffer& r, sal_Int32 nPos, sal_Unicode c )
      85             : {
      86         246 :     if( c >= 32 )
      87             :     {
      88         246 :         int n = 2;   // Default for chars > 128 (HACK!)
      89         246 :         if( c <= 127 )
      90             :         {
      91         246 :             n = (int)cCharWidths[ c - 32 ];
      92             :         }
      93         738 :         while( n-- )
      94             :         {
      95         246 :             r.insert( nPos++, ' ');
      96             :         }
      97             :     }
      98         246 :     return nPos;
      99             : }
     100             : 
     101        5424 : static long GetPrecExp( double fAbsVal )
     102             : {
     103             :     DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" );
     104        5424 :     if ( fAbsVal < 1e-7 || fAbsVal > 1e7 )
     105             :     {
     106             :         // Shear: whether it's faster or not, falls in between 1e6 and 1e7
     107           8 :         return (long) floor( log10( fAbsVal ) ) + 1;
     108             :     }
     109             :     else
     110             :     {
     111        5416 :         long nPrecExp = 1;
     112       11314 :         while( fAbsVal < 1 )
     113             :         {
     114         482 :             fAbsVal *= 10;
     115         482 :             nPrecExp--;
     116             :         }
     117       19921 :         while( fAbsVal >= 10 )
     118             :         {
     119        9089 :             fAbsVal /= 10;
     120        9089 :             nPrecExp++;
     121             :         }
     122        5416 :         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             : /**
     131             :  * SvNumberformatInfo
     132             :  * */
     133             : 
     134        9864 : void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz )
     135             : {
     136       39374 :     for (sal_uInt16 i = 0; i < nAnz; ++i)
     137             :     {
     138       29510 :         sStrArray[i]  = rNumFor.sStrArray[i];
     139       29510 :         nTypeArray[i] = rNumFor.nTypeArray[i];
     140             :     }
     141        9864 :     eScannedType = rNumFor.eScannedType;
     142        9864 :     bThousand    = rNumFor.bThousand;
     143        9864 :     nThousand    = rNumFor.nThousand;
     144        9864 :     nCntPre      = rNumFor.nCntPre;
     145        9864 :     nCntPost     = rNumFor.nCntPost;
     146        9864 :     nCntExp      = rNumFor.nCntExp;
     147        9864 : }
     148             : 
     149           0 : void ImpSvNumberformatInfo::Save(SvStream& rStream, sal_uInt16 nAnz) const
     150             : {
     151           0 :     for (sal_uInt16 i = 0; i < nAnz; i++)
     152             :     {
     153           0 :         rStream.WriteUniOrByteString( sStrArray[i], rStream.GetStreamCharSet() );
     154           0 :         short nType = nTypeArray[i];
     155           0 :         switch ( nType )
     156             :         {
     157             :             // The fight with versions before SV_NUMBERFORMATTER_VERSION_NEW_CURR
     158             :             case NF_SYMBOLTYPE_CURRENCY :
     159           0 :                 rStream.WriteInt16( short( NF_SYMBOLTYPE_STRING ) );
     160           0 :             break;
     161             :             case NF_SYMBOLTYPE_CURRDEL :
     162             :             case NF_SYMBOLTYPE_CURREXT :
     163           0 :                 rStream.WriteInt16( short(0) ); // will be ignored (hopefully ...)
     164           0 :                 break;
     165             :             default:
     166           0 :                 if ( nType > NF_KEY_LASTKEYWORD_SO5 )
     167             :                 {
     168           0 :                     rStream.WriteInt16( short( NF_SYMBOLTYPE_STRING ) );  // all new keywords are string
     169             :                 }
     170             :                 else
     171             :                 {
     172           0 :                     rStream.WriteInt16( nType );
     173             :                 }
     174             :         }
     175             : 
     176             :     }
     177           0 :     rStream.WriteInt16( eScannedType ).WriteUChar( bThousand ).WriteUInt16( nThousand )
     178           0 :            .WriteUInt16( nCntPre ).WriteUInt16( nCntPost ).WriteUInt16( nCntExp );
     179           0 : }
     180             : 
     181           0 : void ImpSvNumberformatInfo::Load(SvStream& rStream, sal_uInt16 nAnz)
     182             : {
     183           0 :     for (sal_uInt16 i = 0; i < nAnz; ++i)
     184             :     {
     185           0 :         sStrArray[i] = SvNumberformat::LoadString( rStream );
     186           0 :         rStream.ReadInt16( nTypeArray[i] );
     187             :     }
     188             :     bool bStreamThousand;
     189           0 :     rStream.ReadInt16( eScannedType ).ReadCharAsBool( bStreamThousand ).ReadUInt16( nThousand )
     190           0 :            .ReadUInt16( nCntPre ).ReadUInt16( nCntPost ).ReadUInt16( nCntExp );
     191           0 :     bThousand = bStreamThousand;
     192           0 : }
     193             : 
     194             : 
     195             : // static
     196           0 : sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate )
     197             : {
     198           0 :     sal_uInt8 nNatNum = 0;
     199           0 :     eLang = MsLangId::getRealLanguage( eLang );  // resolve SYSTEM etc.
     200           0 :     eLang &= 0x03FF;    // 10 bit primary language
     201           0 :     if ( bDate )
     202             :     {
     203           0 :         if ( nDBNum == 4 && eLang == (LANGUAGE_KOREAN & 0x03FF) )
     204             :         {
     205           0 :             nNatNum = 9;
     206             :         }
     207           0 :         else if ( nDBNum <= 3 )
     208             :         {
     209           0 :             nNatNum = nDBNum;   // known to be good for: zh,ja,ko / 1,2,3
     210             :         }
     211             :     }
     212             :     else
     213             :     {
     214           0 :         switch ( nDBNum )
     215             :         {
     216             :         case 1:
     217           0 :             switch ( eLang )
     218             :             {
     219             :             case (LANGUAGE_CHINESE  & 0x03FF):
     220           0 :                 nNatNum = 4;
     221           0 :                 break;
     222             :             case (LANGUAGE_JAPANESE & 0x03FF):
     223           0 :                 nNatNum = 1;
     224           0 :                 break;
     225             :             case (LANGUAGE_KOREAN   & 0x03FF):
     226           0 :                 nNatNum = 1;
     227           0 :                 break;
     228             :             }
     229           0 :             break;
     230             :         case 2:
     231           0 :             switch ( eLang )
     232             :             {
     233             :             case (LANGUAGE_CHINESE  & 0x03FF):
     234           0 :                 nNatNum = 5;
     235           0 :                 break;
     236             :             case (LANGUAGE_JAPANESE & 0x03FF):
     237           0 :                 nNatNum = 4;
     238           0 :                 break;
     239             :             case (LANGUAGE_KOREAN   & 0x03FF):
     240           0 :                 nNatNum = 2;
     241           0 :                 break;
     242             :             }
     243           0 :             break;
     244             :         case 3:
     245           0 :             switch ( eLang )
     246             :             {
     247             :             case (LANGUAGE_CHINESE  & 0x03FF):
     248           0 :                 nNatNum = 6;
     249           0 :                 break;
     250             :             case (LANGUAGE_JAPANESE & 0x03FF):
     251           0 :                 nNatNum = 5;
     252           0 :                 break;
     253             :             case (LANGUAGE_KOREAN   & 0x03FF):
     254           0 :                 nNatNum = 3;
     255           0 :                 break;
     256             :             }
     257           0 :             break;
     258             :         case 4:
     259           0 :             switch ( eLang )
     260             :             {
     261             :             case (LANGUAGE_JAPANESE & 0x03FF):
     262           0 :                 nNatNum = 7;
     263           0 :                 break;
     264             :             case (LANGUAGE_KOREAN   & 0x03FF):
     265           0 :                 nNatNum = 9;
     266           0 :                 break;
     267             :             }
     268           0 :             break;
     269             :         }
     270             :     }
     271           0 :     return nNatNum;
     272             : }
     273             : 
     274             : #ifdef THE_FUTURE
     275             : /* XXX NOTE: even though the MapNatNumToDBNum method is currently unused please
     276             :  * don't remove it in case we'd have to use it for some obscure exports to
     277             :  * Excel. */
     278             : 
     279             : // static
     280             : sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate )
     281             : {
     282             :     sal_uInt8 nDBNum = 0;
     283             :     eLang = MsLangId::getRealLanguage( eLang );  // resolve SYSTEM etc.
     284             :     eLang &= 0x03FF;    // 10 bit primary language
     285             :     if ( bDate )
     286             :     {
     287             :         if ( nNatNum == 9 && eLang == (LANGUAGE_KOREAN & 0x03FF) )
     288             :         {
     289             :             nDBNum = 4;
     290             :         }
     291             :         else if ( nNatNum <= 3 )
     292             :         {
     293             :             nDBNum = nNatNum;   // known to be good for: zh,ja,ko / 1,2,3
     294             :         }
     295             :     }
     296             :     else
     297             :     {
     298             :         switch ( nNatNum )
     299             :         {
     300             :         case 1:
     301             :             switch ( eLang )
     302             :             {
     303             :             case (LANGUAGE_JAPANESE & 0x03FF):
     304             :                 nDBNum = 1;
     305             :                 break;
     306             :             case (LANGUAGE_KOREAN   & 0x03FF):
     307             :                 nDBNum = 1;
     308             :                 break;
     309             :             }
     310             :             break;
     311             :         case 2:
     312             :             switch ( eLang )
     313             :             {
     314             :             case (LANGUAGE_KOREAN   & 0x03FF):
     315             :                 nDBNum = 2;
     316             :                 break;
     317             :             }
     318             :             break;
     319             :         case 3:
     320             :             switch ( eLang )
     321             :             {
     322             :             case (LANGUAGE_KOREAN   & 0x03FF):
     323             :                 nDBNum = 3;
     324             :                 break;
     325             :             }
     326             :             break;
     327             :         case 4:
     328             :             switch ( eLang )
     329             :             {
     330             :             case (LANGUAGE_CHINESE  & 0x03FF):
     331             :                 nDBNum = 1;
     332             :                 break;
     333             :             case (LANGUAGE_JAPANESE & 0x03FF):
     334             :                 nDBNum = 2;
     335             :                 break;
     336             :             }
     337             :             break;
     338             :         case 5:
     339             :             switch ( eLang )
     340             :             {
     341             :             case (LANGUAGE_CHINESE  & 0x03FF):
     342             :                 nDBNum = 2;
     343             :                 break;
     344             :             case (LANGUAGE_JAPANESE & 0x03FF):
     345             :                 nDBNum = 3;
     346             :                 break;
     347             :             }
     348             :             break;
     349             :         case 6:
     350             :             switch ( eLang )
     351             :             {
     352             :             case (LANGUAGE_CHINESE  & 0x03FF):
     353             :                 nDBNum = 3;
     354             :                 break;
     355             :             }
     356             :             break;
     357             :         case 7:
     358             :             switch ( eLang )
     359             :             {
     360             :             case (LANGUAGE_JAPANESE & 0x03FF):
     361             :                 nDBNum = 4;
     362             :                 break;
     363             :             }
     364             :             break;
     365             :         case 8:
     366             :             break;
     367             :         case 9:
     368             :             switch ( eLang )
     369             :             {
     370             :             case (LANGUAGE_KOREAN   & 0x03FF):
     371             :                 nDBNum = 4;
     372             :                 break;
     373             :             }
     374             :             break;
     375             :         case 10:
     376             :             break;
     377             :         case 11:
     378             :             break;
     379             :         }
     380             :     }
     381             :     return nDBNum;
     382             : }
     383             : #endif
     384             : 
     385             : /**
     386             :  * SvNumFor
     387             :  */
     388             : 
     389     2295956 : ImpSvNumFor::ImpSvNumFor()
     390             : {
     391     2295956 :     nAnzStrings = 0;
     392     2295956 :     aI.nTypeArray = NULL;
     393     2295956 :     aI.sStrArray = NULL;
     394     2295956 :     aI.eScannedType = NUMBERFORMAT_UNDEFINED;
     395     2295956 :     aI.bThousand = false;
     396     2295956 :     aI.nThousand = 0;
     397     2295956 :     aI.nCntPre = 0;
     398     2295956 :     aI.nCntPost = 0;
     399     2295956 :     aI.nCntExp = 0;
     400     2295956 :     pColor = NULL;
     401     2295956 : }
     402             : 
     403     4547832 : ImpSvNumFor::~ImpSvNumFor()
     404             : {
     405     2273916 :     delete [] aI.sStrArray;
     406     2273916 :     delete [] aI.nTypeArray;
     407     2273916 : }
     408             : 
     409      698527 : void ImpSvNumFor::Enlarge(sal_uInt16 nAnz)
     410             : {
     411      698527 :     if ( nAnzStrings != nAnz )
     412             :     {
     413      692333 :         delete [] aI.nTypeArray;
     414      692333 :         delete [] aI.sStrArray;
     415      692333 :         nAnzStrings = nAnz;
     416      692333 :         if ( nAnz )
     417             :         {
     418      692333 :             aI.nTypeArray = new short[nAnz];
     419      692333 :             aI.sStrArray  = new OUString[nAnz];
     420             :         }
     421             :         else
     422             :         {
     423           0 :             aI.nTypeArray = NULL;
     424           0 :             aI.sStrArray  = NULL;
     425             :         }
     426             :     }
     427      698527 : }
     428             : 
     429        9864 : void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
     430             : {
     431        9864 :     Enlarge( rNumFor.nAnzStrings );
     432        9864 :     aI.Copy( rNumFor.aI, nAnzStrings );
     433        9864 :     sColorName = rNumFor.sColorName;
     434        9864 :     if ( pSc )
     435             :     {
     436        9864 :         pColor = pSc->GetColor( sColorName );   // #121103# don't copy pointer between documents
     437             :     }
     438             :     else
     439             :     {
     440           0 :         pColor = rNumFor.pColor;
     441             :     }
     442        9864 :     aNatNum = rNumFor.aNatNum;
     443        9864 : }
     444             : 
     445           0 : void ImpSvNumFor::Save(SvStream& rStream) const
     446             : {
     447           0 :     rStream.WriteUInt16( nAnzStrings );
     448           0 :     aI.Save(rStream, nAnzStrings);
     449           0 :     rStream.WriteUniOrByteString( sColorName, rStream.GetStreamCharSet() );
     450           0 : }
     451             : 
     452           0 : void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc,
     453             :                        OUString& rLoadedColorName )
     454             : {
     455             :     sal_uInt16 nAnz;
     456           0 :     rStream.ReadUInt16( nAnz ); //! Not nAnzStrings right away due to Enlarge
     457           0 :     Enlarge( nAnz );
     458           0 :     aI.Load( rStream, nAnz );
     459           0 :     sColorName = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
     460           0 :     rLoadedColorName = sColorName;
     461           0 :     pColor = rSc.GetColor(sColorName);
     462           0 : }
     463             : 
     464           0 : bool ImpSvNumFor::HasNewCurrency() const
     465             : {
     466           0 :     for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
     467             :     {
     468           0 :         if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
     469             :         {
     470           0 :             return true;
     471             :         }
     472             :     }
     473           0 :     return false;
     474             : }
     475             : 
     476       16122 : bool ImpSvNumFor::GetNewCurrencySymbol( OUString& rSymbol,
     477             :                                         OUString& rExtension ) const
     478             : {
     479       20478 :     for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
     480             :     {
     481        4534 :         if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
     482             :         {
     483         178 :             rSymbol = aI.sStrArray[j];
     484         178 :             if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT )
     485             :             {
     486          96 :                 rExtension = aI.sStrArray[j+1];
     487             :             }
     488             :             else
     489             :             {
     490          82 :                 rExtension = "";
     491             :             }
     492         178 :             return true;
     493             :         }
     494             :     }
     495             :     //! No Erase at rSymbol, rExtension
     496       15944 :     return false;
     497             : }
     498             : 
     499           0 : void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
     500             : {
     501             :     sal_uInt16 j;
     502           0 :     sal_uInt16 nCnt = 0;
     503           0 :     for ( j=0; j<nAnzStrings; j++ )
     504             :     {
     505           0 :         switch ( aI.nTypeArray[j] )
     506             :         {
     507             :         case NF_SYMBOLTYPE_CURRENCY :
     508             :         case NF_SYMBOLTYPE_CURRDEL :
     509             :         case NF_SYMBOLTYPE_CURREXT :
     510           0 :             nCnt++;
     511           0 :             break;
     512             :         }
     513             :     }
     514           0 :     rStream.WriteUInt16( nCnt );
     515           0 :     for ( j=0; j<nAnzStrings; j++ )
     516             :     {
     517           0 :         switch ( aI.nTypeArray[j] )
     518             :         {
     519             :         case NF_SYMBOLTYPE_CURRENCY :
     520             :         case NF_SYMBOLTYPE_CURRDEL :
     521             :         case NF_SYMBOLTYPE_CURREXT :
     522           0 :             rStream.WriteUInt16( j ).WriteInt16( aI.nTypeArray[j] );
     523           0 :             break;
     524             :         }
     525             :     }
     526           0 : }
     527             : 
     528           0 : void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
     529             : {
     530             :     sal_uInt16 nCnt;
     531           0 :     rStream.ReadUInt16(nCnt);
     532           0 :     if (!nCnt)
     533           0 :         return;
     534           0 :     for (sal_uInt16 j=0; j < nCnt; ++j)
     535             :     {
     536             :         sal_uInt16 nPos;
     537             :         short nType;
     538           0 :         rStream.ReadUInt16( nPos ).ReadInt16( nType );
     539           0 :         if ( nPos < nAnzStrings )
     540             :         {
     541           0 :             aI.nTypeArray[nPos] = nType;
     542             :         }
     543             :     }
     544             : }
     545             : 
     546             : /**
     547             :  * SvNumberformat
     548             :  */
     549             : 
     550             : enum BracketFormatSymbolType
     551             : {
     552             :     BRACKET_SYMBOLTYPE_FORMAT   = -1,   // subformat string
     553             :     BRACKET_SYMBOLTYPE_COLOR    = -2,   // color
     554             :     BRACKET_SYMBOLTYPE_ERROR    = -3,   // error
     555             :     BRACKET_SYMBOLTYPE_DBNUM1   = -4,   // DoubleByteNumber, represent numbers
     556             :     BRACKET_SYMBOLTYPE_DBNUM2   = -5,   // using CJK characters, Excel compatible
     557             :     BRACKET_SYMBOLTYPE_DBNUM3   = -6,
     558             :     BRACKET_SYMBOLTYPE_DBNUM4   = -7,
     559             :     BRACKET_SYMBOLTYPE_DBNUM5   = -8,
     560             :     BRACKET_SYMBOLTYPE_DBNUM6   = -9,
     561             :     BRACKET_SYMBOLTYPE_DBNUM7   = -10,
     562             :     BRACKET_SYMBOLTYPE_DBNUM8   = -11,
     563             :     BRACKET_SYMBOLTYPE_DBNUM9   = -12,
     564             :     BRACKET_SYMBOLTYPE_LOCALE   = -13,
     565             :     BRACKET_SYMBOLTYPE_NATNUM0  = -14,  // Our NativeNumber support, ASCII
     566             :     BRACKET_SYMBOLTYPE_NATNUM1  = -15,  // Our NativeNumber support, represent
     567             :     BRACKET_SYMBOLTYPE_NATNUM2  = -16,  // numbers using CJK, CTL, ...
     568             :     BRACKET_SYMBOLTYPE_NATNUM3  = -17,
     569             :     BRACKET_SYMBOLTYPE_NATNUM4  = -18,
     570             :     BRACKET_SYMBOLTYPE_NATNUM5  = -19,
     571             :     BRACKET_SYMBOLTYPE_NATNUM6  = -20,
     572             :     BRACKET_SYMBOLTYPE_NATNUM7  = -21,
     573             :     BRACKET_SYMBOLTYPE_NATNUM8  = -22,
     574             :     BRACKET_SYMBOLTYPE_NATNUM9  = -23,
     575             :     BRACKET_SYMBOLTYPE_NATNUM10 = -24,
     576             :     BRACKET_SYMBOLTYPE_NATNUM11 = -25,
     577             :     BRACKET_SYMBOLTYPE_NATNUM12 = -26,
     578             :     BRACKET_SYMBOLTYPE_NATNUM13 = -27,
     579             :     BRACKET_SYMBOLTYPE_NATNUM14 = -28,
     580             :     BRACKET_SYMBOLTYPE_NATNUM15 = -29,
     581             :     BRACKET_SYMBOLTYPE_NATNUM16 = -30,
     582             :     BRACKET_SYMBOLTYPE_NATNUM17 = -31,
     583             :     BRACKET_SYMBOLTYPE_NATNUM18 = -32,
     584             :     BRACKET_SYMBOLTYPE_NATNUM19 = -33
     585             : };
     586             : 
     587           0 : SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge )
     588             :     : fLimit1(0.0)
     589             :     , fLimit2(0.0)
     590             :     , rScan(rSc)
     591             :     , eOp1(NUMBERFORMAT_OP_NO)
     592             :     , eOp2(NUMBERFORMAT_OP_NO)
     593             :     , nNewStandardDefined(0)
     594             :     , eType(0)
     595             :     , bStarFlag( false )
     596             :     , bStandard( false )
     597           0 :     , bIsUsed( false )
     598             : {
     599           0 :     maLocale.meLanguage = eLge;
     600           0 : }
     601             : 
     602        2466 : void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat )
     603             : {
     604        2466 :     sFormatstring = rFormat.sFormatstring;
     605        2466 :     eType         = rFormat.eType;
     606        2466 :     maLocale      = rFormat.maLocale;
     607        2466 :     fLimit1       = rFormat.fLimit1;
     608        2466 :     fLimit2       = rFormat.fLimit2;
     609        2466 :     eOp1          = rFormat.eOp1;
     610        2466 :     eOp2          = rFormat.eOp2;
     611        2466 :     bStandard     = rFormat.bStandard;
     612        2466 :     bIsUsed       = rFormat.bIsUsed;
     613        2466 :     sComment      = rFormat.sComment;
     614        2466 :     nNewStandardDefined = rFormat.nNewStandardDefined;
     615             : 
     616             :     // #121103# when copying between documents, get color pointers from own scanner
     617        2466 :     ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL;
     618             : 
     619       12330 :     for (sal_uInt16 i = 0; i < 4; i++)
     620             :     {
     621        9864 :         NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
     622             :     }
     623        2466 : }
     624             : 
     625           0 : SvNumberformat::SvNumberformat( SvNumberformat& rFormat )
     626           0 :     : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag )
     627             : {
     628           0 :     ImpCopyNumberformat( rFormat );
     629           0 : }
     630             : 
     631        2466 : SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc )
     632             :     : rScan(rSc)
     633        2466 :     , bStarFlag( rFormat.bStarFlag )
     634             : {
     635        2466 :     ImpCopyNumberformat( rFormat );
     636        2466 : }
     637             : 
     638     1476024 : static bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
     639             : {
     640     1476024 :     if ( nSymbolType > 0  )
     641             :     {
     642         348 :         return true; // conditions
     643             :     }
     644     1475676 :     switch ( nSymbolType )
     645             :     {
     646             :     case BRACKET_SYMBOLTYPE_COLOR :
     647             :     case BRACKET_SYMBOLTYPE_DBNUM1 :
     648             :     case BRACKET_SYMBOLTYPE_DBNUM2 :
     649             :     case BRACKET_SYMBOLTYPE_DBNUM3 :
     650             :     case BRACKET_SYMBOLTYPE_DBNUM4 :
     651             :     case BRACKET_SYMBOLTYPE_DBNUM5 :
     652             :     case BRACKET_SYMBOLTYPE_DBNUM6 :
     653             :     case BRACKET_SYMBOLTYPE_DBNUM7 :
     654             :     case BRACKET_SYMBOLTYPE_DBNUM8 :
     655             :     case BRACKET_SYMBOLTYPE_DBNUM9 :
     656             :     case BRACKET_SYMBOLTYPE_LOCALE :
     657             :     case BRACKET_SYMBOLTYPE_NATNUM0 :
     658             :     case BRACKET_SYMBOLTYPE_NATNUM1 :
     659             :     case BRACKET_SYMBOLTYPE_NATNUM2 :
     660             :     case BRACKET_SYMBOLTYPE_NATNUM3 :
     661             :     case BRACKET_SYMBOLTYPE_NATNUM4 :
     662             :     case BRACKET_SYMBOLTYPE_NATNUM5 :
     663             :     case BRACKET_SYMBOLTYPE_NATNUM6 :
     664             :     case BRACKET_SYMBOLTYPE_NATNUM7 :
     665             :     case BRACKET_SYMBOLTYPE_NATNUM8 :
     666             :     case BRACKET_SYMBOLTYPE_NATNUM9 :
     667             :     case BRACKET_SYMBOLTYPE_NATNUM10 :
     668             :     case BRACKET_SYMBOLTYPE_NATNUM11 :
     669             :     case BRACKET_SYMBOLTYPE_NATNUM12 :
     670             :     case BRACKET_SYMBOLTYPE_NATNUM13 :
     671             :     case BRACKET_SYMBOLTYPE_NATNUM14 :
     672             :     case BRACKET_SYMBOLTYPE_NATNUM15 :
     673             :     case BRACKET_SYMBOLTYPE_NATNUM16 :
     674             :     case BRACKET_SYMBOLTYPE_NATNUM17 :
     675             :     case BRACKET_SYMBOLTYPE_NATNUM18 :
     676             :     case BRACKET_SYMBOLTYPE_NATNUM19 :
     677       98330 :         return true;
     678             :     }
     679     1377346 :     return false;
     680             : }
     681             : 
     682             : 
     683           4 : OUString SvNumberformat::ImpObtainCalendarAndNumerals( OUStringBuffer & rString, sal_Int32 & nPos,
     684             :                                                        LanguageType & nLang, const LocaleType & aTmpLocale )
     685             : {
     686           4 :     OUString sCalendar;
     687             :     /* TODO: this could be enhanced to allow other possible locale dependent
     688             :      * calendars and numerals. BUT only if our locale data allows it! For LCID
     689             :      * numerals and calendars see
     690             :      * http://office.microsoft.com/en-us/excel/HA010346351033.aspx */
     691           4 :     if (MsLangId::getRealLanguage( aTmpLocale.meLanguage) == LANGUAGE_THAI)
     692             :     {
     693             :         // Numeral shape code "D" = Thai digits.
     694           2 :         if (aTmpLocale.mnNumeralShape == 0xD)
     695             :         {
     696           0 :             rString.insert( nPos, "[NatNum1]");
     697             :         }
     698             :         // Calendar type code "07" = Thai Buddhist calendar, insert this after
     699             :         // all prefixes have been consumed as it is actually a format modifier
     700             :         // and not a prefix.
     701           2 :         if (aTmpLocale.mnCalendarType == 0x07)
     702             :         {
     703             :             // Currently calendars are tied to the locale of the entire number
     704             :             // format, e.g. [~buddhist] in en_US doesn't work.
     705             :             // => Having different locales in sub formats does not work!
     706             :             /* TODO: calendars could be tied to a sub format's NatNum info
     707             :              * instead, or even better be available for any locale. Needs a
     708             :              * different implementation of GetCal() and locale data calendars.
     709             :              * */
     710             :             // If this is not Thai yet, make it so.
     711           2 :             if (MsLangId::getRealLanguage( maLocale.meLanguage) != LANGUAGE_THAI)
     712             :             {
     713           0 :                 maLocale = aTmpLocale;
     714           0 :                 nLang = maLocale.meLanguage = LANGUAGE_THAI;
     715             :             }
     716           2 :             sCalendar="[~buddhist]";
     717             :         }
     718             :     }
     719           4 :     return sCalendar;
     720             : }
     721             : 
     722             : 
     723      571523 : SvNumberformat::SvNumberformat(OUString& rString,
     724             :                                ImpSvNumberformatScan* pSc,
     725             :                                ImpSvNumberInputScan* pISc,
     726             :                                sal_Int32& nCheckPos,
     727             :                                LanguageType& eLan,
     728             :                                bool bStan)
     729             :         : rScan(*pSc)
     730             :         , nNewStandardDefined(0)
     731      571523 :         , bStarFlag( false )
     732             : {
     733      571523 :     OUStringBuffer sBuff(rString);
     734             : 
     735             :     // If the group (AKA thousand) separator is a No-Break Space (French)
     736             :     // replace all occurrences by a simple space.
     737             :     // The same for Narrow No-Break Space just in case some locale uses it.
     738             :     // The tokens will be changed to the LocaleData separator again later on.
     739      571523 :     const OUString& rThSep = GetFormatter().GetNumThousandSep();
     740      571523 :     if ( rThSep.getLength() == 1)
     741             :     {
     742      571523 :         const sal_Unicode cNBSp = 0xA0;
     743      571523 :         const sal_Unicode cNNBSp = 0x202F;
     744      571523 :         if (rThSep[0] == cNBSp )
     745         578 :             sBuff.replace( cNBSp, ' ');
     746      570945 :         else if (rThSep[0] == cNNBSp )
     747           0 :             sBuff.replace( cNNBSp, ' ');
     748             :     }
     749             : 
     750      571523 :     if (rScan.GetConvertMode())
     751             :     {
     752       13978 :         maLocale.meLanguage = rScan.GetNewLnge();
     753       13978 :         eLan = maLocale.meLanguage; // Make sure to return switch
     754             :     }
     755             :     else
     756             :     {
     757      557545 :         maLocale.meLanguage = eLan;
     758             :     }
     759      571523 :     bStandard = bStan;
     760      571523 :     bIsUsed = false;
     761      571523 :     fLimit1 = 0.0;
     762      571523 :     fLimit2 = 0.0;
     763      571523 :     eOp1 = NUMBERFORMAT_OP_NO;
     764      571523 :     eOp2 = NUMBERFORMAT_OP_NO;
     765      571523 :     eType = NUMBERFORMAT_DEFINED;
     766             : 
     767      571523 :     bool bCancel = false;
     768      571523 :     bool bCondition = false;
     769             :     short eSymbolType;
     770      571523 :     sal_Int32 nPos = 0;
     771             :     sal_Int32 nPosOld;
     772      571523 :     nCheckPos = 0;
     773             : 
     774             :     // Split into 4 sub formats
     775             :     sal_uInt16 nIndex;
     776     1260198 :     for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ )
     777             :     {
     778             :         // Original language/country may have to be reestablished
     779      688675 :         if (rScan.GetConvertMode())
     780             :         {
     781       20450 :             (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge());
     782             :         }
     783      688675 :         OUString sInsertCalendar; // a calendar resulting from parsing LCID
     784     1377350 :         OUString sStr;
     785      688675 :         nPosOld = nPos; // Start position of substring
     786             :         // first get bracketed prefixes; e.g. conditions, color
     787      738187 :         do
     788             :         {
     789      738187 :             eSymbolType = ImpNextSymbol(sBuff, nPos, sStr);
     790      738187 :             if (eSymbolType > 0) // condition
     791             :             {
     792         348 :                 if ( nIndex == 0 && !bCondition )
     793             :                 {
     794         178 :                     bCondition = true;
     795         178 :                     eOp1 = (SvNumberformatLimitOps) eSymbolType;
     796             :                 }
     797         170 :                 else if ( nIndex == 1 && bCondition )
     798             :                 {
     799         170 :                     eOp2 = (SvNumberformatLimitOps) eSymbolType;
     800             :                 }
     801             :                 else                                // error
     802             :                 {
     803           0 :                     bCancel = true;                 // break for
     804           0 :                     nCheckPos = nPosOld;
     805             :                 }
     806         348 :                 if (!bCancel)
     807             :                 {
     808             :                     double fNumber;
     809         348 :                     sal_Int32 nAnzChars = ImpGetNumber(sBuff, nPos, sStr);
     810         348 :                     if (nAnzChars > 0)
     811             :                     {
     812         348 :                         short F_Type = NUMBERFORMAT_UNDEFINED;
     813         696 :                         if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
     814         348 :                             ( F_Type != NUMBERFORMAT_NUMBER &&
     815           0 :                               F_Type != NUMBERFORMAT_SCIENTIFIC) )
     816             :                         {
     817           0 :                             fNumber = 0.0;
     818           0 :                             nPos = nPos - nAnzChars;
     819           0 :                             sBuff.remove(nPos, nAnzChars);
     820           0 :                             sBuff.insert(nPos, '0');
     821           0 :                             nPos++;
     822             :                         }
     823             :                     }
     824             :                     else
     825             :                     {
     826           0 :                         fNumber = 0.0;
     827           0 :                         sBuff.insert(nPos++, '0');
     828             :                     }
     829         348 :                     if (nIndex == 0)
     830             :                     {
     831         178 :                         fLimit1 = fNumber;
     832             :                     }
     833             :                     else
     834             :                     {
     835         170 :                         fLimit2 = fNumber;
     836             :                     }
     837         348 :                     if ( sBuff[nPos] == ']' )
     838             :                     {
     839         348 :                         nPos++;
     840             :                     }
     841             :                     else
     842             :                     {
     843           0 :                         bCancel = true;             // break for
     844           0 :                         nCheckPos = nPos;
     845             :                     }
     846             :                 }
     847         348 :                 nPosOld = nPos;                     // position before string
     848             :             }
     849      737839 :             else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
     850             :             {
     851       49166 :                 OUString sSymbol( sStr);
     852       49166 :                 switch ( eSymbolType )
     853             :                 {
     854             :                 case BRACKET_SYMBOLTYPE_COLOR :
     855       48928 :                     if ( NumFor[nIndex].GetColor() != NULL )
     856             :                     {                           // error, more than one color
     857           0 :                         bCancel = true;         // break for
     858           0 :                         nCheckPos = nPosOld;
     859             :                     }
     860             :                     else
     861             :                     {
     862       48928 :                         Color* pColor = pSc->GetColor( sStr);
     863       48928 :                         NumFor[nIndex].SetColor( pColor, sStr);
     864       48928 :                         if (pColor == NULL)
     865             :                         {                       // error
     866           2 :                             bCancel = true;     // break for
     867           2 :                             nCheckPos = nPosOld;
     868             :                         }
     869             :                     }
     870       48928 :                     break;
     871             :                 case BRACKET_SYMBOLTYPE_NATNUM0 :
     872             :                 case BRACKET_SYMBOLTYPE_NATNUM1 :
     873             :                 case BRACKET_SYMBOLTYPE_NATNUM2 :
     874             :                 case BRACKET_SYMBOLTYPE_NATNUM3 :
     875             :                 case BRACKET_SYMBOLTYPE_NATNUM4 :
     876             :                 case BRACKET_SYMBOLTYPE_NATNUM5 :
     877             :                 case BRACKET_SYMBOLTYPE_NATNUM6 :
     878             :                 case BRACKET_SYMBOLTYPE_NATNUM7 :
     879             :                 case BRACKET_SYMBOLTYPE_NATNUM8 :
     880             :                 case BRACKET_SYMBOLTYPE_NATNUM9 :
     881             :                 case BRACKET_SYMBOLTYPE_NATNUM10 :
     882             :                 case BRACKET_SYMBOLTYPE_NATNUM11 :
     883             :                 case BRACKET_SYMBOLTYPE_NATNUM12 :
     884             :                 case BRACKET_SYMBOLTYPE_NATNUM13 :
     885             :                 case BRACKET_SYMBOLTYPE_NATNUM14 :
     886             :                 case BRACKET_SYMBOLTYPE_NATNUM15 :
     887             :                 case BRACKET_SYMBOLTYPE_NATNUM16 :
     888             :                 case BRACKET_SYMBOLTYPE_NATNUM17 :
     889             :                 case BRACKET_SYMBOLTYPE_NATNUM18 :
     890             :                 case BRACKET_SYMBOLTYPE_NATNUM19 :
     891         210 :                     if ( NumFor[nIndex].GetNatNum().IsSet() )
     892             :                     {
     893           0 :                         bCancel = true;         // break for
     894           0 :                         nCheckPos = nPosOld;
     895             :                     }
     896             :                     else
     897             :                     {
     898         210 :                         sStr = "NatNum";
     899             :                         //! eSymbolType is negative
     900         210 :                         sal_uInt8 nNum = (sal_uInt8)(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
     901         210 :                         sStr += OUString::number( nNum );
     902         210 :                         NumFor[nIndex].SetNatNumNum( nNum, false );
     903             :                     }
     904         210 :                     break;
     905             :                 case BRACKET_SYMBOLTYPE_DBNUM1 :
     906             :                 case BRACKET_SYMBOLTYPE_DBNUM2 :
     907             :                 case BRACKET_SYMBOLTYPE_DBNUM3 :
     908             :                 case BRACKET_SYMBOLTYPE_DBNUM4 :
     909             :                 case BRACKET_SYMBOLTYPE_DBNUM5 :
     910             :                 case BRACKET_SYMBOLTYPE_DBNUM6 :
     911             :                 case BRACKET_SYMBOLTYPE_DBNUM7 :
     912             :                 case BRACKET_SYMBOLTYPE_DBNUM8 :
     913             :                 case BRACKET_SYMBOLTYPE_DBNUM9 :
     914           0 :                     if ( NumFor[nIndex].GetNatNum().IsSet() )
     915             :                     {
     916           0 :                         bCancel = true;         // break for
     917           0 :                         nCheckPos = nPosOld;
     918             :                     }
     919             :                     else
     920             :                     {
     921           0 :                         sStr = "DBNum";
     922             :                         //! eSymbolType is negative
     923           0 :                         sal_uInt8 nNum = (sal_uInt8)(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
     924           0 :                         sStr += OUString((sal_Unicode)('0' + nNum));
     925           0 :                         NumFor[nIndex].SetNatNumNum( nNum, true );
     926             :                     }
     927           0 :                     break;
     928             :                 case BRACKET_SYMBOLTYPE_LOCALE :
     929          56 :                     if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ||
     930          28 :                          sBuff[nPos-1] != ']' )
     931             :                         // Check also for ']' to avoid pulling in
     932             :                         // locale data for the preview string for not
     933             :                         // yet completed LCIDs in the dialog.
     934             :                     {
     935           0 :                         bCancel = true;         // break for
     936           0 :                         nCheckPos = nPosOld;
     937             :                     }
     938             :                     else
     939             :                     {
     940          28 :                         sal_Int32 nTmp = 2;
     941          28 :                         LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp));
     942          28 :                         if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW)
     943             :                         {
     944           0 :                             bCancel = true;         // break for
     945           0 :                             nCheckPos = nPosOld;
     946             :                         }
     947             :                         else
     948             :                         {
     949             :                             // Only the first sub format's locale will be
     950             :                             // used as the format's overall locale.
     951             :                             // Sorts this also under the corresponding
     952             :                             // locale for the dialog.
     953             :                             // If we don't support the locale this would
     954             :                             // result in an unknown (empty) language
     955             :                             // listbox entry and the user would never see
     956             :                             // this format.
     957          54 :                             if (nIndex == 0 && (aTmpLocale.meLanguage == 0 ||
     958          26 :                                                 SvNumberFormatter::IsLocaleInstalled( aTmpLocale.meLanguage)))
     959             :                             {
     960          20 :                                 maLocale = aTmpLocale;
     961          20 :                                 eLan = aTmpLocale.meLanguage;   // return to caller
     962             :                                 /* TODO: fiddle with scanner to make this
     963             :                                  * known? A change in the locale may affect
     964             :                                  * separators and keywords. On the other
     965             :                                  * hand they may have been entered as used
     966             :                                  * in the originating locale, there's no
     967             :                                  * way to predict other than analyzing the
     968             :                                  * format code, we assume here the current
     969             :                                  * context is used, which is most likely
     970             :                                  * the case.
     971             :                                  * */
     972             :                             }
     973          28 :                             sStr = "$-" + aTmpLocale.generateCode();
     974          28 :                             NumFor[nIndex].SetNatNumLang( MsLangId::getRealLanguage( aTmpLocale.meLanguage));
     975             : 
     976             :                             // "$-NNCCLLLL" Numerals and Calendar
     977          28 :                             if (sSymbol.getLength() > 6)
     978             :                             {
     979           4 :                                 sInsertCalendar = ImpObtainCalendarAndNumerals( sBuff, nPos, eLan, aTmpLocale);
     980             :                             }
     981             :                             /* NOTE: there can be only one calendar
     982             :                              * inserted so the last one wins, though
     983             :                              * our own calendar modifiers support
     984             :                              * multiple calendars within one sub format
     985             :                              * code if at different positions. */
     986             :                         }
     987             :                     }
     988          28 :                     break;
     989             :                 }
     990       49166 :                 if ( !bCancel )
     991             :                 {
     992       49164 :                     if (sStr == sSymbol)
     993             :                     {
     994       48738 :                         nPosOld = nPos;
     995             :                     }
     996             :                     else
     997             :                     {
     998         426 :                         sBuff.remove(nPosOld, nPos - nPosOld);
     999         426 :                         if (!sStr.isEmpty())
    1000             :                         {
    1001         426 :                             sBuff.insert(nPosOld, sStr);
    1002         426 :                             nPos = nPosOld + sStr.getLength();
    1003         426 :                             sBuff.insert(nPos, "]");
    1004         426 :                             sBuff.insert(nPosOld, "[");
    1005         426 :                             nPos += 2;
    1006         426 :                             nPosOld = nPos;     // position before string
    1007             :                         }
    1008             :                         else
    1009             :                         {
    1010           0 :                             nPos = nPosOld;     // prefix removed for whatever reason
    1011             :                         }
    1012             :                     }
    1013       49166 :                 }
    1014             :             }
    1015             :         }
    1016      738187 :         while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
    1017             : 
    1018             :         // The remaining format code string
    1019      688675 :         if ( !bCancel )
    1020             :         {
    1021      688673 :             if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT)
    1022             :             {
    1023      688673 :                 if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO)
    1024             :                 {
    1025      114218 :                     eOp1 = NUMBERFORMAT_OP_GT;  // undefined condition, default: > 0
    1026             :                 }
    1027      574455 :                 else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
    1028             :                 {
    1029        1260 :                     eOp2 = NUMBERFORMAT_OP_LT;  // undefined condition, default: < 0
    1030             :                 }
    1031      688673 :                 if (sStr.isEmpty())
    1032             :                 {
    1033             :                     // empty sub format
    1034             :                 }
    1035             :                 else
    1036             :                 {
    1037      688667 :                     if (!sInsertCalendar.isEmpty())
    1038             :                     {
    1039           2 :                         sStr = sInsertCalendar + sStr;
    1040             :                     }
    1041      688667 :                     sal_Int32 nStrPos = pSc->ScanFormat( sStr);
    1042      688667 :                     sal_uInt16 nAnz = pSc->GetAnzResStrings();
    1043      688667 :                     if (nAnz == 0)              // error
    1044             :                     {
    1045           0 :                         nStrPos = 1;
    1046             :                     }
    1047      688667 :                     if (nStrPos == 0)               // ok
    1048             :                     {
    1049             :                         // e.g. Thai T speciality
    1050      688663 :                         if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
    1051             :                         {
    1052           0 :                             sStr = "[NatNum"  + OUString::number( pSc->GetNatNumModifier()) + "]" + sStr;
    1053           0 :                             NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), false );
    1054             :                         }
    1055             :                         // #i53826# #i42727# For the Thai T speciality we need
    1056             :                         // to freeze the locale and immunize it against
    1057             :                         // conversions during exports, just in case we want to
    1058             :                         // save to Xcl. This disables the feature of being able
    1059             :                         // to convert a NatNum to another locale. You can't
    1060             :                         // have both.
    1061             :                         // FIXME: implement a specialized export conversion
    1062             :                         // that works on tokens (have to tokenize all first)
    1063             :                         // and doesn't use the format string and
    1064             :                         // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
    1065             :                         // sc/source/filter/excel/xestyle.cxx
    1066             :                         // XclExpNumFmtBuffer::WriteFormatRecord().
    1067             :                         LanguageType eLanguage;
    1068     1377536 :                         if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
    1069      688849 :                             ((eLanguage = MsLangId::getRealLanguage( eLan)) == LANGUAGE_THAI) &&
    1070         186 :                             NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW)
    1071             :                         {
    1072         182 :                             sStr = "[$-" + OUString::number( eLanguage, 16 ).toAsciiUpperCase() + "]" + sStr;
    1073         182 :                             NumFor[nIndex].SetNatNumLang( eLanguage);
    1074             :                         }
    1075      688663 :                         sBuff.remove(nPosOld, nPos - nPosOld);
    1076      688663 :                         sBuff.insert(nPosOld, sStr);
    1077      688663 :                         nPos = nPosOld + sStr.getLength();
    1078      688663 :                         if (nPos < sBuff.getLength())
    1079             :                         {
    1080      117146 :                             sBuff.insert(nPos, ";");
    1081      117146 :                             nPos++;
    1082             :                         }
    1083      688663 :                         NumFor[nIndex].Enlarge(nAnz);
    1084      688663 :                         pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
    1085             :                         // type check
    1086      688663 :                         if (nIndex == 0)
    1087             :                         {
    1088      571515 :                             eType = (short) NumFor[nIndex].Info().eScannedType;
    1089             :                         }
    1090      117148 :                         else if (nIndex == 3)
    1091             :                         {   // #77026# Everything recognized IS text
    1092        1326 :                             NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT;
    1093             :                         }
    1094      115822 :                         else if ( (short) NumFor[nIndex].Info().eScannedType != eType)
    1095             :                         {
    1096         672 :                             eType = NUMBERFORMAT_DEFINED;
    1097             :                         }
    1098             :                     }
    1099             :                     else
    1100             :                     {
    1101           4 :                         nCheckPos = nPosOld + nStrPos;  // error in string
    1102           4 :                         bCancel = true;                 // break for
    1103             :                     }
    1104             :                 }
    1105             :             }
    1106           0 :             else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR)   // error
    1107             :             {
    1108           0 :                 nCheckPos = nPosOld;
    1109           0 :                 bCancel = true;
    1110             :             }
    1111           0 :             else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
    1112             :             {
    1113           0 :                 nCheckPos = nPosOld + 1;                // error, prefix in string
    1114           0 :                 bCancel = true;                         // break for
    1115             :             }
    1116             :         }
    1117      688675 :         if ( bCancel && !nCheckPos )
    1118             :         {
    1119           2 :             nCheckPos = 1;      // nCheckPos is used as an error condition
    1120             :         }
    1121      688675 :         if ( !bCancel )
    1122             :         {
    1123      688879 :             if ( NumFor[nIndex].GetNatNum().IsSet() &&
    1124         210 :                  NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
    1125             :             {
    1126          24 :                  NumFor[nIndex].SetNatNumLang( eLan );
    1127             :             }
    1128             :         }
    1129      688675 :         if (sBuff.getLength() == nPos)
    1130             :         {
    1131      571625 :             if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT &&
    1132         104 :                  sBuff[nPos - 1] == ';' )
    1133             :             {
    1134             :                 // #83510# A 4th subformat explicitly specified to be empty
    1135             :                 // hides any text. Need the type here for HasTextFormat()
    1136           0 :                 NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT;
    1137             :             }
    1138      571521 :             bCancel = true;
    1139             :         }
    1140      688675 :         if ( NumFor[nIndex].GetNatNum().IsSet() )
    1141             :         {
    1142         210 :             NumFor[nIndex].SetNatNumDate( (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 );
    1143             :         }
    1144      688675 :     }
    1145             : 
    1146      571523 :     if ( bCondition && !nCheckPos )
    1147             :     {
    1148         178 :         if ( nIndex == 1 && NumFor[0].GetCount() == 0 &&
    1149           0 :              sBuff[sBuff.getLength() - 1] != ';' )
    1150             :         {
    1151             :             // No format code => GENERAL but not if specified empty
    1152           0 :             OUString aAdd( pSc->GetStandardName() );
    1153           0 :             if ( !pSc->ScanFormat( aAdd ) )
    1154             :             {
    1155           0 :                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
    1156           0 :                 if ( nAnz )
    1157             :                 {
    1158           0 :                     NumFor[0].Enlarge(nAnz);
    1159           0 :                     pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
    1160           0 :                     sBuff.append(aAdd);
    1161             :                 }
    1162           0 :             }
    1163             :         }
    1164         178 :         else if ( nIndex == 1 && NumFor[nIndex].GetCount() == 0 &&
    1165         178 :                   sBuff[sBuff.getLength() - 1] != ';' &&
    1166           0 :                   (NumFor[0].GetCount() > 1 ||
    1167           0 :                    (NumFor[0].GetCount() == 1 &&
    1168           0 :                     NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) )
    1169             :         {
    1170             :             // No trailing second subformat => GENERAL but not if specified empty
    1171             :             // and not if first subformat is GENERAL
    1172           0 :             OUString aAdd( pSc->GetStandardName() );
    1173           0 :             if ( !pSc->ScanFormat( aAdd ) )
    1174             :             {
    1175           0 :                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
    1176           0 :                 if ( nAnz )
    1177             :                 {
    1178           0 :                     NumFor[nIndex].Enlarge(nAnz);
    1179           0 :                     pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
    1180           0 :                     sBuff.append(";");
    1181           0 :                     sBuff.append(aAdd);
    1182             :                 }
    1183           0 :             }
    1184             :         }
    1185         194 :         else if ( nIndex == 2 && NumFor[nIndex].GetCount() == 0 &&
    1186         194 :                   sBuff[sBuff.getLength() - 1] != ';' &&
    1187           8 :                   eOp2 != NUMBERFORMAT_OP_NO )
    1188             :         {
    1189             :             // No trailing third subformat => GENERAL but not if specified empty
    1190           0 :             OUString aAdd( pSc->GetStandardName() );
    1191           0 :             if ( !pSc->ScanFormat( aAdd ) )
    1192             :             {
    1193           0 :                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
    1194           0 :                 if ( nAnz )
    1195             :                 {
    1196           0 :                     NumFor[nIndex].Enlarge(nAnz);
    1197           0 :                     pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
    1198           0 :                     sBuff.append(";");
    1199           0 :                     sBuff.append(aAdd);
    1200             :                 }
    1201           0 :             }
    1202             :         }
    1203             :     }
    1204      571523 :     rString = sBuff.makeStringAndClear();
    1205      571523 :     sFormatstring = rString;
    1206             : 
    1207     1713141 :     if (NumFor[2].GetCount() == 0 && // No third partial string
    1208      796013 :         eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
    1209      797439 :         fLimit1 == 0.0 && fLimit2 == 0.0)
    1210             :     {
    1211      112958 :         eOp1 = NUMBERFORMAT_OP_GE; // Add 0 to the first format
    1212      571523 :     }
    1213             : 
    1214      571523 : }
    1215             : 
    1216      568479 : SvNumberformat::~SvNumberformat()
    1217             : {
    1218      568479 : }
    1219             : 
    1220             : /**
    1221             :  * Next_Symbol
    1222             :  *
    1223             :  * Splits up the symbols for further processing (by the Turing machine)
    1224             :  *
    1225             :  * Start state = SsStart, * = Special state
    1226             :  * ---------------+-------------------+----------------------------+---------------
    1227             :  *  Old State     | Symbol read       | Event                      | New state
    1228             :  * ---------------+-------------------+----------------------------+---------------
    1229             :  *  SsStart       | ;                 | Pos--                      | SsGetString
    1230             :  *                | [                 | Symbol += Character        | SsGetBracketed
    1231             :  *                | ]                 | Error                      | SsStop
    1232             :  *                | BLANK             |                            |
    1233             :  *                | Else              | Symbol += Character        | SsGetString
    1234             :  * ---------------+-------------------+----------------------------+---------------
    1235             :  *  SsGetString   | ;                 |                            | SsStop
    1236             :  *                | Else              | Symbol += Character        |
    1237             :  * ---------------+-------------------+----------------------------+---------------
    1238             :  * SsGetBracketed | <, > =            | del [                      |
    1239             :  *                |                   | Symbol += Character        | SsGetCon
    1240             :  *                | BLANK             |                            |
    1241             :  *                | h, H, m, M, s, S  | Symbol += Character        | SsGetTime
    1242             :  *                | Else              | del [                      |
    1243             :  *                |                   | Symbol += Character        | SsGetPrefix
    1244             :  * ---------------+-------------------+----------------------------+---------------
    1245             :  *  SsGetTime     | ]                 | Symbol += Character        | SsGetString
    1246             :  *                | h, H, m, M, s, S  | Symbol += Character, *     | SsGetString
    1247             :  *                | Else              | del [; Symbol += Character | SsGetPrefix
    1248             :  * ---------------+-------------------+----------------------------+---------------
    1249             :  *  SsGetPrefix   | ]                 |                            | SsStop
    1250             :  *                | Else              | Symbol += Character        |
    1251             :  * ---------------+-------------------+----------------------------+---------------
    1252             :  *  SsGetCon      | >, =              | Symbol += Character        |
    1253             :  *                | ]                 |                            | SsStop
    1254             :  *                | Else              | Error                      | SsStop
    1255             :  * ---------------+-------------------+----------------------------+---------------
    1256             :  */
    1257             : 
    1258             : enum ScanState
    1259             : {
    1260             :     SsStop,
    1261             :     SsStart,
    1262             :     SsGetCon,           // condition
    1263             :     SsGetString,        // format string
    1264             :     SsGetPrefix,        // color or NatNumN
    1265             :     SsGetTime,          // [HH] for time
    1266             :     SsGetBracketed      // any [...] not decided yet
    1267             : };
    1268             : 
    1269             : // read a string until ']' and delete spaces in input
    1270             : // static
    1271         348 : sal_Int32 SvNumberformat::ImpGetNumber(OUStringBuffer& rString,
    1272             :                                        sal_Int32& nPos,
    1273             :                                        OUString& sSymbol)
    1274             : {
    1275         348 :     sal_Int32 nStartPos = nPos;
    1276             :     sal_Unicode cToken;
    1277         348 :     sal_Int32 nLen = rString.getLength();
    1278         348 :     OUStringBuffer sBuffSymbol;
    1279        1044 :     while ( nPos < nLen && ((cToken = rString[nPos]) != ']') )
    1280             :     {
    1281         348 :         if (cToken == ' ')
    1282             :         {                                               // delete spaces
    1283           0 :             rString.remove(nPos,1);
    1284           0 :             nLen--;
    1285             :         }
    1286             :         else
    1287             :         {
    1288         348 :             nPos++;
    1289         348 :             sBuffSymbol.append(cToken);
    1290             :         }
    1291             :     }
    1292         348 :     sSymbol = sBuffSymbol.makeStringAndClear();
    1293         348 :     return nPos - nStartPos;
    1294             : }
    1295             : 
    1296             : namespace {
    1297             : 
    1298          88 : sal_Unicode toUniChar(sal_uInt8 n)
    1299             : {
    1300             :     sal_Char c;
    1301          88 :     if (n < 10)
    1302             :     {
    1303          74 :         c = '0' + n;
    1304             :     }
    1305             :     else
    1306             :     {
    1307          14 :         c = 'A' + n - 10;
    1308             :     }
    1309          88 :     return sal_Unicode(c);
    1310             : }
    1311             : 
    1312      117150 : bool IsCombiningSymbol( OUStringBuffer& rStringBuffer, sal_Int32 nPos )
    1313             : {
    1314      117150 :     bool bRet = false;
    1315      234300 :     while (nPos >= 0)
    1316             :     {
    1317      117150 :         switch (rStringBuffer[nPos])
    1318             :         {
    1319             :             case '*':
    1320             :             case '\\':
    1321             :             case '_':
    1322           0 :                 bRet = !bRet;
    1323           0 :                 --nPos;
    1324           0 :                 break;
    1325             :             default:
    1326      117150 :                 return bRet;
    1327             :         }
    1328             :     }
    1329           0 :     return bRet;
    1330             : }
    1331             : 
    1332             : } // namespace
    1333             : 
    1334          28 : OUString SvNumberformat::LocaleType::generateCode() const
    1335             : {
    1336          28 :     OUStringBuffer aBuf;
    1337             : #if 0
    1338             :     // TODO: We may re-enable this later. Don't remove it! --Kohei
    1339             :     if (mnNumeralShape)
    1340             :     {
    1341             :         sal_uInt8 nVal = mnNumeralShape;
    1342             :         for (sal_uInt8 i = 0; i < 2; ++i)
    1343             :         {
    1344             :             sal_uInt8 n = (nVal & 0xF0) >> 4;
    1345             :             if (n || aBuf.getLength())
    1346             :             {
    1347             :                 aBuf.append(toUniChar(n));
    1348             :             }
    1349             :             nVal = nVal << 4;
    1350             :         }
    1351             :     }
    1352             : 
    1353             :     if (mnNumeralShape || mnCalendarType)
    1354             :     {
    1355             :         sal_uInt8 nVal = mnCalendarType;
    1356             :         for (sal_uInt8 i = 0; i < 2; ++i)
    1357             :         {
    1358             :             sal_uInt8 n = (nVal & 0xF0) >> 4;
    1359             :             if (n || aBuf.getLength())
    1360             :             {
    1361             :                 aBuf.append(toUniChar(n));
    1362             :             }
    1363             :             nVal = nVal << 4;
    1364             :         }
    1365             :     }
    1366             : #endif
    1367             : 
    1368          28 :     sal_uInt16 n16 = static_cast<sal_uInt16>(meLanguage);
    1369         140 :     for (sal_uInt8 i = 0; i < 4; ++i)
    1370             :     {
    1371         112 :         sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12);
    1372             :         // Omit leading zeros for consistency.
    1373         112 :         if (n || !aBuf.isEmpty() || i == 3)
    1374             :         {
    1375          88 :             aBuf.append(toUniChar(n));
    1376             :         }
    1377         112 :         n16 = n16 << 4;
    1378             :     }
    1379             : 
    1380          28 :     return aBuf.makeStringAndClear();
    1381             : }
    1382             : 
    1383      573989 : SvNumberformat::LocaleType::LocaleType()
    1384             :     : mnNumeralShape(0)
    1385             :     , mnCalendarType(0)
    1386      573989 :     , meLanguage(LANGUAGE_DONTKNOW)
    1387             : {
    1388      573989 : }
    1389             : 
    1390          28 : SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum)
    1391             :     : mnNumeralShape(0)
    1392             :     , mnCalendarType(0)
    1393          28 :     , meLanguage(LANGUAGE_DONTKNOW)
    1394             : {
    1395          28 :     meLanguage = static_cast<LanguageType>(nRawNum & 0x0000FFFF);
    1396          28 :     nRawNum = (nRawNum >> 16);
    1397          28 :     mnCalendarType = static_cast<sal_uInt8>(nRawNum & 0xFF);
    1398          28 :     nRawNum = (nRawNum >> 8);
    1399          28 :     mnNumeralShape = static_cast<sal_uInt8>(nRawNum & 0xFF);
    1400          28 : }
    1401             : 
    1402             : // static
    1403          28 : SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType(const OUString& rString, sal_Int32& nPos )
    1404             : {
    1405          28 :     sal_uInt32 nNum = 0;
    1406          28 :     sal_Unicode cToken = 0;
    1407          28 :     sal_Int32 nStart = nPos;
    1408          28 :     sal_Int32 nLen = rString.getLength();
    1409         164 :     while ( nPos < nLen && (nPos - nStart < 8) && ((cToken = rString[nPos]) != ']') )
    1410             :     {
    1411         108 :         if ( '0' <= cToken && cToken <= '9' )
    1412             :         {
    1413          94 :             nNum *= 16;
    1414          94 :             nNum += cToken - '0';
    1415             :         }
    1416          14 :         else if ( 'a' <= cToken && cToken <= 'f' )
    1417             :         {
    1418           0 :             nNum *= 16;
    1419           0 :             nNum += cToken - 'a' + 10;
    1420             :         }
    1421          14 :         else if ( 'A' <= cToken && cToken <= 'F' )
    1422             :         {
    1423          14 :             nNum *= 16;
    1424          14 :             nNum += cToken - 'A' + 10;
    1425             :         }
    1426             :         else
    1427             :         {
    1428           0 :             return LANGUAGE_DONTKNOW;
    1429             :         }
    1430         108 :         ++nPos;
    1431             :     }
    1432             : 
    1433          28 :     return (cToken == ']' || nPos == nLen) ? LocaleType(nNum) : LocaleType();
    1434             : }
    1435             : 
    1436      130498 : static bool lcl_matchKeywordAndGetNumber( const OUString & rString, const sal_Int32 nPos,
    1437             :         const OUString & rKeyword, sal_Int32 & nNumber )
    1438             : {
    1439      130498 :     if (0 <= nPos && nPos + rKeyword.getLength() < rString.getLength() && rString.matchIgnoreAsciiCase( rKeyword, nPos))
    1440             :     {
    1441         212 :         nNumber = rString.copy( nPos + rKeyword.getLength()).toInt32();
    1442         212 :         return true;
    1443             :     }
    1444             :     else
    1445             :     {
    1446      130286 :         nNumber = 0;
    1447      130286 :         return false;
    1448             :     }
    1449             : }
    1450             : 
    1451      738187 : short SvNumberformat::ImpNextSymbol(OUStringBuffer& rString,
    1452             :                                     sal_Int32& nPos,
    1453             :                                     OUString& sSymbol)
    1454             : {
    1455      738187 :     short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1456             :     sal_Unicode cToken;
    1457      738187 :     sal_Unicode cLetter = ' '; // Preliminary result
    1458      738187 :     sal_Int32 nLen = rString.getLength();
    1459      738187 :     ScanState eState = SsStart;
    1460      738187 :     OUStringBuffer sBuffSymbol;
    1461             : 
    1462      738187 :     const NfKeywordTable & rKeywords = rScan.GetKeywords();
    1463     9420361 :     while (nPos < nLen && eState != SsStop)
    1464             :     {
    1465     7943987 :         cToken = rString[nPos];
    1466     7943987 :         nPos++;
    1467     7943987 :         switch (eState)
    1468             :         {
    1469             :         case SsStart:
    1470      738259 :             if (cToken == '[')
    1471             :             {
    1472      198230 :                 eState = SsGetBracketed;
    1473      198230 :                 sBuffSymbol.append(cToken);
    1474             :             }
    1475      540029 :             else if (cToken == ';')
    1476             :             {
    1477           6 :                 eState = SsGetString;
    1478           6 :                 nPos--;
    1479           6 :                 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1480             :             }
    1481      540023 :             else if (cToken == ']')
    1482             :             {
    1483           0 :                 eState = SsStop;
    1484           0 :                 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
    1485             :             }
    1486      540023 :             else if (cToken == ' ') // Skip Blanks
    1487             :             {
    1488          72 :                 nPos--;
    1489          72 :                 rString.remove(nPos, 1);
    1490          72 :                 nLen--;
    1491             :             }
    1492             :             else
    1493             :             {
    1494      539951 :                 sBuffSymbol.append(cToken);
    1495      539951 :                 eState = SsGetString;
    1496      539951 :                 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1497             :             }
    1498      738259 :             break;
    1499             :         case SsGetBracketed:
    1500      198230 :             switch (cToken)
    1501             :             {
    1502             :             case '<':
    1503             :             case '>':
    1504             :             case '=':
    1505         348 :                 sBuffSymbol.stripStart('[');
    1506         348 :                 sBuffSymbol.append(cToken);
    1507         348 :                 cLetter = cToken;
    1508         348 :                 eState = SsGetCon;
    1509         348 :                 switch (cToken)
    1510             :                 {
    1511             :                 case '<':
    1512         178 :                     eSymbolType = NUMBERFORMAT_OP_LT;
    1513         178 :                     break;
    1514             :                 case '>':
    1515         170 :                     eSymbolType = NUMBERFORMAT_OP_GT;
    1516         170 :                     break;
    1517             :                 case '=':
    1518           0 :                     eSymbolType = NUMBERFORMAT_OP_EQ;
    1519           0 :                     break;
    1520             :                 }
    1521         348 :                 break;
    1522             :             case ' ':
    1523           0 :                 nPos--;
    1524           0 :                 rString.remove(nPos, 1);
    1525           0 :                 nLen--;
    1526           0 :                 break;
    1527             :             case '$' :
    1528       55332 :                 if ( rString[nPos] == '-' )
    1529             :                 {
    1530             :                     // [$-xxx] locale
    1531          28 :                     sBuffSymbol.stripStart('[');
    1532          28 :                     eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
    1533          28 :                     eState = SsGetPrefix;
    1534             :                 }
    1535             :                 else
    1536             :                 {   // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
    1537       55304 :                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1538       55304 :                     eState = SsGetString;
    1539             :                 }
    1540       55332 :                 sBuffSymbol.append(cToken);
    1541       55332 :                 break;
    1542             :             case '~' :
    1543             :                 // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
    1544       77196 :                 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1545       77196 :                 sBuffSymbol.append(cToken);
    1546       77196 :                 eState = SsGetString;
    1547       77196 :                 break;
    1548             :             default:
    1549             :             {
    1550       65354 :                 const OUString aNatNum("NATNUM");
    1551      130708 :                 const OUString aDBNum("DBNUM");
    1552      130708 :                 const OUString aBufStr( rString.toString());
    1553             :                 sal_Int32 nNatNumNum;
    1554             :                 sal_Int32 nDBNum;
    1555      130918 :                 if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aNatNum, nNatNumNum) &&
    1556       65564 :                         0 <= nNatNumNum && nNatNumNum <= 19 )
    1557             :                 {
    1558         210 :                     sBuffSymbol.stripStart('[');
    1559         210 :                     sBuffSymbol.append( aBufStr.copy( --nPos, aNatNum.getLength()+1 ));
    1560         210 :                     nPos += aNatNum.getLength()+1;
    1561             :                     //! SymbolType is negative
    1562         210 :                     eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
    1563         210 :                     eState = SsGetPrefix;
    1564             :                 }
    1565      130290 :                 else if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aDBNum, nDBNum) &&
    1566       65144 :                         '1' <= nDBNum && nDBNum <= '9' )
    1567             :                 {
    1568           0 :                     sBuffSymbol.stripStart('[');
    1569           0 :                     sBuffSymbol.append( aBufStr.copy( --nPos, aDBNum.getLength()+1 ));
    1570           0 :                     nPos += aDBNum.getLength()+1;
    1571             :                     //! SymbolType is negative
    1572           0 :                     eSymbolType = sal::static_int_cast< short >( BRACKET_SYMBOLTYPE_DBNUM1 - (nDBNum - '1'));
    1573           0 :                     eState = SsGetPrefix;
    1574             :                 }
    1575             :                 else
    1576             :                 {
    1577       65144 :                     sal_Unicode cUpper = rChrCls().uppercase( aBufStr, nPos-1, 1)[0];
    1578      179216 :                     if (    cUpper == rKeywords[NF_KEY_H][0] ||     // H
    1579      114072 :                             cUpper == rKeywords[NF_KEY_MI][0] ||    // M
    1580       48928 :                             cUpper == rKeywords[NF_KEY_S][0] )      // S
    1581             :                     {
    1582       16216 :                         sBuffSymbol.append(cToken);
    1583       16216 :                         eState = SsGetTime;
    1584       16216 :                         cLetter = cToken;
    1585             :                     }
    1586             :                     else
    1587             :                     {
    1588       48928 :                         sBuffSymbol.stripStart('[');
    1589       48928 :                         sBuffSymbol.append(cToken);
    1590       48928 :                         eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
    1591       48928 :                         eState = SsGetPrefix;
    1592             :                     }
    1593       65354 :                 }
    1594             :             }
    1595             :             }
    1596      198230 :             break;
    1597             :         case SsGetString:
    1598     6828060 :             if (cToken == ';' && (nPos < 2 || !IsCombiningSymbol( rString, nPos-2)))
    1599             :             {
    1600      117152 :                 eState = SsStop;
    1601             :             }
    1602             :             else
    1603             :             {
    1604     6710908 :                 sBuffSymbol.append(cToken);
    1605             :             }
    1606     6828060 :             break;
    1607             :         case SsGetTime:
    1608       31870 :             if (cToken == ']')
    1609             :             {
    1610       16216 :                 sBuffSymbol.append(cToken);
    1611       16216 :                 eState = SsGetString;
    1612       16216 :                 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
    1613             :             }
    1614             :             else
    1615             :             {
    1616       15654 :                 sal_Unicode cUpper = rChrCls().uppercase(rString.toString(), nPos-1, 1)[0];
    1617       31308 :                 if (cUpper == rKeywords[NF_KEY_H][0] ||   // H
    1618       15654 :                     cUpper == rKeywords[NF_KEY_MI][0] ||  // M
    1619           0 :                     cUpper == rKeywords[NF_KEY_S][0] )    // S
    1620             :                 {
    1621       15654 :                     if (cLetter == cToken)
    1622             :                     {
    1623       15654 :                         sBuffSymbol.append(cToken);
    1624       15654 :                         cLetter = ' ';
    1625             :                     }
    1626             :                     else
    1627             :                     {
    1628           0 :                         sBuffSymbol.stripStart('[');
    1629           0 :                         sBuffSymbol.append(cToken);
    1630           0 :                         eState = SsGetPrefix;
    1631             :                     }
    1632             :                 }
    1633             :                 else
    1634             :                 {
    1635           0 :                     sBuffSymbol.stripStart('[');
    1636           0 :                     sBuffSymbol.append(cToken);
    1637           0 :                     eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
    1638           0 :                     eState = SsGetPrefix;
    1639             :                 }
    1640             :             }
    1641       31870 :             break;
    1642             :         case SsGetCon:
    1643         348 :             switch (cToken)
    1644             :             {
    1645             :             case '<':
    1646           0 :                 eState = SsStop;
    1647           0 :                 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
    1648           0 :                 break;
    1649             :             case '>':
    1650           8 :                 if (cLetter == '<')
    1651             :                 {
    1652           8 :                     sBuffSymbol.append(cToken);
    1653           8 :                     cLetter = ' ';
    1654           8 :                     eState = SsStop;
    1655           8 :                     eSymbolType = NUMBERFORMAT_OP_NE;
    1656             :                 }
    1657             :                 else
    1658             :                 {
    1659           0 :                     eState = SsStop;
    1660           0 :                     eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
    1661             :                 }
    1662           8 :                 break;
    1663             :             case '=':
    1664           0 :                 if (cLetter == '<')
    1665             :                 {
    1666           0 :                     sBuffSymbol.append(cToken);
    1667           0 :                     cLetter = ' ';
    1668           0 :                     eSymbolType = NUMBERFORMAT_OP_LE;
    1669             :                 }
    1670           0 :                 else if (cLetter == '>')
    1671             :                 {
    1672           0 :                     sBuffSymbol.append(cToken);
    1673           0 :                     cLetter = ' ';
    1674           0 :                     eSymbolType = NUMBERFORMAT_OP_GE;
    1675             :                 }
    1676             :                 else
    1677             :                 {
    1678           0 :                     eState = SsStop;
    1679           0 :                     eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
    1680             :                 }
    1681           0 :                 break;
    1682             :             case ' ':
    1683           0 :                 nPos--;
    1684           0 :                 rString.remove(nPos,1);
    1685           0 :                 nLen--;
    1686           0 :                 break;
    1687             :             default:
    1688         340 :                 eState = SsStop;
    1689         340 :                 nPos--;
    1690         340 :                 break;
    1691             :             }
    1692         348 :             break;
    1693             :         case SsGetPrefix:
    1694      147220 :             if (cToken == ']')
    1695             :             {
    1696       49166 :                 eState = SsStop;
    1697             :             }
    1698             :             else
    1699             :             {
    1700       98054 :                 sBuffSymbol.append(cToken);
    1701             :             }
    1702      147220 :             break;
    1703             :         default:
    1704           0 :             break;
    1705             :         } // of switch
    1706             :     } // of while
    1707      738187 :     sSymbol = sBuffSymbol.makeStringAndClear();
    1708      738187 :     return eSymbolType;
    1709             : }
    1710             : 
    1711           0 : NfHackConversion SvNumberformat::Load( SvStream& rStream,
    1712             :                                        ImpSvNumMultipleReadHeader& rHdr,
    1713             :                                        SvNumberFormatter* pHackConverter,
    1714             :                                        ImpSvNumberInputScan& rISc )
    1715             : {
    1716           0 :     rHdr.StartEntry();
    1717             :     sal_uInt16 nOp1, nOp2;
    1718           0 :     sFormatstring = SvNumberformat::LoadString( rStream );
    1719             :     bool bStreamStandard, bStreamUsed;
    1720           0 :     rStream.ReadInt16( eType ).ReadDouble( fLimit1 ).ReadDouble( fLimit2 )
    1721           0 :            .ReadUInt16( nOp1 ).ReadUInt16( nOp2 ).ReadCharAsBool( bStreamStandard ).ReadCharAsBool( bStreamUsed );
    1722           0 :     bStandard = bStreamStandard;
    1723           0 :     bIsUsed = bStreamUsed;
    1724           0 :     NfHackConversion eHackConversion = NF_CONVERT_NONE;
    1725           0 :     bool bOldConvert = false;
    1726           0 :     LanguageType eOldTmpLang = 0;
    1727           0 :     LanguageType eOldNewLang = 0;
    1728           0 :     if ( pHackConverter )
    1729             :     {
    1730             :         // Are only needed here
    1731           0 :         bOldConvert = rScan.GetConvertMode();
    1732           0 :         eOldTmpLang = rScan.GetTmpLnge();
    1733           0 :         eOldNewLang = rScan.GetNewLnge();
    1734             :     }
    1735           0 :     OUString aLoadedColorName;
    1736           0 :     for (sal_uInt16 i = 0; i < 4; i++)
    1737             :     {
    1738           0 :         NumFor[i].Load( rStream, rScan, aLoadedColorName );
    1739           0 :         if ( pHackConverter && eHackConversion == NF_CONVERT_NONE )
    1740             :         {
    1741             :             // FIXME: HACK!
    1742             :             // Unfortunately we didn't save what SYSTEM on Save really was :-/
    1743             :             // After all we save FARBE or COLOR for an Entry ...
    1744             :             // When translating from System-German FARBE to System-xxx COLOR and vice versa,
    1745             :             // we assume that onSave only has GERMAN and ENGLISH KeyWords in ImpSvNumberformatScan
    1746           0 :             if ( !aLoadedColorName.isEmpty() &&
    1747           0 :                  !NumFor[i].GetColor() &&
    1748           0 :                  aLoadedColorName != rScan.GetColorString() )
    1749             :             {
    1750           0 :                 if ( rScan.GetColorString() == "FARBE" )
    1751             :                 {   // English -> German
    1752           0 :                     eHackConversion = NF_CONVERT_ENGLISH_GERMAN;
    1753           0 :                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US );
    1754           0 :                     rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN );
    1755             :                 }
    1756             :                 else
    1757             :                 {   // German -> English
    1758           0 :                     eHackConversion = NF_CONVERT_GERMAN_ENGLISH;
    1759           0 :                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN );
    1760           0 :                     rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US );
    1761             :                 }
    1762           0 :                 OUString aColorName = NumFor[i].GetColorName();
    1763           0 :                 const Color* pColor = rScan.GetColor( aColorName );
    1764           0 :                 if ( !pColor && aLoadedColorName == aColorName )
    1765             :                 {
    1766           0 :                     eHackConversion = NF_CONVERT_NONE;
    1767             :                 }
    1768           0 :                 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM );
    1769           0 :                 rScan.SetConvertMode( eOldTmpLang, eOldNewLang );
    1770           0 :                 rScan.SetConvertMode( bOldConvert );
    1771             :             }
    1772             :         }
    1773             :     }
    1774           0 :     eOp1 = (SvNumberformatLimitOps) nOp1;
    1775           0 :     eOp2 = (SvNumberformatLimitOps) nOp2;
    1776           0 :     OUString aComment; // Will be set to the correct value after the NewCurrency troubles
    1777           0 :     if ( rHdr.BytesLeft() )
    1778             :     {
    1779             :         // As of SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
    1780           0 :         aComment = SvNumberformat::LoadString( rStream );
    1781           0 :         rStream.ReadUInt16( nNewStandardDefined );
    1782             :     }
    1783             : 
    1784           0 :     sal_Int32 nNewCurrencyEnd = -1;
    1785           0 :     bool bNewCurrencyComment = ( aComment.getLength() > 1 && aComment[0] == cNewCurrencyMagic &&
    1786           0 :                                  (nNewCurrencyEnd = aComment.indexOf( cNewCurrencyMagic, 1 )) >= 0 );
    1787           0 :     bool bNewCurrencyLoaded = false;
    1788           0 :     bool bNewCurrency = false;
    1789             : 
    1790           0 :     bool bGoOn = true;
    1791           0 :     while ( rHdr.BytesLeft() && bGoOn )
    1792             :     {
    1793             :         // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
    1794             :         sal_uInt16 nId;
    1795             :         unsigned char bStreamCurr;
    1796           0 :         rStream.ReadUInt16( nId );
    1797           0 :         switch ( nId )
    1798             :         {
    1799             :         case nNewCurrencyVersionId :
    1800           0 :             bNewCurrencyLoaded = true;
    1801           0 :             rStream.ReadUChar( bStreamCurr );
    1802           0 :             bNewCurrency = bStreamCurr;
    1803           0 :             if ( bNewCurrency )
    1804             :             {
    1805           0 :                 for ( sal_uInt16 j=0; j<4; j++ )
    1806             :                 {
    1807           0 :                     NumFor[j].LoadNewCurrencyMap( rStream );
    1808             :                 }
    1809             :             }
    1810           0 :             break;
    1811             :         case nNewStandardFlagVersionId :
    1812           0 :             rStream.ReadCharAsBool( bStreamStandard ); // the real standard flag
    1813           0 :             bStandard = bStreamStandard;
    1814           0 :             break;
    1815             :         default:
    1816             :             SAL_WARN( "svl.numbers", "SvNumberformat::Load: unknown header bytes left nId" );
    1817           0 :             bGoOn = false; // stop reading unknown stream left over of newer versions
    1818             :             // Would be nice to have multiple read/write headers instead
    1819             :             // but old versions wouldn't know it, TLOT.
    1820             :         }
    1821             :     }
    1822           0 :     rHdr.EndEntry();
    1823             : 
    1824           0 :     if ( bNewCurrencyLoaded )
    1825             :     {
    1826           0 :         if ( bNewCurrency && bNewCurrencyComment )
    1827             :         {   // Recover original format string and comment
    1828           0 :             sFormatstring = aComment.copy( 1, nNewCurrencyEnd-1 );
    1829           0 :             if(nNewCurrencyEnd + 1 < aComment.getLength())
    1830             :             {
    1831           0 :                 aComment = aComment.copy(nNewCurrencyEnd + 1 );
    1832             :             }
    1833             :             else
    1834             :             {
    1835           0 :                 aComment = "";
    1836             :             }
    1837             :         }
    1838             :     }
    1839           0 :     else if ( bNewCurrencyComment )
    1840             :     {
    1841             :         // New, but saved with version before SV_NUMBERFORMATTER_VERSION_NEW_CURR
    1842             :         // Recover original format string and comment
    1843           0 :         sFormatstring = aComment.copy( 1, nNewCurrencyEnd - 1 );
    1844           0 :         if(nNewCurrencyEnd + 1 < aComment.getLength())
    1845             :         {
    1846           0 :             aComment = aComment.copy(nNewCurrencyEnd + 1 );
    1847             :         }
    1848             :         else
    1849             :         {
    1850           0 :             aComment = "";
    1851             :         }
    1852             :         // Remember states
    1853           0 :         short nDefined = ( eType & NUMBERFORMAT_DEFINED );
    1854           0 :         sal_uInt16 nNewStandard = nNewStandardDefined;
    1855             : 
    1856             :         // Parse new ones etc.
    1857           0 :         OUString aStr( sFormatstring );
    1858           0 :         sal_Int32 nCheckPos = 0;
    1859             :         boost::scoped_ptr<SvNumberformat> pFormat(new SvNumberformat( aStr, &rScan, &rISc,
    1860           0 :                                                       nCheckPos, maLocale.meLanguage, bStandard ));
    1861             :         DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
    1862           0 :         ImpCopyNumberformat( *pFormat );
    1863           0 :         pFormat.reset();
    1864             : 
    1865             :         // Recover states
    1866           0 :         eType |= nDefined;
    1867           0 :         if ( nNewStandard )
    1868             :         {
    1869           0 :             SetNewStandardDefined( nNewStandard );
    1870           0 :         }
    1871             :     }
    1872           0 :     SetComment( aComment );
    1873             : 
    1874           0 :     if ( eHackConversion != NF_CONVERT_NONE )
    1875             :     {
    1876             :         //! and we continue with the HACK!
    1877           0 :         switch ( eHackConversion )
    1878             :         {
    1879             :         case NF_CONVERT_ENGLISH_GERMAN :
    1880             :             ConvertLanguage( *pHackConverter,
    1881           0 :                              LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, true );
    1882           0 :             break;
    1883             :         case NF_CONVERT_GERMAN_ENGLISH :
    1884             :             ConvertLanguage( *pHackConverter,
    1885           0 :                              LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, true );
    1886           0 :             break;
    1887             :         default:
    1888             :             SAL_WARN( "svl.numbers", "SvNumberformat::Load: eHackConversion unknown" );
    1889             :         }
    1890             :     }
    1891           0 :     return eHackConversion;
    1892             : }
    1893             : 
    1894           0 : void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
    1895             :                                       LanguageType eConvertFrom,
    1896             :                                       LanguageType eConvertTo, bool bSystem )
    1897             : {
    1898             :     sal_Int32 nCheckPos;
    1899             :     sal_uInt32 nKey;
    1900           0 :     short nType = eType;
    1901           0 :     OUString aFormatString( sFormatstring );
    1902           0 :     if ( bSystem )
    1903             :     {
    1904             :         rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
    1905           0 :                                              nKey, eConvertFrom, eConvertTo );
    1906             :     }
    1907             :     else
    1908             :     {
    1909             :         rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
    1910           0 :                                        nKey, eConvertFrom, eConvertTo );
    1911             :     }
    1912           0 :     const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
    1913             :     DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
    1914           0 :     if ( pFormat )
    1915             :     {
    1916           0 :         ImpCopyNumberformat( *pFormat );
    1917             :         // Reset values taken over from Formatter/Scanner
    1918           0 :         if ( bSystem )
    1919             :         {
    1920           0 :             maLocale.meLanguage = LANGUAGE_SYSTEM;
    1921             :         }
    1922             :         // pColor still points to table in temporary Formatter/Scanner
    1923           0 :         for ( sal_uInt16 i = 0; i < 4; i++ )
    1924             :         {
    1925           0 :             OUString aColorName = NumFor[i].GetColorName();
    1926           0 :             Color* pColor = rScan.GetColor( aColorName );
    1927           0 :             NumFor[i].SetColor( pColor, aColorName );
    1928           0 :         }
    1929           0 :     }
    1930           0 : }
    1931             : 
    1932             : // static
    1933           0 : OUString SvNumberformat::LoadString( SvStream& rStream )
    1934             : {
    1935           0 :     rtl_TextEncoding eStream = rStream.GetStreamCharSet();
    1936           0 :     OString aStr = read_uInt16_lenPrefixed_uInt8s_ToOString(rStream);
    1937           0 :     sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream );
    1938           0 :     if (aStr.indexOf(cStream) < 0)
    1939             :     {
    1940             :         // simple conversion to unicode
    1941           0 :         return OStringToOUString(aStr, eStream);
    1942             :     }
    1943           0 :     sal_Unicode cSource = OUString(&cStream, 1, eStream).toChar();
    1944           0 :     sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol();
    1945           0 :     OUStringBuffer aBuf(OStringToOUString(aStr, eStream));
    1946           0 :     aBuf.replace(cSource, cTarget);
    1947             : 
    1948           0 :     return aBuf.makeStringAndClear();
    1949             : }
    1950             : 
    1951           0 : void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const
    1952             : {
    1953           0 :     OUString aFormatstring( sFormatstring );
    1954           0 :     OUStringBuffer aComment( sComment.getLength() + sFormatstring.getLength() + 2 );
    1955             : 
    1956           0 :     bool bNewCurrency = HasNewCurrency();
    1957           0 :     if ( bNewCurrency )
    1958             :     {
    1959             :         // Save SV_NUMBERFORMATTER_VERSION_NEW_CURR in comment
    1960           0 :         aComment.insert( 0, cNewCurrencyMagic );
    1961           0 :         aComment.insert( 0, cNewCurrencyMagic );
    1962           0 :         aComment.insert( 1, aFormatstring );
    1963           0 :         Build50Formatstring( aFormatstring ); // Generate old format string
    1964             :     }
    1965             : 
    1966             :     // old SO5 versions do behave strange (no output) if standard flag is set
    1967             :     // on formats not prepared for it (not having the following exact types)
    1968           0 :     bool bOldStandard = bStandard;
    1969           0 :     if ( bOldStandard )
    1970             :     {
    1971           0 :         switch ( eType )
    1972             :         {
    1973             :         case NUMBERFORMAT_NUMBER :
    1974             :         case NUMBERFORMAT_DATE :
    1975             :         case NUMBERFORMAT_TIME :
    1976             :         case NUMBERFORMAT_DATETIME :
    1977             :         case NUMBERFORMAT_PERCENT :
    1978             :         case NUMBERFORMAT_SCIENTIFIC :
    1979             :             // ok to save
    1980           0 :             break;
    1981             :         default:
    1982           0 :             bOldStandard = false;
    1983             :         }
    1984             :     }
    1985             : 
    1986           0 :     rHdr.StartEntry();
    1987           0 :     rStream.WriteUniOrByteString( aFormatstring, rStream.GetStreamCharSet() );
    1988           0 :     rStream.WriteInt16( eType ).WriteDouble( fLimit1 ).WriteDouble( fLimit2 ).WriteUInt16( eOp1 ).WriteUInt16( eOp2 )
    1989           0 :            .WriteUChar( bOldStandard ).WriteUChar( bIsUsed );
    1990           0 :     for (sal_uInt16 i = 0; i < 4; i++)
    1991             :     {
    1992           0 :         NumFor[i].Save(rStream);
    1993             :     }
    1994             :     // As of SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
    1995           0 :     rStream.WriteUniOrByteString( aComment.makeStringAndClear(), rStream.GetStreamCharSet() );
    1996           0 :     rStream.WriteUInt16( nNewStandardDefined );
    1997             :     // As of SV_NUMBERFORMATTER_VERSION_NEW_CURR
    1998           0 :     rStream.WriteUInt16( nNewCurrencyVersionId );
    1999           0 :     rStream.WriteUChar( bNewCurrency );
    2000           0 :     if ( bNewCurrency )
    2001             :     {
    2002           0 :         for ( sal_uInt16 j=0; j<4; j++ )
    2003             :         {
    2004           0 :             NumFor[j].SaveNewCurrencyMap( rStream );
    2005             :         }
    2006             :     }
    2007             : 
    2008             :     // the real standard flag to load with versions >638 if different
    2009           0 :     if ( bStandard != bOldStandard )
    2010             :     {
    2011           0 :         rStream.WriteUInt16( nNewStandardFlagVersionId );
    2012           0 :         rStream.WriteUChar( bStandard );
    2013             :     }
    2014             : 
    2015           0 :     rHdr.EndEntry();
    2016           0 : }
    2017             : 
    2018           0 : bool SvNumberformat::HasNewCurrency() const
    2019             : {
    2020           0 :     for ( sal_uInt16 j=0; j<4; j++ )
    2021             :     {
    2022           0 :         if ( NumFor[j].HasNewCurrency() )
    2023             :         {
    2024           0 :             return true;
    2025             :         }
    2026             :     }
    2027           0 :     return false;
    2028             : }
    2029             : 
    2030        4164 : bool SvNumberformat::GetNewCurrencySymbol( OUString& rSymbol,
    2031             :                                            OUString& rExtension ) const
    2032             : {
    2033       20108 :     for ( sal_uInt16 j=0; j<4; j++ )
    2034             :     {
    2035       16122 :         if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
    2036             :         {
    2037         178 :             return true;
    2038             :         }
    2039             :     }
    2040        3986 :     rSymbol = "";
    2041        3986 :     rExtension = "";
    2042        3986 :     return false;
    2043             : }
    2044             : 
    2045             : // static
    2046       39120 : OUString SvNumberformat::StripNewCurrencyDelimiters( const OUString& rStr,
    2047             :                                                      bool bQuoteSymbol )
    2048             : {
    2049       39120 :     OUString aTmp;
    2050       78240 :     OUString aSource(rStr);
    2051             :     sal_Int32 nStartPos, nPos, nLen;
    2052       39120 :     nLen = aSource.getLength();
    2053       39120 :     nStartPos = 0;
    2054      156480 :     while ( (nPos = aSource.indexOf( "[$", nStartPos )) >= 0 )
    2055             :     {
    2056             :         sal_Int32 nEnd;
    2057       78240 :         if ( (nEnd = GetQuoteEnd( aSource, nPos )) >= 0 )
    2058             :         {
    2059           0 :             aTmp += aSource.copy( nStartPos, ++nEnd - nStartPos );
    2060           0 :             nStartPos = nEnd;
    2061             :         }
    2062             :         else
    2063             :         {
    2064       78240 :             aTmp += aSource.copy( nStartPos, nPos - nStartPos );
    2065       78240 :             nStartPos = nPos + 2;
    2066             :             sal_Int32 nDash;
    2067       78240 :             nEnd = nStartPos - 1;
    2068       78240 :             do
    2069             :             {
    2070       78240 :                 nDash = aSource.indexOf( '-', ++nEnd );
    2071             :             }
    2072             :             while ( (nEnd = GetQuoteEnd( aSource, nDash )) >= 0 );
    2073             :             sal_Int32 nClose;
    2074       78240 :             nEnd = nStartPos - 1;
    2075       78240 :             do
    2076             :             {
    2077       78240 :                 nClose = aSource.indexOf( ']', ++nEnd );
    2078             :             }
    2079             :             while ( (nEnd = GetQuoteEnd( aSource, nClose )) >= 0 );
    2080             : 
    2081       78240 :             if(nClose < 0)
    2082             :             {
    2083             :                 /* there should always be a closing ]
    2084             :                  * but the old String class would have hidden
    2085             :                  * that. so be conservative too
    2086             :                  */
    2087           0 :                 nClose = nLen;
    2088             :             }
    2089             : 
    2090       78240 :             nPos = nClose;
    2091       78240 :             if(nDash >= 0 && nDash < nClose)
    2092             :             {
    2093       78240 :                 nPos = nDash;
    2094             :             }
    2095       78240 :             if ( !bQuoteSymbol || aSource[ nStartPos ] == '"' )
    2096             :             {
    2097       78240 :                 aTmp += aSource.copy( nStartPos, nPos - nStartPos );
    2098             :             }
    2099             :             else
    2100             :             {
    2101           0 :                 aTmp += "\"";
    2102           0 :                 aTmp += aSource.copy( nStartPos, nPos - nStartPos );
    2103           0 :                 aTmp += "\"";
    2104             :             }
    2105       78240 :             nStartPos = nClose + 1;
    2106             :         }
    2107             :     }
    2108       39120 :     if ( nLen > nStartPos )
    2109             :     {
    2110       38840 :         aTmp += aSource.copy( nStartPos, nLen - nStartPos );
    2111             :     }
    2112       78240 :     return aTmp;
    2113             : }
    2114             : 
    2115           0 : void SvNumberformat::Build50Formatstring( OUString& rStr ) const
    2116             : {
    2117           0 :     rStr = StripNewCurrencyDelimiters( sFormatstring, true );
    2118           0 : }
    2119             : 
    2120        3331 : void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUStringBuffer& OutString)
    2121             : {
    2122        3331 :     OUString sTemp;
    2123        3331 :     ImpGetOutputStandard(fNumber, sTemp);
    2124        3331 :     OutString = sTemp;
    2125        3331 : }
    2126             : 
    2127        3331 : void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUString& OutString)
    2128             : {
    2129        3331 :     sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
    2130             : 
    2131        3331 :     if ( fabs(fNumber) > 1.0E15 ) // #58531# was E16
    2132             :     {
    2133           0 :         nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
    2134           0 :         OutString = ::rtl::math::doubleToUString( fNumber,
    2135             :                                                   rtl_math_StringFormat_E, nStandardPrec /*2*/,
    2136           0 :                                                   GetFormatter().GetNumDecimalSep()[0]);
    2137             :     }
    2138             :     else
    2139             :     {
    2140        3331 :         ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec);
    2141             :     }
    2142        3331 : }
    2143             : 
    2144       88061 : void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, OUString& rOutString, sal_uInt16 nPrecision) const
    2145             : {
    2146             :     // Make sure the precision doesn't go over the maximum allowable precision.
    2147       88061 :     nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
    2148             : 
    2149             : #if 0
    2150             : {
    2151             :     // debugger test case for ANSI standard correctness
    2152             :     OUString aTest;
    2153             :     // expect 0.00123   OK
    2154             :     aTest = ::rtl::math::doubleToUString( 0.001234567,
    2155             :                                           rtl_math_StringFormat_G, 3, '.', true );
    2156             :     // expect 123       OK
    2157             :     aTest = ::rtl::math::doubleToUString( 123.4567,
    2158             :                                           rtl_math_StringFormat_G, 3, '.', true );
    2159             :     // expect 123.5     OK
    2160             :     aTest = ::rtl::math::doubleToUString( 123.4567,
    2161             :                                           rtl_math_StringFormat_G, 4, '.', true );
    2162             :     // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
    2163             :     // 1000 with an exponent equal to significant digits)
    2164             :     // Currently (24-Jan-2003) we do fail in this case and output 1000
    2165             :     // instead, negligible.
    2166             :     aTest = ::rtl::math::doubleToUString( 999.6,
    2167             :                                           rtl_math_StringFormat_G, 3, '.', true );
    2168             :     // expect what? result is 1.2e+004
    2169             :     aTest = ::rtl::math::doubleToUString( 12345.6789,
    2170             :                                           rtl_math_StringFormat_G, -3, '.', true );
    2171             : }
    2172             : #endif
    2173             : 
    2174             :     // We decided to strip trailing zeros unconditionally, since binary
    2175             :     // double-precision rounding error makes it impossible to determine e.g.
    2176             :     // whether 844.10000000000002273737 is what the user has typed, or the
    2177             :     // user has typed 844.1 but IEEE 754 represents it that way internally.
    2178             : 
    2179      176122 :     rOutString = ::rtl::math::doubleToUString( rNumber,
    2180             :                                                rtl_math_StringFormat_F, nPrecision /*2*/,
    2181      176122 :                                                GetFormatter().GetNumDecimalSep()[0], true );
    2182       88367 :     if (rOutString[0] == '-' &&
    2183         306 :         comphelper::string::getTokenCount(rOutString, '0') == rOutString.getLength())
    2184             :     {
    2185           0 :         rOutString = comphelper::string::stripStart(rOutString, '-'); // not -0
    2186             :     }
    2187       88061 :     rOutString = impTransliterate(rOutString, NumFor[0].GetNatNum());
    2188       88061 : }
    2189             : 
    2190        1076 : void SvNumberformat::ImpGetOutputInputLine(double fNumber, OUString& OutString)
    2191             : {
    2192        1076 :     bool bModified = false;
    2193        1076 :     if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
    2194             :     {
    2195           0 :         if (fNumber == 0.0)
    2196             :         {
    2197           0 :             OutString = "0%";
    2198           0 :             return;
    2199             :         }
    2200           0 :         fNumber *= 100;
    2201           0 :         bModified = true;
    2202             :     }
    2203             : 
    2204        1076 :     if (fNumber == 0.0)
    2205             :     {
    2206         296 :         OutString = "0";
    2207         296 :         return;
    2208             :     }
    2209             : 
    2210        1560 :     OutString = ::rtl::math::doubleToUString( fNumber,
    2211             :                                               rtl_math_StringFormat_Automatic,
    2212             :                                               rtl_math_DecimalPlaces_Max,
    2213        1560 :                                               GetFormatter().GetNumDecimalSep()[0], true );
    2214             : 
    2215         780 :     if ( eType & NUMBERFORMAT_PERCENT && bModified)
    2216             :     {
    2217           0 :         OutString += "%";
    2218             :     }
    2219         780 :     return;
    2220             : }
    2221             : 
    2222        8942 : short SvNumberformat::ImpCheckCondition(double& fNumber,
    2223             :                                         double& fLimit,
    2224             :                                         SvNumberformatLimitOps eOp)
    2225             : {
    2226        8942 :     switch(eOp)
    2227             :     {
    2228             :     case NUMBERFORMAT_OP_NO:
    2229        8580 :         return -1;
    2230             :     case NUMBERFORMAT_OP_EQ:
    2231           0 :         return (short) (fNumber == fLimit);
    2232             :     case NUMBERFORMAT_OP_NE:
    2233          44 :         return (short) (fNumber != fLimit);
    2234             :     case NUMBERFORMAT_OP_LT:
    2235           0 :         return (short) (fNumber <  fLimit);
    2236             :     case NUMBERFORMAT_OP_LE:
    2237           0 :         return (short) (fNumber <= fLimit);
    2238             :     case NUMBERFORMAT_OP_GT:
    2239          26 :         return (short) (fNumber >  fLimit);
    2240             :     case NUMBERFORMAT_OP_GE:
    2241         292 :         return (short) (fNumber >= fLimit);
    2242             :     default:
    2243           0 :         return -1;
    2244             :     }
    2245             : }
    2246             : 
    2247           0 : static bool lcl_appendStarFillChar( OUStringBuffer& rBuf, const OUString& rStr )
    2248             : {
    2249             :     // Right during user input the star symbol is the very
    2250             :     // last character before the user enters another one.
    2251           0 :     if (rStr.getLength() > 1)
    2252             :     {
    2253           0 :         rBuf.append((sal_Unicode) 0x1B);
    2254           0 :         rBuf.append(rStr[1]);
    2255           0 :         return true;
    2256             :     }
    2257           0 :     return false;
    2258             : }
    2259             : 
    2260           0 : static bool lcl_insertStarFillChar( OUStringBuffer& rBuf, sal_Int32 nPos, const OUString& rStr )
    2261             : {
    2262           0 :     if (rStr.getLength() > 1)
    2263             :     {
    2264           0 :         rBuf.insert( nPos, rStr[1]);
    2265           0 :         rBuf.insert( nPos, (sal_Unicode) 0x1B);
    2266           0 :         return true;
    2267             :     }
    2268           0 :     return false;
    2269             : }
    2270             : 
    2271        1168 : bool SvNumberformat::GetOutputString(const OUString& sString,
    2272             :                                      OUString& OutString,
    2273             :                                      Color** ppColor)
    2274             : {
    2275        1168 :     OUStringBuffer sOutBuff;
    2276             :     sal_uInt16 nIx;
    2277        1168 :     if (eType & NUMBERFORMAT_TEXT)
    2278             :     {
    2279        1168 :         nIx = 0;
    2280             :     }
    2281           0 :     else if (NumFor[3].GetCount() > 0)
    2282             :     {
    2283           0 :         nIx = 3;
    2284             :     }
    2285             :     else
    2286             :     {
    2287           0 :         *ppColor = NULL; // no change of color
    2288           0 :         return false;
    2289             :     }
    2290        1168 :     *ppColor = NumFor[nIx].GetColor();
    2291        1168 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    2292        1168 :     bool bRes = false;
    2293        1168 :     if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
    2294             :     {
    2295        1168 :         const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    2296        2344 :         for (sal_uInt16 i = 0; i < nAnz; i++)
    2297             :         {
    2298        1176 :             switch (rInfo.nTypeArray[i])
    2299             :             {
    2300             :             case NF_SYMBOLTYPE_STAR:
    2301           0 :                 if( bStarFlag )
    2302             :                 {
    2303           0 :                     bRes = lcl_appendStarFillChar( sOutBuff, rInfo.sStrArray[i]);
    2304             :                 }
    2305           0 :                 break;
    2306             :             case NF_SYMBOLTYPE_BLANK:
    2307             :                 InsertBlanks( sOutBuff, sOutBuff.getLength(),
    2308           0 :                               rInfo.sStrArray[i][1] );
    2309           0 :                 break;
    2310             :             case NF_KEY_GENERAL :   // #77026# "General" is the same as "@"
    2311             :             case NF_SYMBOLTYPE_DEL :
    2312        1168 :                 sOutBuff.append(sString);
    2313        1168 :                 break;
    2314             :             default:
    2315           8 :                 sOutBuff.append(rInfo.sStrArray[i]);
    2316             :             }
    2317             :         }
    2318             :     }
    2319        1168 :     OutString = sOutBuff.makeStringAndClear();
    2320        1168 :     return bRes;
    2321             : }
    2322             : 
    2323          26 : sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y)
    2324             : {
    2325          26 :     if (y == 0)
    2326             :     {
    2327           0 :         return x;
    2328             :     }
    2329             :     else
    2330             :     {
    2331          26 :         sal_uLong z = x%y;
    2332         146 :         while (z)
    2333             :         {
    2334          94 :             x = y;
    2335          94 :             y = z;
    2336          94 :             z = x%y;
    2337             :         }
    2338          26 :         return y;
    2339             :     }
    2340             : }
    2341             : 
    2342           0 : sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y)
    2343             : {
    2344           0 :     if (y == 0)
    2345             :     {
    2346           0 :         return x;
    2347             :     }
    2348             :     else
    2349             :     {
    2350           0 :         sal_uLong z = x%y;
    2351           0 :         while ((double)z/(double)y > D_EPS)
    2352             :         {
    2353           0 :             x = y;
    2354           0 :             y = z;
    2355           0 :             z = x%y;
    2356             :         }
    2357           0 :         return y;
    2358             :     }
    2359             : }
    2360             : 
    2361             : namespace {
    2362             : 
    2363         110 : void lcl_GetOutputStringScientific(double fNumber, sal_uInt16 nCharCount,
    2364             :                                    const SvNumberFormatter& rFormatter, OUString& rOutString)
    2365             : {
    2366         110 :     bool bSign = ::rtl::math::isSignBitSet(fNumber);
    2367             : 
    2368             :     // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7).
    2369         110 :     sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0;
    2370         110 :     if (nPrec && bSign)
    2371             :     {
    2372             :         // Make room for the negative sign.
    2373           2 :         --nPrec;
    2374             :     }
    2375         110 :     nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
    2376             : 
    2377         220 :     rOutString = ::rtl::math::doubleToUString(fNumber, rtl_math_StringFormat_E,
    2378         220 :                                               nPrec, rFormatter.GetNumDecimalSep()[0]);
    2379         110 : }
    2380             : 
    2381          20 : sal_Int32 lcl_GetForcedDenominator(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nAnz)
    2382             : {
    2383             :     sal_uInt16 i;
    2384          20 :     OUString aDiv;
    2385         120 :     for( i = 0; i < nAnz; i++ )
    2386             :     {
    2387         100 :         if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC_FDIV )
    2388             :         {
    2389           0 :             aDiv += rInfo.sStrArray[i];
    2390             :         }
    2391             :     }
    2392          20 :     return aDiv.toInt32();
    2393             : }
    2394             : 
    2395             : // TODO: More optimizations?
    2396           0 : void lcl_ForcedDenominator(sal_uLong &nFrac, sal_uLong &nDiv, sal_uLong nForcedDiv)
    2397             : {
    2398           0 :     double fFrac = (double)nFrac / (double)nDiv;
    2399           0 :     double fMultiplier = (double)nForcedDiv / (double)nDiv;
    2400           0 :     nFrac = (sal_uLong)( (double)nFrac * fMultiplier );
    2401             : 
    2402           0 :     double fFracNew = (double)nFrac / (double)nForcedDiv;
    2403           0 :     double fFracNew1 = (double)(nFrac + 1) / (double)nForcedDiv;
    2404           0 :     double fDiff = fFrac - fFracNew;
    2405           0 :     if( fDiff > ( fFracNew1 - fFrac ) )
    2406             :     {
    2407           0 :         nFrac++;
    2408             :     }
    2409           0 :     nDiv = nForcedDiv;
    2410           0 : }
    2411             : 
    2412             : }
    2413             : 
    2414           4 : sal_Int32 SvNumberformat::GetForcedDenominatorForType( sal_uInt16 nNumFor ) const
    2415             : {
    2416           4 :     const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
    2417           4 :     sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
    2418           4 :     return lcl_GetForcedDenominator( rInfo, nAnz );
    2419             : }
    2420             : 
    2421         854 : bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString& rOutString) const
    2422             : {
    2423             :     using namespace std;
    2424             : 
    2425         854 :     if (eType != NUMBERFORMAT_NUMBER)
    2426             :     {
    2427           0 :         return false;
    2428             :     }
    2429         854 :     double fTestNum = fNumber;
    2430         854 :     bool bSign = ::rtl::math::isSignBitSet(fTestNum);
    2431         854 :     if (bSign)
    2432             :     {
    2433         304 :         fTestNum = -fTestNum;
    2434             :     }
    2435         854 :     if (fTestNum < EXP_LOWER_BOUND)
    2436             :     {
    2437           0 :         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
    2438           0 :         return true;
    2439             :     }
    2440             : 
    2441         854 :     double fExp = log10(fTestNum);
    2442             :     // Values < 1.0 always have one digit before the decimal point.
    2443         854 :     sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
    2444             : 
    2445         854 :     if (nDigitPre > 15)
    2446             :     {
    2447           2 :         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
    2448           2 :         return true;
    2449             :     }
    2450             : 
    2451         852 :     sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
    2452         852 :     if (nPrec && bSign)
    2453             :     {
    2454             :         // Subtract the negative sign.
    2455         302 :         --nPrec;
    2456             :     }
    2457         852 :     if (nPrec)
    2458             :     {
    2459             :         // Subtract the decimal point.
    2460         744 :         --nPrec;
    2461             :     }
    2462         852 :     ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
    2463         852 :     if (rOutString.getLength() > nCharCount)
    2464             :     {
    2465             :         // String still wider than desired.  Switch to scientific notation.
    2466         108 :         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
    2467             :     }
    2468         852 :     return true;
    2469             : }
    2470             : 
    2471       98729 : bool SvNumberformat::GetOutputString(double fNumber,
    2472             :                                      OUString& OutString,
    2473             :                                      Color** ppColor)
    2474             : {
    2475       98729 :     bool bRes = false;
    2476       98729 :     OUStringBuffer sBuff;
    2477       98729 :     OutString = "";
    2478       98729 :     *ppColor = NULL; // No color change
    2479       98729 :     if (eType & NUMBERFORMAT_LOGICAL)
    2480             :     {
    2481        1278 :         if (fNumber)
    2482             :         {
    2483         576 :             OutString = rScan.GetTrueString();
    2484             :         }
    2485             :         else
    2486             :         {
    2487         702 :             OutString = rScan.GetFalseString();
    2488             :         }
    2489        1278 :         return false;
    2490             :     }
    2491       97451 :     if (eType & NUMBERFORMAT_TEXT)
    2492             :     {
    2493           0 :         ImpGetOutputStandard(fNumber, sBuff);
    2494           0 :         OutString = sBuff.makeStringAndClear();
    2495           0 :         return false;
    2496             :     }
    2497       97451 :     bool bHadStandard = false;
    2498       97451 :     if (bStandard) // Individual standard formats
    2499             :     {
    2500       88905 :         if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // All number format InputLine
    2501             :         {
    2502        1076 :             ImpGetOutputInputLine(fNumber, OutString);
    2503        1076 :             return false;
    2504             :         }
    2505       87829 :         switch (eType)
    2506             :         {
    2507             :         case NUMBERFORMAT_NUMBER: // Standard number format
    2508       87173 :             if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
    2509             :             {
    2510       83878 :                 bool bSign = ::rtl::math::isSignBitSet(fNumber);
    2511       83878 :                 if (bSign)
    2512             :                 {
    2513        2999 :                     if (!(fNumber < 0.0))
    2514             :                     {
    2515           0 :                         bSign = false;
    2516             :                     }
    2517        2999 :                     fNumber = -fNumber;
    2518             :                 }
    2519             :                 {
    2520       83878 :                     OUString sTemp;
    2521       83878 :                     ImpGetOutputStdToPrecision(fNumber, sTemp, 10); // Use 10 decimals for general 'unlimited' format.
    2522       83878 :                     sBuff.append(sTemp);
    2523             :                 }
    2524       83878 :                 if (fNumber < EXP_LOWER_BOUND)
    2525             :                 {
    2526        2899 :                     sal_Int32 nLen = sBuff.getLength();
    2527        2899 :                     if (!nLen)
    2528             :                     {
    2529           0 :                         return false;
    2530             :                     }
    2531             :                     // #i112250# With the 10-decimal limit, small numbers are formatted as "0".
    2532             :                     // Switch to scientific in that case, too:
    2533        2899 :                     if (nLen > 11 || ((nLen == 1 && sBuff[0] == '0') && fNumber != 0.0))
    2534             :                     {
    2535           0 :                         sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
    2536           0 :                         nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
    2537           0 :                         sBuff = ::rtl::math::doubleToUString( fNumber,
    2538             :                                                               rtl_math_StringFormat_E, nStandardPrec /*2*/,
    2539           0 :                                                               GetFormatter().GetNumDecimalSep()[0], true);
    2540             :                     }
    2541             :                 }
    2542       83878 :                 if (bSign)
    2543             :                 {
    2544        2999 :                     sBuff.insert(0, '-');
    2545             :                 }
    2546       83878 :                 OutString = sBuff.makeStringAndClear();
    2547       83878 :                 return false;
    2548             :             }
    2549        3295 :             ImpGetOutputStandard(fNumber, sBuff);
    2550        3295 :             bHadStandard = true;
    2551        3295 :             break;
    2552             :         case NUMBERFORMAT_DATE:
    2553           0 :             bRes |= ImpGetDateOutput(fNumber, 0, sBuff);
    2554           0 :             bHadStandard = true;
    2555           0 :             break;
    2556             :         case NUMBERFORMAT_TIME:
    2557         278 :             bRes |= ImpGetTimeOutput(fNumber, 0, sBuff);
    2558         278 :             bHadStandard = true;
    2559         278 :             break;
    2560             :         case NUMBERFORMAT_DATETIME:
    2561           4 :             bRes |= ImpGetDateTimeOutput(fNumber, 0, sBuff);
    2562           4 :             bHadStandard = true;
    2563           4 :             break;
    2564             :         }
    2565             :     }
    2566       12497 :     if ( !bHadStandard )
    2567             :     {
    2568             :         sal_uInt16 nIx; // Index of the partial format
    2569        8920 :         short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
    2570        8920 :         if (nCheck == -1 || nCheck == 1) // Only 1 String or True
    2571             :         {
    2572        8898 :             nIx = 0;
    2573             :         }
    2574             :         else
    2575             :         {
    2576          22 :             nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
    2577          22 :             if (nCheck == -1 || nCheck == 1)
    2578             :             {
    2579          22 :                 nIx = 1;
    2580             :             }
    2581             :             else
    2582             :             {
    2583           0 :                 nIx = 2;
    2584             :             }
    2585             :         }
    2586        8934 :         if (fNumber < 0.0 &&
    2587        1836 :                 ((nIx == 0 && IsFirstSubformatRealNegative()) || // 1st, usually positive subformat
    2588          14 :                  (nIx == 1 && IsSecondSubformatRealNegative()))) // 2nd, usually negative subformat
    2589             :         {
    2590          14 :             fNumber = -fNumber; // eliminate sign
    2591             :         }
    2592        8920 :         *ppColor = NumFor[nIx].GetColor();
    2593        8920 :         const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    2594        8920 :         const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    2595        8920 :         if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
    2596             :         {
    2597           0 :             return false; // Empty => nothing
    2598             :         }
    2599        8920 :         else if (nAnz == 0) // Else Standard Format
    2600             :         {
    2601           0 :             ImpGetOutputStandard(fNumber, sBuff);
    2602           0 :             OutString = sBuff.makeStringAndClear();
    2603           0 :             return false;
    2604             :         }
    2605        8920 :         switch (rInfo.eScannedType)
    2606             :         {
    2607             :         case NUMBERFORMAT_TEXT:
    2608             :         case NUMBERFORMAT_DEFINED:
    2609          16 :             for (sal_uInt16 i = 0; i < nAnz; i++)
    2610             :             {
    2611           8 :                 switch (rInfo.nTypeArray[i])
    2612             :                 {
    2613             :                 case NF_SYMBOLTYPE_STAR:
    2614           0 :                     if( bStarFlag )
    2615             :                     {
    2616           0 :                         bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
    2617             :                     }
    2618           0 :                     break;
    2619             :                 case NF_SYMBOLTYPE_BLANK:
    2620             :                     InsertBlanks(sBuff, sBuff.getLength(),
    2621           0 :                                  rInfo.sStrArray[i][1] );
    2622           0 :                     break;
    2623             :                 case NF_SYMBOLTYPE_STRING:
    2624             :                 case NF_SYMBOLTYPE_CURRENCY:
    2625           8 :                     sBuff.append(rInfo.sStrArray[i]);
    2626           8 :                     break;
    2627             :                 case NF_SYMBOLTYPE_THSEP:
    2628           0 :                     if (rInfo.nThousand == 0)
    2629             :                     {
    2630           0 :                         sBuff.append(rInfo.sStrArray[i]);
    2631             :                     }
    2632           0 :                     break;
    2633             :                 default:
    2634           0 :                     break;
    2635             :                 }
    2636             :             }
    2637           8 :             break;
    2638             :         case NUMBERFORMAT_DATE:
    2639        2216 :             bRes |= ImpGetDateOutput(fNumber, nIx, sBuff);
    2640        2216 :             break;
    2641             :         case NUMBERFORMAT_TIME:
    2642         400 :             bRes |= ImpGetTimeOutput(fNumber, nIx, sBuff);
    2643         400 :                 break;
    2644             :         case NUMBERFORMAT_DATETIME:
    2645          22 :             bRes |= ImpGetDateTimeOutput(fNumber, nIx, sBuff);
    2646          22 :             break;
    2647             :         case NUMBERFORMAT_NUMBER:
    2648             :         case NUMBERFORMAT_PERCENT:
    2649             :         case NUMBERFORMAT_CURRENCY:
    2650        6240 :             bRes |= ImpGetNumberOutput(fNumber, nIx, sBuff);
    2651        6240 :             break;
    2652             :         case NUMBERFORMAT_FRACTION:
    2653          16 :             bRes |= ImpGetFractionOutput(fNumber, nIx, sBuff);
    2654          16 :             break;
    2655             :         case NUMBERFORMAT_SCIENTIFIC:
    2656          18 :             bRes |= ImpGetScientificOutput(fNumber, nIx, sBuff);
    2657          18 :             break;
    2658             :         }
    2659             :     }
    2660       12497 :     OutString = sBuff.makeStringAndClear();
    2661       12497 :     return bRes;
    2662             : }
    2663             : 
    2664          18 : bool SvNumberformat::ImpGetScientificOutput(double fNumber,
    2665             :                                             sal_uInt16 nIx,
    2666             :                                             OUStringBuffer& sStr)
    2667             : {
    2668          18 :     bool bRes = false;
    2669          18 :     bool bSign = false;
    2670             : 
    2671          18 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    2672          18 :     const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    2673             : 
    2674          18 :     if (fNumber < 0)
    2675             :     {
    2676           6 :         if (nIx == 0) // Not in the ones at the end
    2677             :         {
    2678           6 :             bSign = true; // Formats
    2679             :         }
    2680           6 :         fNumber = -fNumber;
    2681             :     }
    2682             : 
    2683          36 :     sStr = ::rtl::math::doubleToUString( fNumber,
    2684             :                                          rtl_math_StringFormat_E,
    2685          36 :                                          rInfo.nCntPre + rInfo.nCntPost - 1, '.' );
    2686          18 :     OUStringBuffer ExpStr;
    2687          18 :     short nExpSign = 1;
    2688          18 :     sal_Int32 nExPos = sStr.indexOf('E');
    2689             : 
    2690          18 :     if ( nExPos >= 0 )
    2691             :     {
    2692             :         // split into mantisse and exponent and get rid of "E+" or "E-"
    2693          18 :         sal_Int32 nExpStart = nExPos + 1;
    2694             : 
    2695          18 :         switch ( sStr[ nExpStart ] )
    2696             :         {
    2697             :         case '-' :
    2698           0 :             nExpSign = -1;
    2699             :             // fallthru
    2700             :         case '+' :
    2701          18 :             ++nExpStart;
    2702          18 :             break;
    2703             :         }
    2704          18 :         ExpStr = sStr.toString().copy( nExpStart );    // part following the "E+"
    2705          18 :         sStr.truncate( nExPos );
    2706             :         // cut any decimal delimiter
    2707          18 :         sal_Int32 index = 0;
    2708             : 
    2709          54 :         while((index = sStr.indexOf('.', index)) >= 0)
    2710             :         {
    2711          18 :             sStr.remove(index, 1);
    2712             :         }
    2713          18 :         if ( rInfo.nCntPre != 1 ) // rescale Exp
    2714             :         {
    2715           2 :             sal_Int32 nExp = ExpStr.toString().toInt32() * nExpSign;
    2716             : 
    2717           2 :             nExp -= (sal_Int32)rInfo.nCntPre - 1;
    2718           2 :             if ( nExp < 0 )
    2719             :             {
    2720           2 :                 nExpSign = -1;
    2721           2 :                 nExp = -nExp;
    2722             :             }
    2723             :             else
    2724             :             {
    2725           0 :                 nExpSign = 1;
    2726             :             }
    2727           2 :             ExpStr = OUString::number( nExp );
    2728             :         }
    2729             :     }
    2730             : 
    2731          18 :     sal_uInt16 j = nAnz-1;  // Last symbol
    2732             :     sal_Int32 k;  // Position in ExpStr
    2733          18 :     sal_Int32 nZeros = 0; // Erase leading zeros
    2734             : 
    2735          18 :     bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
    2736             : 
    2737          42 :     while (nZeros < k && ExpStr[nZeros] == '0')
    2738             :     {
    2739           6 :         ++nZeros;
    2740             :     }
    2741          18 :     if (nZeros)
    2742             :     {
    2743           6 :         ExpStr.remove( 0, nZeros);
    2744             :     }
    2745             : 
    2746          18 :     bool bCont = true;
    2747             : 
    2748          18 :     if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
    2749             :     {
    2750          18 :         const OUString& rStr = rInfo.sStrArray[j];
    2751          18 :         if (nExpSign == -1)
    2752             :         {
    2753           2 :             ExpStr.insert(0, '-');
    2754             :         }
    2755          16 :         else if (rStr.getLength() > 1 && rStr[1] == '+')
    2756             :         {
    2757          16 :             ExpStr.insert(0, '+');
    2758             :         }
    2759          18 :         ExpStr.insert(0, rStr[0]);
    2760          18 :         if ( j )
    2761             :         {
    2762          18 :             j--;
    2763             :         }
    2764             :         else
    2765             :         {
    2766           0 :             bCont = false;
    2767             :         }
    2768             :     }
    2769             :     // Continure main number:
    2770          18 :     if ( !bCont )
    2771             :     {
    2772           0 :         sStr.truncate();
    2773             :     }
    2774             :     else
    2775             :     {
    2776          18 :         k = sStr.getLength(); // After last figure
    2777             :         bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
    2778          18 :                                            rInfo.nCntPre + rInfo.nCntPost);
    2779             :     }
    2780          18 :     if (bSign)
    2781             :     {
    2782           6 :         sStr.insert(0, '-');
    2783             :     }
    2784          18 :     sStr.append(ExpStr);
    2785             : 
    2786          18 :     return bRes;
    2787             : }
    2788             : 
    2789          16 : bool SvNumberformat::ImpGetFractionOutput(double fNumber,
    2790             :                                           sal_uInt16 nIx,
    2791             :                                           OUStringBuffer& sBuff)
    2792             : {
    2793          16 :     bool bRes = false;
    2794          16 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    2795          16 :     const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    2796          32 :     OUStringBuffer sStr, sFrac, sDiv; // Strings, value for
    2797             :     sal_uLong nFrac, nDiv;            // Integral part
    2798          16 :     bool bSign = false;               // Numerator and denominator
    2799             : 
    2800          16 :     if (fNumber < 0)
    2801             :     {
    2802           0 :         if (nIx == 0) // Not in the ones at the end
    2803           0 :             bSign = true; // Formats
    2804           0 :         fNumber = -fNumber;
    2805             :     }
    2806             : 
    2807          16 :     double fNum = floor(fNumber); // Integral part
    2808             : 
    2809          16 :     fNumber -= fNum; // Fractional part
    2810          16 :     if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) // Too large
    2811             :     {
    2812           0 :         sBuff = rScan.GetErrorString();
    2813           0 :         return false;
    2814             :     }
    2815          16 :     if (rInfo.nCntExp == 0)
    2816             :     {
    2817             :         SAL_WARN( "svl.numbers", "SvNumberformat:: Fraction, nCntExp == 0");
    2818           0 :         sBuff.truncate();
    2819           0 :         return false;
    2820             :     }
    2821             : 
    2822          16 :     sal_uLong nBasis = ((sal_uLong)floor( pow(10.0,rInfo.nCntExp))) - 1; // 9, 99, 999 ,...
    2823             :     sal_uLong x0, y0, x1, y1;
    2824             : 
    2825          16 :     if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
    2826             :     {
    2827             :         bool bUpperHalf;
    2828             : 
    2829          16 :         if (fNumber > 0.5)
    2830             :         {
    2831           0 :             bUpperHalf = true;
    2832           0 :             fNumber -= (fNumber - 0.5) * 2.0;
    2833             :         }
    2834             :         else
    2835             :         {
    2836          16 :             bUpperHalf = false;
    2837             :         }
    2838             :         // Find entry to Farey sequence:
    2839          16 :         x0 = (sal_uLong) floor(fNumber*nBasis); // e.g.: 2/9 <= x < 3/9
    2840          16 :         if (x0 == 0)                            // => x0 = 2
    2841             :         {
    2842           0 :             y0 = 1;
    2843           0 :             x1 = 1;
    2844           0 :             y1 = nBasis;
    2845             :         }
    2846          16 :         else if (x0 == (nBasis-1)/2)    // (b-1)/2, 1/2
    2847             :         {                               // is ok (nBasis is odd)
    2848           0 :             y0 = nBasis;
    2849           0 :             x1 = 1;
    2850           0 :             y1 = 2;
    2851             :         }
    2852          16 :         else if (x0 == 1)
    2853             :         {
    2854           8 :             y0 = nBasis;                //  1/n; 1/(n-1)
    2855           8 :             x1 = 1;
    2856           8 :             y1 = nBasis - 1;
    2857             :         }
    2858             :         else
    2859             :         {
    2860           8 :             y0 = nBasis;                // e.g.: 2/9   2/8
    2861           8 :             x1 = x0;
    2862           8 :             y1 = nBasis - 1;
    2863           8 :             double fUg = (double) x0 / (double) y0;
    2864           8 :             double fOg = (double) x1 / (double) y1;
    2865           8 :             sal_uLong nGgt = ImpGGT(y0, x0);       // x0/y0 kuerzen
    2866           8 :             x0 /= nGgt;
    2867           8 :             y0 /= nGgt;                     // Nest:
    2868           8 :             sal_uLong x2 = 0;
    2869           8 :             sal_uLong y2 = 0;
    2870           8 :             bool bStop = false;
    2871          34 :             while (!bStop)
    2872             :             {
    2873             : #ifdef __GNUC__
    2874             :                 // #i21648# GCC over-optimizes something resulting
    2875             :                 // in wrong fTest values throughout the loops.
    2876             :                 volatile
    2877             : #endif
    2878          18 :                     double fTest = (double)x1/(double)y1;
    2879          56 :                 while (!bStop)
    2880             :                 {
    2881          52 :                     while (fTest > fOg)
    2882             :                     {
    2883          12 :                         x1--;
    2884          12 :                         fTest = (double)x1/(double)y1;
    2885             :                     }
    2886          56 :                     while (fTest < fUg && y1 > 1)
    2887             :                     {
    2888          16 :                         y1--;
    2889          16 :                         fTest = (double)x1/(double)y1;
    2890             :                     }
    2891          20 :                     if (fTest <= fOg)
    2892             :                     {
    2893          18 :                         fOg = fTest;
    2894          18 :                         bStop = true;
    2895             :                     }
    2896           2 :                     else if (y1 == 1)
    2897             :                     {
    2898           0 :                         bStop = true;
    2899             :                     }
    2900             :                 } // of while
    2901          18 :                 nGgt = ImpGGT(y1, x1); // Shorten x1/y1
    2902          18 :                 x2 = x1 / nGgt;
    2903          18 :                 y2 = y1 / nGgt;
    2904          18 :                 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test for x2/y2
    2905           8 :                     bStop = true;                  // Next Farey number
    2906             :                 else
    2907             :                 {
    2908          10 :                     y1--;
    2909          10 :                     bStop = false;
    2910             :                 }
    2911             :             } // of while
    2912           8 :             x1 = x2;
    2913           8 :             y1 = y2;
    2914             :         } // of else
    2915             : 
    2916             :         double fup, flow;
    2917             : 
    2918          16 :         flow = (double)x0/(double)y0;
    2919          16 :         fup  = (double)x1/(double)y1;
    2920         140 :         while (fNumber > fup)
    2921             :         {
    2922         108 :             sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // Next Farey number
    2923         108 :             sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0;
    2924             : 
    2925         108 :             x0 = x1;
    2926         108 :             y0 = y1;
    2927         108 :             x1 = x2;
    2928         108 :             y1 = y2;
    2929         108 :             flow = fup;
    2930         108 :             fup  = (double)x1/(double)y1;
    2931             :         }
    2932          16 :         if (fNumber - flow < fup - fNumber)
    2933             :         {
    2934           6 :             nFrac = x0;
    2935           6 :             nDiv  = y0;
    2936             :         }
    2937             :         else
    2938             :         {
    2939          10 :             nFrac = x1;
    2940          10 :             nDiv  = y1;
    2941             :         }
    2942          16 :         if (bUpperHalf) // Recover original
    2943             :         {
    2944           0 :             if (nFrac == 0 && nDiv == 1) // 1/1
    2945             :             {
    2946           0 :                 fNum += 1.0;
    2947             :             }
    2948             :             else
    2949             :             {
    2950           0 :                 nFrac = nDiv - nFrac;
    2951             :             }
    2952             :         }
    2953             :     }
    2954             :     else // Large denominator
    2955             :     {    // 0,1234->123/1000
    2956             :         sal_uLong nGgt;
    2957             : 
    2958           0 :         nDiv = 10000000;
    2959           0 :         nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0));
    2960           0 :         nGgt = ImpGGT(nDiv, nFrac);
    2961           0 :         if (nGgt > 1)
    2962             :         {
    2963           0 :             nDiv  /= nGgt;
    2964           0 :             nFrac /= nGgt;
    2965             :         }
    2966           0 :         if (nDiv > nBasis)
    2967             :         {
    2968           0 :             nGgt = ImpGGTRound(nDiv, nFrac);
    2969           0 :             if (nGgt > 1)
    2970             :             {
    2971           0 :                 nDiv  /= nGgt;
    2972           0 :                 nFrac /= nGgt;
    2973             :             }
    2974             :         }
    2975           0 :         if (nDiv > nBasis)
    2976             :         {
    2977           0 :             nDiv = nBasis;
    2978           0 :             nFrac = ((sal_uLong)floor(0.5 + fNumber *
    2979           0 :                                       pow(10.0,rInfo.nCntExp)));
    2980           0 :             nGgt = ImpGGTRound(nDiv, nFrac);
    2981           0 :             if (nGgt > 1)
    2982             :             {
    2983           0 :                 nDiv  /= nGgt;
    2984           0 :                 nFrac /= nGgt;
    2985             :             }
    2986             :         }
    2987             :     }
    2988             : 
    2989          16 :     if( sal_Int32 nForcedDiv = lcl_GetForcedDenominator(NumFor[nIx].Info(), nAnz) )
    2990             :     {
    2991           0 :         lcl_ForcedDenominator(nFrac, nDiv, nForcedDiv);
    2992           0 :         if( nFrac >= nDiv )
    2993             :         {
    2994           0 :             nFrac = nDiv = 0;
    2995           0 :             fNum = fNum + 1.0;
    2996             :         }
    2997             :     }
    2998             : 
    2999          16 :     if (rInfo.nCntPre == 0) // Improper fraction
    3000             :     {
    3001           0 :         double fNum1 = fNum * (double)nDiv + (double)nFrac;
    3002             : 
    3003           0 :         if (fNum1 > _D_MAX_U_LONG_)
    3004             :         {
    3005           0 :             sBuff = rScan.GetErrorString();
    3006           0 :             return false;
    3007             :         }
    3008           0 :         nFrac = (sal_uLong) floor(fNum1);
    3009             :     }
    3010          16 :     else if (fNum == 0.0 && nFrac != 0)
    3011             :     {
    3012             :     }
    3013             :     else
    3014             :     {
    3015             :         char aBuf[100];
    3016          14 :         sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
    3017          14 :         sStr.appendAscii( aBuf );
    3018          14 :         impTransliterate(sStr, NumFor[nIx].GetNatNum());
    3019             :     }
    3020          16 :     if (rInfo.nCntPre > 0 && nFrac == 0)
    3021             :     {
    3022           0 :         sDiv.truncate();
    3023             :     }
    3024             :     else
    3025             :     {
    3026          16 :         sFrac = ImpIntToString( nIx, nFrac );
    3027          16 :         sDiv = ImpIntToString( nIx, nDiv );
    3028             :     }
    3029             : 
    3030          16 :     sal_uInt16 j = nAnz-1; // Last symbol -> backwards
    3031             :     sal_Int32 k;           // Denominator
    3032             : 
    3033          16 :     bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
    3034             : 
    3035          16 :     bool bCont = true;
    3036          16 :     if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
    3037             :     {
    3038          16 :         if (rInfo.nCntPre > 0 && nFrac == 0)
    3039             :         {
    3040           0 :             sDiv.insert(0, ' ');
    3041             :         }
    3042             :         else
    3043             :         {
    3044          16 :             sDiv.insert(0, rInfo.sStrArray[j][0]);
    3045             :         }
    3046          16 :         if ( j )
    3047             :         {
    3048          16 :             j--;
    3049             :         }
    3050             :         else
    3051             :         {
    3052           0 :             bCont = false;
    3053             :         }
    3054             :     }
    3055             :     // Further numerators:
    3056          16 :     if ( !bCont )
    3057             :     {
    3058           0 :         sFrac.truncate();
    3059             :     }
    3060             :     else
    3061             :     {
    3062          16 :         bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
    3063          16 :         if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
    3064             :         {
    3065          16 :             sFrac.insert(0, rInfo.sStrArray[j]);
    3066          16 :             if ( j )
    3067             :             {
    3068          16 :                 j--;
    3069             :             }
    3070             :             else
    3071             :             {
    3072           0 :                 bCont = false;
    3073             :             }
    3074             :         }
    3075             :     }
    3076             :     // Continue main number
    3077          16 :     if ( !bCont )
    3078             :     {
    3079           0 :         sStr.truncate();
    3080             :     }
    3081             :     else
    3082             :     {
    3083          16 :         k = sStr.getLength(); // After last figure
    3084             :         bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
    3085          16 :                                            rInfo.nCntPre);
    3086             :     }
    3087          16 :     if (bSign && !(nFrac == 0 && fNum == 0.0))
    3088             :     {
    3089           0 :         sBuff.insert(0, '-'); // Not -0
    3090             :     }
    3091          16 :     sBuff.append(sStr);
    3092          16 :     sBuff.append(sFrac);
    3093          16 :     sBuff.append(sDiv);
    3094          32 :     return bRes;
    3095             : }
    3096             : 
    3097         678 : bool SvNumberformat::ImpGetTimeOutput(double fNumber,
    3098             :                                       sal_uInt16 nIx,
    3099             :                                       OUStringBuffer& sBuff)
    3100             : {
    3101             :     using namespace ::com::sun::star::i18n;
    3102         678 :     bool bCalendarSet = false;
    3103         678 :     double fNumberOrig = fNumber;
    3104         678 :     bool bRes = false;
    3105         678 :     bool bSign = false;
    3106         678 :     if (fNumber < 0.0)
    3107             :     {
    3108           0 :         fNumber = -fNumber;
    3109           0 :         if (nIx == 0)
    3110             :         {
    3111           0 :             bSign = true;
    3112             :         }
    3113             :     }
    3114         678 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    3115         678 :     if (rInfo.bThousand) // [] format
    3116             :     {
    3117           0 :         if (fNumber > 1.0E10) // Too large
    3118             :         {
    3119           0 :             sBuff = rScan.GetErrorString();
    3120           0 :             return false;
    3121             :         }
    3122             :     }
    3123             :     else
    3124             :     {
    3125         678 :         fNumber -= floor(fNumber); // Else truncate date
    3126             :     }
    3127             :     bool bInputLine;
    3128             :     sal_Int32 nCntPost;
    3129        1356 :     if ( rScan.GetStandardPrec() == 300 &&
    3130         678 :          0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
    3131             :     {   // round at 7 decimals (+5 of 86400 == 12 significant digits)
    3132           0 :         bInputLine = true;
    3133           0 :         nCntPost = 7;
    3134             :     }
    3135             :     else
    3136             :     {
    3137         678 :         bInputLine = false;
    3138         678 :         nCntPost = rInfo.nCntPost;
    3139             :     }
    3140         678 :     if (bSign && !rInfo.bThousand) // No [] format
    3141             :     {
    3142           0 :         fNumber = 1.0 - fNumber; // "Inverse"
    3143             :     }
    3144         678 :     double fTime = fNumber * 86400.0;
    3145         678 :     fTime = ::rtl::math::round( fTime, int(nCntPost) );
    3146         678 :     if (bSign && fTime == 0.0)
    3147             :     {
    3148           0 :         bSign = false; // Not -00:00:00
    3149             :     }
    3150         678 :     if( floor( fTime ) > _D_MAX_U_LONG_ )
    3151             :     {
    3152           0 :         sBuff = rScan.GetErrorString();
    3153           0 :         return false;
    3154             :     }
    3155         678 :     sal_uLong nSeconds = (sal_uLong)floor( fTime );
    3156             : 
    3157             :     OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
    3158         678 :                                                           rtl_math_StringFormat_F, int(nCntPost), '.'));
    3159         678 :     sSecStr.stripStart('0');
    3160         678 :     sSecStr.stripStart('.');
    3161         678 :     if ( bInputLine )
    3162             :     {
    3163           0 :         sSecStr.stripEnd('0');
    3164           0 :         for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
    3165             :         {
    3166           0 :             sSecStr.append('0');
    3167             :         }
    3168           0 :         impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
    3169           0 :         nCntPost = sSecStr.getLength();
    3170             :     }
    3171             :     else
    3172             :     {
    3173         678 :         impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
    3174             :     }
    3175             : 
    3176         678 :     sal_Int32 nSecPos = 0; // For figure by figure processing
    3177             :     sal_uLong nHour, nMin, nSec;
    3178         678 :     if (!rInfo.bThousand) // No [] format
    3179             :     {
    3180         678 :         nHour = (nSeconds/3600) % 24;
    3181         678 :         nMin = (nSeconds%3600) / 60;
    3182         678 :         nSec = nSeconds%60;
    3183             :     }
    3184           0 :     else if (rInfo.nThousand == 3) // [ss]
    3185             :     {
    3186           0 :         nHour = 0;
    3187           0 :         nMin = 0;
    3188           0 :         nSec = nSeconds;
    3189             :     }
    3190           0 :     else if (rInfo.nThousand == 2) // [mm]:ss
    3191             :     {
    3192           0 :         nHour = 0;
    3193           0 :         nMin = nSeconds / 60;
    3194           0 :         nSec = nSeconds % 60;
    3195             :     }
    3196           0 :     else if (rInfo.nThousand == 1) // [hh]:mm:ss
    3197             :     {
    3198           0 :         nHour = nSeconds / 3600;
    3199           0 :         nMin = (nSeconds%3600) / 60;
    3200           0 :         nSec = nSeconds%60;
    3201             :     }
    3202             :     else
    3203             :     {
    3204             :         // TODO  What should these be set to?
    3205           0 :         nHour = 0;
    3206           0 :         nMin  = 0;
    3207           0 :         nSec  = 0;
    3208             :     }
    3209             : 
    3210         678 :     sal_Unicode cAmPm = ' '; // a or p
    3211         678 :     if (rInfo.nCntExp) // AM/PM
    3212             :     {
    3213         278 :         if (nHour == 0)
    3214             :         {
    3215          26 :             nHour = 12;
    3216          26 :             cAmPm = 'a';
    3217             :         }
    3218         252 :         else if (nHour < 12)
    3219             :         {
    3220         148 :             cAmPm = 'a';
    3221             :         }
    3222             :         else
    3223             :         {
    3224         104 :             cAmPm = 'p';
    3225         104 :             if (nHour > 12)
    3226             :             {
    3227          84 :                 nHour -= 12;
    3228             :             }
    3229             :         }
    3230             :     }
    3231         678 :     const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    3232        4608 :     for (sal_uInt16 i = 0; i < nAnz; i++)
    3233             :     {
    3234             :         sal_Int32 nLen;
    3235        3930 :         switch (rInfo.nTypeArray[i])
    3236             :         {
    3237             :         case NF_SYMBOLTYPE_STAR:
    3238           0 :             if( bStarFlag )
    3239             :             {
    3240           0 :                 bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
    3241             :             }
    3242           0 :             break;
    3243             :         case NF_SYMBOLTYPE_BLANK:
    3244             :             InsertBlanks(sBuff, sBuff.getLength(),
    3245           0 :                          rInfo.sStrArray[i][1] );
    3246           0 :             break;
    3247             :         case NF_SYMBOLTYPE_STRING:
    3248             :         case NF_SYMBOLTYPE_CURRENCY:
    3249             :         case NF_SYMBOLTYPE_DATESEP:
    3250             :         case NF_SYMBOLTYPE_TIMESEP:
    3251             :         case NF_SYMBOLTYPE_TIME100SECSEP:
    3252        1626 :             sBuff.append(rInfo.sStrArray[i]);
    3253        1626 :             break;
    3254             :         case NF_SYMBOLTYPE_DIGIT:
    3255           0 :             nLen = ( bInputLine && i > 0 &&
    3256           0 :                      (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
    3257           0 :                       rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
    3258           0 :                      nCntPost : rInfo.sStrArray[i].getLength() );
    3259           0 :             for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost; j++)
    3260             :             {
    3261           0 :                 sBuff.append(sSecStr[nSecPos]);
    3262           0 :                 nSecPos++;
    3263             :             }
    3264           0 :             break;
    3265             :         case NF_KEY_AMPM:               // AM/PM
    3266         278 :             if ( !bCalendarSet )
    3267             :             {
    3268         278 :                 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
    3269         278 :                 fDiff += fNumberOrig;
    3270         278 :                 GetCal().setLocalDateTime( fDiff );
    3271         278 :                 bCalendarSet = true;
    3272             :             }
    3273         278 :             if (cAmPm == 'a')
    3274             :             {
    3275         174 :                 sBuff.append(GetCal().getDisplayName(
    3276         174 :                                  CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ));
    3277             :             }
    3278             :             else
    3279             :             {
    3280         104 :                 sBuff.append(GetCal().getDisplayName(
    3281         104 :                                  CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ));
    3282             :             }
    3283         278 :             break;
    3284             :         case NF_KEY_AP:                 // A/P
    3285           0 :             if (cAmPm == 'a')
    3286             :             {
    3287           0 :                 sBuff.append('a');
    3288             :             }
    3289             :             else
    3290             :             {
    3291           0 :                 sBuff.append('p');
    3292             :             }
    3293           0 :             break;
    3294             :         case NF_KEY_MI:                 // M
    3295           0 :             sBuff.append(ImpIntToString( nIx, nMin ));
    3296           0 :             break;
    3297             :         case NF_KEY_MMI:                // MM
    3298         678 :             sBuff.append(ImpIntToString( nIx, nMin, 2 ));
    3299         678 :             break;
    3300             :         case NF_KEY_H:                  // H
    3301           0 :             sBuff.append(ImpIntToString( nIx, nHour ));
    3302           0 :             break;
    3303             :         case NF_KEY_HH:                 // HH
    3304         678 :             sBuff.append(ImpIntToString( nIx, nHour, 2 ));
    3305         678 :             break;
    3306             :         case NF_KEY_S:                  // S
    3307           0 :             sBuff.append(ImpIntToString( nIx, nSec ));
    3308           0 :             break;
    3309             :         case NF_KEY_SS:                 // SS
    3310         670 :             sBuff.append(ImpIntToString( nIx, nSec, 2 ));
    3311         670 :             break;
    3312             :         default:
    3313           0 :             break;
    3314             :         }
    3315             :     }
    3316         678 :     if (bSign && rInfo.bThousand)
    3317             :     {
    3318           0 :         sBuff.insert(0, '-');
    3319             :     }
    3320         678 :     return bRes;
    3321             : }
    3322             : 
    3323             : 
    3324             : /** If a day of month occurs within the format, the month name is in possessive
    3325             :     genitive case if the day follows the month, and partitive case if the day
    3326             :     precedes the month. If there is no day of month the nominative case (noun)
    3327             :     is returned. Also if the month is immediately preceded or followed by a
    3328             :     literal string other than space the nominative name is used, this prevents
    3329             :     duplicated casing for MMMM\t\a and such in documents imported from (e.g.
    3330             :     Finnish) Excel or older LibO/OOo releases.
    3331             :  */
    3332             : 
    3333             : // IDEA: instead of eCodeType pass the index to nTypeArray and restrict
    3334             : // inspection of month name around that one, that would enable different month
    3335             : // cases in one format. Though probably the most rare use case ever..
    3336             : 
    3337        1480 : sal_Int32 SvNumberformat::ImpUseMonthCase( int & io_nState, const ImpSvNumFor& rNumFor, NfKeywordIndex eCodeType ) const
    3338             : {
    3339             :     using namespace ::com::sun::star::i18n;
    3340        1480 :     if (!io_nState)
    3341             :     {
    3342        1480 :         bool bMonthSeen = false;
    3343        1480 :         bool bDaySeen = false;
    3344        1480 :         const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
    3345        1480 :         const sal_uInt16 nCount = rNumFor.GetCount();
    3346        5896 :         for (sal_uInt16 i = 0; i < nCount && io_nState == 0; ++i)
    3347             :         {
    3348             :             sal_Int32 nLen;
    3349        4416 :             switch (rInfo.nTypeArray[i])
    3350             :             {
    3351             :             case NF_KEY_D :
    3352             :             case NF_KEY_DD :
    3353        1468 :                 if (bMonthSeen)
    3354             :                 {
    3355        1464 :                     io_nState = 2;
    3356             :                 }
    3357             :                 else
    3358             :                 {
    3359           4 :                     bDaySeen = true;
    3360             :                 }
    3361        1468 :                 break;
    3362             :             case NF_KEY_MMM:
    3363             :             case NF_KEY_MMMM:
    3364             :             case NF_KEY_MMMMM:
    3365        4440 :                 if ((i < nCount-1 &&
    3366        2960 :                      rInfo.nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
    3367        4440 :                      rInfo.sStrArray[i+1][0] != ' ') ||
    3368           8 :                     (i > 0 && rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING &&
    3369           8 :                      ((nLen = rInfo.sStrArray[i-1].getLength()) > 0) &&
    3370           4 :                      rInfo.sStrArray[i-1][nLen-1] != ' '))
    3371             :                 {
    3372          12 :                     io_nState = 1;
    3373             :                 }
    3374        1468 :                 else if (bDaySeen)
    3375             :                 {
    3376           4 :                     io_nState = 3;
    3377             :                 }
    3378             :                 else
    3379             :                 {
    3380        1464 :                     bMonthSeen = true;
    3381             :                 }
    3382        1480 :                 break;
    3383             :             }
    3384             :         }
    3385        1480 :         if (io_nState == 0)
    3386             :         {
    3387           0 :             io_nState = 1; // No day of month
    3388             :         }
    3389             :     }
    3390        1480 :     switch (io_nState)
    3391             :     {
    3392             :     case 1:
    3393             :         // No day of month or forced nominative
    3394          12 :         switch (eCodeType)
    3395             :         {
    3396             :         case NF_KEY_MMM:
    3397          12 :             return CalendarDisplayCode::SHORT_MONTH_NAME;
    3398             :         case NF_KEY_MMMM:
    3399           0 :             return CalendarDisplayCode::LONG_MONTH_NAME;
    3400             :         case NF_KEY_MMMMM:
    3401           0 :             return CalendarDisplayCode::NARROW_MONTH_NAME;
    3402             :         default:
    3403             :             ;   // nothing
    3404             :         }
    3405             :     case 2:
    3406             :         // Day of month follows month (the month's 17th)
    3407        1464 :         switch (eCodeType)
    3408             :         {
    3409             :         case NF_KEY_MMM:
    3410        1464 :             return CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME;
    3411             :         case NF_KEY_MMMM:
    3412           0 :             return CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME;
    3413             :         case NF_KEY_MMMMM:
    3414           0 :             return CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME;
    3415             :         default:
    3416             :             ;   // Nothing
    3417             :         }
    3418             :     case 3:
    3419             :         // Day of month precedes month (17 of month)
    3420           4 :         switch (eCodeType)
    3421             :         {
    3422             :         case NF_KEY_MMM:
    3423           0 :             return CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME;
    3424             :         case NF_KEY_MMMM:
    3425           4 :             return CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME;
    3426             :         case NF_KEY_MMMMM:
    3427           0 :             return CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME;
    3428             :         default:
    3429             :             ;   // nothing
    3430             :         }
    3431             :     }
    3432             :     SAL_WARN( "svl.numbers", "ImpUseMonthCase: unhandled keyword index eCodeType");
    3433           0 :     return CalendarDisplayCode::LONG_MONTH_NAME;
    3434             : }
    3435             : 
    3436             : 
    3437        2242 : bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
    3438             : {
    3439        2242 :     if ( GetCal().getUniqueID() != Gregorian::get() )
    3440             :     {
    3441           0 :         return false;
    3442             :     }
    3443        2242 :     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
    3444        2242 :     const sal_uInt16 nAnz = rNumFor.GetCount();
    3445             :     sal_uInt16 i;
    3446       10644 :     for ( i = 0; i < nAnz; i++ )
    3447             :     {
    3448        8414 :         switch ( rInfo.nTypeArray[i] )
    3449             :         {
    3450             :         case NF_SYMBOLTYPE_CALENDAR :
    3451           8 :             return false;
    3452             :         case NF_KEY_EC :
    3453             :         case NF_KEY_EEC :
    3454             :         case NF_KEY_R :
    3455             :         case NF_KEY_RR :
    3456             :         case NF_KEY_AAA :
    3457             :         case NF_KEY_AAAA :
    3458           4 :             return true;
    3459             :         }
    3460             :     }
    3461        2230 :     return false;
    3462             : }
    3463             : 
    3464           4 : void SvNumberformat::SwitchToOtherCalendar( OUString& rOrgCalendar,
    3465             :                                             double& fOrgDateTime ) const
    3466             : {
    3467           4 :     CalendarWrapper& rCal = GetCal();
    3468           4 :     const OUString &rGregorian = Gregorian::get();
    3469           4 :     if ( rCal.getUniqueID() == rGregorian )
    3470             :     {
    3471             :         using namespace ::com::sun::star::i18n;
    3472             :         ::com::sun::star::uno::Sequence< OUString > xCals = rCal.getAllCalendars(
    3473           4 :                 rLoc().getLanguageTag().getLocale() );
    3474           4 :         sal_Int32 nCnt = xCals.getLength();
    3475           4 :         if ( nCnt > 1 )
    3476             :         {
    3477           8 :             for ( sal_Int32 j=0; j < nCnt; j++ )
    3478             :             {
    3479           8 :                 if ( xCals[j] != rGregorian )
    3480             :                 {
    3481           4 :                     if ( !rOrgCalendar.getLength() )
    3482             :                     {
    3483           4 :                         rOrgCalendar = rCal.getUniqueID();
    3484           4 :                         fOrgDateTime = rCal.getDateTime();
    3485             :                     }
    3486           4 :                     rCal.loadCalendar( xCals[j], rLoc().getLanguageTag().getLocale() );
    3487           4 :                     rCal.setDateTime( fOrgDateTime );
    3488           4 :                     break;  // for
    3489             :                 }
    3490             :             }
    3491           4 :         }
    3492             :     }
    3493           4 : }
    3494             : 
    3495           0 : void SvNumberformat::SwitchToGregorianCalendar( const OUString& rOrgCalendar,
    3496             :                                                 double fOrgDateTime ) const
    3497             : {
    3498           0 :     CalendarWrapper& rCal = GetCal();
    3499           0 :     const OUString &rGregorian = Gregorian::get();
    3500           0 :     if ( rOrgCalendar.getLength() && rCal.getUniqueID() != rGregorian )
    3501             :     {
    3502           0 :         rCal.loadCalendar( rGregorian, rLoc().getLanguageTag().getLocale() );
    3503           0 :         rCal.setDateTime( fOrgDateTime );
    3504             :     }
    3505           0 : }
    3506             : 
    3507        2250 : bool SvNumberformat::ImpFallBackToGregorianCalendar( OUString& rOrgCalendar, double& fOrgDateTime )
    3508             : {
    3509             :     using namespace ::com::sun::star::i18n;
    3510        2250 :     CalendarWrapper& rCal = GetCal();
    3511        2250 :     const OUString &rGregorian = Gregorian::get();
    3512        2250 :     if ( rCal.getUniqueID() != rGregorian )
    3513             :     {
    3514          12 :         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
    3515          12 :         if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID == "Dummy" )
    3516             :         {
    3517           0 :             if ( !rOrgCalendar.getLength() )
    3518             :             {
    3519           0 :                 rOrgCalendar = rCal.getUniqueID();
    3520           0 :                 fOrgDateTime = rCal.getDateTime();
    3521             :             }
    3522           0 :             else if ( rOrgCalendar == rGregorian )
    3523             :             {
    3524           0 :                 rOrgCalendar = "";
    3525             :             }
    3526           0 :             rCal.loadCalendar( rGregorian, rLoc().getLanguageTag().getLocale() );
    3527           0 :             rCal.setDateTime( fOrgDateTime );
    3528           0 :             return true;
    3529             :         }
    3530             :     }
    3531        2250 :     return false;
    3532             : }
    3533             : 
    3534             : 
    3535             : #ifdef THE_FUTURE
    3536             : /* XXX NOTE: even if the ImpSwitchToSpecifiedCalendar method is currently
    3537             :  * unused please don't remove it, it would be needed by
    3538             :  * SwitchToSpecifiedCalendar(), see comment in
    3539             :  * ImpSvNumberInputScan::GetDateRef() */
    3540             : 
    3541             : bool SvNumberformat::ImpSwitchToSpecifiedCalendar( OUString& rOrgCalendar,
    3542             :                                                    double& fOrgDateTime,
    3543             :                                                    const ImpSvNumFor& rNumFor ) const
    3544             : {
    3545             :     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
    3546             :     const sal_uInt16 nAnz = rNumFor.GetCount();
    3547             :     for ( sal_uInt16 i = 0; i < nAnz; i++ )
    3548             :     {
    3549             :         if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
    3550             :         {
    3551             :             CalendarWrapper& rCal = GetCal();
    3552             :             if ( !rOrgCalendar.getLength() )
    3553             :             {
    3554             :                 rOrgCalendar = rCal.getUniqueID();
    3555             :                 fOrgDateTime = rCal.getDateTime();
    3556             :             }
    3557             :             rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
    3558             :             rCal.setDateTime( fOrgDateTime );
    3559             :             return true;
    3560             :         }
    3561             :     }
    3562             :     return false;
    3563             : }
    3564             : #endif
    3565             : 
    3566             : // static
    3567           0 : void SvNumberformat::ImpAppendEraG( OUStringBuffer& OutString,
    3568             :                                     const CalendarWrapper& rCal,
    3569             :                                     sal_Int16 nNatNum )
    3570             : {
    3571             :     using namespace ::com::sun::star::i18n;
    3572           0 :     if ( rCal.getUniqueID() == "gengou" )
    3573             :     {
    3574             :         sal_Unicode cEra;
    3575           0 :         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
    3576           0 :         switch ( nVal )
    3577             :         {
    3578             :         case 1:
    3579           0 :             cEra = 'M';
    3580           0 :             break;
    3581             :         case 2:
    3582           0 :             cEra = 'T';
    3583           0 :             break;
    3584             :         case 3:
    3585           0 :             cEra = 'S';
    3586           0 :             break;
    3587             :         case 4:
    3588           0 :             cEra = 'H';
    3589           0 :             break;
    3590             :         default:
    3591           0 :             cEra = '?';
    3592           0 :             break;
    3593             :         }
    3594           0 :         OutString.append(cEra);
    3595             :     }
    3596             :     else
    3597             :     {
    3598           0 :         OutString.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
    3599             :     }
    3600           0 : }
    3601             : 
    3602          20 : bool SvNumberformat::ImpIsIso8601( const ImpSvNumFor& rNumFor )
    3603             : {
    3604          20 :     bool bIsIso = false;
    3605          20 :     if ((eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE)
    3606             :     {
    3607             :         enum State
    3608             :         {
    3609             :             eNone,
    3610             :             eAtYear,
    3611             :             eAtSep1,
    3612             :             eAtMonth,
    3613             :             eAtSep2,
    3614             :             eNotIso
    3615             :         };
    3616          20 :         State eState = eNone;
    3617          20 :         short const * const pType = rNumFor.Info().nTypeArray;
    3618          20 :         sal_uInt16 nAnz = rNumFor.GetCount();
    3619          40 :         for (sal_uInt16 i=0; i < nAnz && !bIsIso && eState != eNotIso; ++i)
    3620             :         {
    3621          20 :             switch ( pType[i] )
    3622             :             {
    3623             :             case NF_KEY_YY:     // two digits not strictly ISO 8601
    3624             :             case NF_KEY_YYYY:
    3625           0 :                 if (eState != eNone)
    3626             :                 {
    3627           0 :                     eState = eNotIso;
    3628             :                 }
    3629             :                 else
    3630             :                 {
    3631           0 :                     eState = eAtYear;
    3632             :                 }
    3633           0 :                 break;
    3634             :             case NF_KEY_M:      // single digit not strictly ISO 8601
    3635             :             case NF_KEY_MM:
    3636          20 :                 if (eState != eAtSep1)
    3637             :                 {
    3638          20 :                     eState = eNotIso;
    3639             :                 }
    3640             :                 else
    3641             :                 {
    3642           0 :                     eState = eAtMonth;
    3643             :                 }
    3644          20 :                 break;
    3645             :             case NF_KEY_D:      // single digit not strictly ISO 8601
    3646             :             case NF_KEY_DD:
    3647           0 :                 if (eState != eAtSep2)
    3648             :                 {
    3649           0 :                     eState = eNotIso;
    3650             :                 }
    3651             :                 else
    3652             :                 {
    3653           0 :                     bIsIso = true;
    3654             :                 }
    3655           0 :                 break;
    3656             :             case NF_SYMBOLTYPE_STRING:
    3657             :             case NF_SYMBOLTYPE_DATESEP:
    3658           0 :                 if (comphelper::string::equals(rNumFor.Info().sStrArray[i], '-'))
    3659             :                 {
    3660           0 :                     if (eState == eAtYear)
    3661             :                     {
    3662           0 :                         eState = eAtSep1;
    3663             :                     }
    3664           0 :                     else if (eState == eAtMonth)
    3665             :                     {
    3666           0 :                         eState = eAtSep2;
    3667             :                     }
    3668             :                     else
    3669             :                     {
    3670           0 :                         eState = eNotIso;
    3671             :                     }
    3672             :                 }
    3673             :                 else
    3674             :                 {
    3675           0 :                     eState = eNotIso;
    3676             :                 }
    3677           0 :                 break;
    3678             :             default:
    3679           0 :                 eState = eNotIso;
    3680             :             }
    3681             :         }
    3682             :     }
    3683             :     else
    3684             :     {
    3685             :        SAL_WARN( "svl.numbers", "SvNumberformat::ImpIsIso8601: no date" );
    3686             :     }
    3687          20 :     return bIsIso;
    3688             : }
    3689             : 
    3690        2216 : bool SvNumberformat::ImpGetDateOutput(double fNumber,
    3691             :                                       sal_uInt16 nIx,
    3692             :                                       OUStringBuffer& sBuff)
    3693             : {
    3694             :     using namespace ::com::sun::star::i18n;
    3695        2216 :     bool bRes = false;
    3696             : 
    3697        2216 :     CalendarWrapper& rCal = GetCal();
    3698        2216 :     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
    3699        2216 :     fNumber += fDiff;
    3700        2216 :     rCal.setLocalDateTime( fNumber );
    3701        2216 :     int nUseMonthCase = 0; // Not decided yet
    3702        2216 :     OUString aOrgCalendar; // empty => not changed yet
    3703             : 
    3704        2216 :     double fOrgDateTime(0.0);
    3705        2216 :     bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
    3706        2216 :     if ( bOtherCalendar )
    3707             :     {
    3708           4 :         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3709             :     }
    3710        2216 :     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
    3711             :     {
    3712           0 :         bOtherCalendar = false;
    3713             :     }
    3714        2216 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    3715        2216 :     const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    3716        2216 :     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
    3717        4432 :     OUString aYear;
    3718             : 
    3719       10368 :     for (sal_uInt16 i = 0; i < nAnz; i++)
    3720             :     {
    3721        8152 :         switch (rInfo.nTypeArray[i])
    3722             :         {
    3723             :         case NF_SYMBOLTYPE_CALENDAR :
    3724           8 :             if ( !aOrgCalendar.getLength() )
    3725             :             {
    3726           8 :                 aOrgCalendar = rCal.getUniqueID();
    3727           8 :                 fOrgDateTime = rCal.getDateTime();
    3728             :             }
    3729           8 :             rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() );
    3730           8 :             rCal.setDateTime( fOrgDateTime );
    3731           8 :             ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    3732           8 :             break;
    3733             :         case NF_SYMBOLTYPE_STAR:
    3734           0 :             if( bStarFlag )
    3735             :             {
    3736           0 :                 bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
    3737             :             }
    3738           0 :             break;
    3739             :         case NF_SYMBOLTYPE_BLANK:
    3740           0 :             InsertBlanks( sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] );
    3741           0 :             break;
    3742             :         case NF_SYMBOLTYPE_STRING:
    3743             :         case NF_SYMBOLTYPE_CURRENCY:
    3744             :         case NF_SYMBOLTYPE_DATESEP:
    3745             :         case NF_SYMBOLTYPE_TIMESEP:
    3746             :         case NF_SYMBOLTYPE_TIME100SECSEP:
    3747        2956 :             sBuff.append(rInfo.sStrArray[i]);
    3748        2956 :             break;
    3749             :         case NF_KEY_M:                  // M
    3750          96 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_MONTH, nNatNum ));
    3751          96 :             break;
    3752             :         case NF_KEY_MM:                 // MM
    3753         640 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_MONTH, nNatNum ));
    3754         640 :             break;
    3755             :         case NF_KEY_MMM:                // MMM
    3756        1476 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    3757        1476 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    3758        4428 :                                                 nNatNum));
    3759        1476 :             break;
    3760             :         case NF_KEY_MMMM:               // MMMM
    3761           4 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    3762           4 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    3763          12 :                                                 nNatNum));
    3764           4 :             break;
    3765             :         case NF_KEY_MMMMM:              // MMMMM
    3766           0 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    3767           0 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    3768           0 :                                                 nNatNum));
    3769           0 :             break;
    3770             :         case NF_KEY_Q:                  // Q
    3771           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum ));
    3772           0 :             break;
    3773             :         case NF_KEY_QQ:                 // QQ
    3774           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum ));
    3775           0 :             break;
    3776             :         case NF_KEY_D:                  // D
    3777         108 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ));
    3778         108 :             break;
    3779             :         case NF_KEY_DD:                 // DD
    3780        2096 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum ));
    3781        2096 :             break;
    3782             :         case NF_KEY_DDD:                // DDD
    3783           0 :             if ( bOtherCalendar )
    3784             :             {
    3785           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    3786             :             }
    3787           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
    3788           0 :             if ( bOtherCalendar )
    3789             :             {
    3790           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3791             :             }
    3792           0 :             break;
    3793             :         case NF_KEY_DDDD:               // DDDD
    3794           0 :             if ( bOtherCalendar )
    3795             :             {
    3796           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    3797             :             }
    3798           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    3799           0 :             if ( bOtherCalendar )
    3800             :             {
    3801           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3802             :             }
    3803           0 :             break;
    3804             :         case NF_KEY_YY:                 // YY
    3805         428 :             if ( bOtherCalendar )
    3806             :             {
    3807           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    3808             :             }
    3809         428 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
    3810         428 :             if ( bOtherCalendar )
    3811             :             {
    3812           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3813             :             }
    3814         428 :             break;
    3815             :         case NF_KEY_YYYY:               // YYYY
    3816         316 :             if ( bOtherCalendar )
    3817             :             {
    3818           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    3819             :             }
    3820         316 :             aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
    3821         316 :             if (aYear.getLength() < 4)
    3822             :             {
    3823             :                 using namespace comphelper::string;
    3824             :                 // Ensure that year consists of at least 4 digits, so it
    3825             :                 // can be distinguished from 2 digits display and edited
    3826             :                 // without suddenly being hit by the 2-digit year magic.
    3827           0 :                 OUStringBuffer aBuf;
    3828           0 :                 padToLength(aBuf, 4 - aYear.getLength(), '0');
    3829           0 :                 impTransliterate(aBuf, NumFor[nIx].GetNatNum());
    3830           0 :                 aBuf.append(aYear);
    3831           0 :                 sBuff.append(aBuf);
    3832             :             }
    3833             :             else
    3834             :             {
    3835         316 :                 sBuff.append(aYear);
    3836             :             }
    3837         316 :             if ( bOtherCalendar )
    3838             :             {
    3839           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3840             :             }
    3841         316 :             break;
    3842             :         case NF_KEY_EC:                 // E
    3843           2 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
    3844           2 :             break;
    3845             :         case NF_KEY_EEC:                // EE
    3846             :         case NF_KEY_R:                  // R
    3847           2 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ));
    3848           2 :             break;
    3849             :         case NF_KEY_NN:                 // NN
    3850             :         case NF_KEY_AAA:                // AAA
    3851           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
    3852           0 :             break;
    3853             :         case NF_KEY_NNN:                // NNN
    3854             :         case NF_KEY_AAAA:               // AAAA
    3855           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    3856           0 :             break;
    3857             :         case NF_KEY_NNNN:               // NNNN
    3858           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    3859           0 :             sBuff.append(rLoc().getLongDateDayOfWeekSep());
    3860           0 :             break;
    3861             :         case NF_KEY_WW :                // WW
    3862             :             sBuff.append(ImpIntToString( nIx,
    3863           0 :                                          rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR )));
    3864           0 :             break;
    3865             :         case NF_KEY_G:                  // G
    3866           0 :             ImpAppendEraG(sBuff, rCal, nNatNum );
    3867           0 :             break;
    3868             :         case NF_KEY_GG:                 // GG
    3869           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
    3870           0 :             break;
    3871             :         case NF_KEY_GGG:                // GGG
    3872           4 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum ));
    3873           4 :             break;
    3874             :         case NF_KEY_RR:                 // RR => GGGEE
    3875           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ));
    3876           0 :             break;
    3877             :         }
    3878             :     }
    3879        2216 :     if ( aOrgCalendar.getLength() )
    3880             :     {
    3881          12 :         rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() );  // restore calendar
    3882             :     }
    3883        4432 :     return bRes;
    3884             : }
    3885             : 
    3886          26 : bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
    3887             :                                           sal_uInt16 nIx,
    3888             :                                           OUStringBuffer& sBuff)
    3889             : {
    3890             :     using namespace ::com::sun::star::i18n;
    3891          26 :     bool bRes = false;
    3892             : 
    3893          26 :     CalendarWrapper& rCal = GetCal();
    3894          26 :     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
    3895          26 :     fNumber += fDiff;
    3896             : 
    3897          26 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    3898             :     bool bInputLine;
    3899             :     sal_Int32 nCntPost;
    3900          52 :     if ( rScan.GetStandardPrec() == 300 &&
    3901          26 :          0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
    3902             :     {
    3903             :         // round at 7 decimals (+5 of 86400 == 12 significant digits)
    3904           0 :         bInputLine = true;
    3905           0 :         nCntPost = 7;
    3906             :     }
    3907             :     else
    3908             :     {
    3909          26 :         bInputLine = false;
    3910          26 :         nCntPost = rInfo.nCntPost;
    3911             :     }
    3912          26 :     double fTime = (fNumber - floor( fNumber )) * 86400.0;
    3913          26 :     fTime = ::rtl::math::round( fTime, int(nCntPost) );
    3914          26 :     if (fTime >= 86400.0)
    3915             :     {
    3916             :         // result of fNumber==x.999999999... rounded up, use correct date/time
    3917           0 :         fTime -= 86400.0;
    3918           0 :         fNumber = floor( fNumber + 0.5) + fTime;
    3919             :     }
    3920          26 :     rCal.setLocalDateTime( fNumber );
    3921             : 
    3922          26 :     int nUseMonthCase = 0; // Not decided yet
    3923          26 :     OUString aOrgCalendar; // empty => not changed yet
    3924          26 :     double fOrgDateTime(0.0);
    3925          26 :     bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
    3926          26 :     if ( bOtherCalendar )
    3927             :     {
    3928           0 :         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    3929             :     }
    3930          26 :     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
    3931             :     {
    3932           0 :         bOtherCalendar = false;
    3933             :     }
    3934          26 :     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
    3935             : 
    3936          26 :     sal_uLong nSeconds = (sal_uLong)floor( fTime );
    3937             :     OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
    3938          52 :                                                   rtl_math_StringFormat_F, int(nCntPost), '.'));
    3939          26 :     sSecStr.stripStart('0');
    3940          26 :     sSecStr.stripStart('.');
    3941          26 :     if ( bInputLine )
    3942             :     {
    3943           0 :         sSecStr.stripEnd('0');
    3944           0 :         for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
    3945             :         {
    3946           0 :             sSecStr.append('0');
    3947             :         }
    3948           0 :         impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
    3949           0 :         nCntPost = sSecStr.getLength();
    3950             :     }
    3951             :     else
    3952             :     {
    3953          26 :         impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
    3954             :     }
    3955             : 
    3956          26 :     sal_Int32 nSecPos = 0; // For figure by figure processing
    3957             :     sal_uLong nHour, nMin, nSec;
    3958          26 :     if (!rInfo.bThousand) // [] format
    3959             :     {
    3960          26 :         nHour = (nSeconds/3600) % 24;
    3961          26 :         nMin = (nSeconds%3600) / 60;
    3962          26 :         nSec = nSeconds%60;
    3963             :     }
    3964           0 :     else if (rInfo.nThousand == 3) // [ss]
    3965             :     {
    3966           0 :         nHour = 0;
    3967           0 :         nMin = 0;
    3968           0 :         nSec = nSeconds;
    3969             :     }
    3970           0 :     else if (rInfo.nThousand == 2) // [mm]:ss
    3971             :     {
    3972           0 :         nHour = 0;
    3973           0 :         nMin = nSeconds / 60;
    3974           0 :         nSec = nSeconds % 60;
    3975             :     }
    3976           0 :     else if (rInfo.nThousand == 1) // [hh]:mm:ss
    3977             :     {
    3978           0 :         nHour = nSeconds / 3600;
    3979           0 :         nMin = (nSeconds%3600) / 60;
    3980           0 :         nSec = nSeconds%60;
    3981             :     }
    3982             :     else
    3983             :     {
    3984           0 :         nHour = 0;  // TODO What should these values be?
    3985           0 :         nMin  = 0;
    3986           0 :         nSec  = 0;
    3987             :     }
    3988          26 :     sal_Unicode cAmPm = ' '; // a or p
    3989          26 :     if (rInfo.nCntExp) // AM/PM
    3990             :     {
    3991          26 :         if (nHour == 0)
    3992             :         {
    3993           0 :             nHour = 12;
    3994           0 :             cAmPm = 'a';
    3995             :         }
    3996          26 :         else if (nHour < 12)
    3997             :         {
    3998          26 :             cAmPm = 'a';
    3999             :         }
    4000             :         else
    4001             :         {
    4002           0 :             cAmPm = 'p';
    4003           0 :             if (nHour > 12)
    4004             :             {
    4005           0 :                 nHour -= 12;
    4006             :             }
    4007             :         }
    4008             :     }
    4009          26 :     const sal_uInt16 nAnz = NumFor[nIx].GetCount();
    4010             :     sal_Int32 nLen;
    4011          52 :     OUString aYear;
    4012         356 :     for (sal_uInt16 i = 0; i < nAnz; i++)
    4013             :     {
    4014         330 :         switch (rInfo.nTypeArray[i])
    4015             :         {
    4016             :         case NF_SYMBOLTYPE_CALENDAR :
    4017           0 :             if ( !aOrgCalendar.getLength() )
    4018             :             {
    4019           0 :                 aOrgCalendar = rCal.getUniqueID();
    4020           0 :                 fOrgDateTime = rCal.getDateTime();
    4021             :             }
    4022           0 :             rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() );
    4023           0 :             rCal.setDateTime( fOrgDateTime );
    4024           0 :             ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    4025           0 :             break;
    4026             :         case NF_SYMBOLTYPE_STAR:
    4027           0 :             if( bStarFlag )
    4028             :             {
    4029           0 :                 bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
    4030             :             }
    4031           0 :             break;
    4032             :         case NF_SYMBOLTYPE_BLANK:
    4033             :             InsertBlanks( sBuff, sBuff.getLength(),
    4034           0 :                           rInfo.sStrArray[i][1] );
    4035           0 :             break;
    4036             :         case NF_SYMBOLTYPE_STRING:
    4037             :         case NF_SYMBOLTYPE_CURRENCY:
    4038             :         case NF_SYMBOLTYPE_DATESEP:
    4039             :         case NF_SYMBOLTYPE_TIMESEP:
    4040             :         case NF_SYMBOLTYPE_TIME100SECSEP:
    4041         152 :             sBuff.append(rInfo.sStrArray[i]);
    4042         152 :             break;
    4043             :         case NF_SYMBOLTYPE_DIGIT:
    4044           0 :             nLen = ( bInputLine && i > 0 &&
    4045           0 :                      (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
    4046           0 :                       rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
    4047           0 :                      nCntPost : rInfo.sStrArray[i].getLength() );
    4048           0 :             for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost; j++)
    4049             :             {
    4050           0 :                 sBuff.append(sSecStr[ nSecPos ]);
    4051           0 :                 nSecPos++;
    4052             :             }
    4053           0 :             break;
    4054             :         case NF_KEY_AMPM:               // AM/PM
    4055          26 :             if (cAmPm == 'a')
    4056             :             {
    4057             :                 sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
    4058          26 :                                                   AmPmValue::AM, 0 ));
    4059             :             }
    4060             :             else
    4061             :             {
    4062             :                 sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
    4063           0 :                                                   AmPmValue::PM, 0 ));
    4064             :             }
    4065          26 :             break;
    4066             :         case NF_KEY_AP:                 // A/P
    4067           0 :             if (cAmPm == 'a')
    4068             :             {
    4069           0 :                 sBuff.append('a');
    4070             :             }
    4071             :             else
    4072             :             {
    4073           0 :                 sBuff.append('p');
    4074             :             }
    4075           0 :             break;
    4076             :         case NF_KEY_MI:                 // M
    4077           0 :             sBuff.append(ImpIntToString( nIx, nMin ));
    4078           0 :             break;
    4079             :         case NF_KEY_MMI:                // MM
    4080          26 :             sBuff.append(ImpIntToString( nIx, nMin, 2 ));
    4081          26 :             break;
    4082             :         case NF_KEY_H:                  // H
    4083          22 :             sBuff.append(ImpIntToString( nIx, nHour ));
    4084          22 :             break;
    4085             :         case NF_KEY_HH:                 // HH
    4086           4 :             sBuff.append(ImpIntToString( nIx, nHour, 2 ));
    4087           4 :             break;
    4088             :         case NF_KEY_S:                  // S
    4089           0 :             sBuff.append(ImpIntToString( nIx, nSec ));
    4090           0 :             break;
    4091             :         case NF_KEY_SS:                 // SS
    4092          22 :             sBuff.append(ImpIntToString( nIx, nSec, 2 ));
    4093          22 :             break;
    4094             :         case NF_KEY_M:                  // M
    4095             :             sBuff.append(rCal.getDisplayString(
    4096          22 :                              CalendarDisplayCode::SHORT_MONTH, nNatNum ));
    4097          22 :             break;
    4098             :         case NF_KEY_MM:                 // MM
    4099             :             sBuff.append(rCal.getDisplayString(
    4100           4 :                              CalendarDisplayCode::LONG_MONTH, nNatNum ));
    4101           4 :             break;
    4102             :         case NF_KEY_MMM:                // MMM
    4103           0 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    4104           0 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    4105           0 :                                                 nNatNum));
    4106           0 :             break;
    4107             :         case NF_KEY_MMMM:               // MMMM
    4108           0 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    4109           0 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    4110           0 :                                                 nNatNum));
    4111           0 :             break;
    4112             :         case NF_KEY_MMMMM:              // MMMMM
    4113           0 :             sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
    4114           0 :                                                                  static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
    4115           0 :                                                 nNatNum));
    4116           0 :             break;
    4117             :         case NF_KEY_Q:                  // Q
    4118           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum ));
    4119           0 :             break;
    4120             :         case NF_KEY_QQ:                 // QQ
    4121           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum ));
    4122           0 :             break;
    4123             :         case NF_KEY_D:                  // D
    4124          22 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ));
    4125          22 :             break;
    4126             :         case NF_KEY_DD:                 // DD
    4127           4 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum ));
    4128           4 :             break;
    4129             :         case NF_KEY_DDD:                // DDD
    4130           0 :             if ( bOtherCalendar )
    4131             :             {
    4132           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    4133             :             }
    4134           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
    4135           0 :             if ( bOtherCalendar )
    4136             :             {
    4137           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    4138             :             }
    4139           0 :             break;
    4140             :         case NF_KEY_DDDD:               // DDDD
    4141           0 :             if ( bOtherCalendar )
    4142             :             {
    4143           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    4144             :             }
    4145           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    4146           0 :             if ( bOtherCalendar )
    4147             :             {
    4148           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    4149             :             }
    4150           0 :             break;
    4151             :         case NF_KEY_YY:                 // YY
    4152           4 :             if ( bOtherCalendar )
    4153             :             {
    4154           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    4155             :             }
    4156           4 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
    4157           4 :             if ( bOtherCalendar )
    4158             :             {
    4159           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    4160             :             }
    4161           4 :             break;
    4162             :         case NF_KEY_YYYY:               // YYYY
    4163          22 :             if ( bOtherCalendar )
    4164             :             {
    4165           0 :                 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
    4166             :             }
    4167          22 :             aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
    4168          22 :             if (aYear.getLength() < 4)
    4169             :             {
    4170             :                 using namespace comphelper::string;
    4171             :                 // Ensure that year consists of at least 4 digits, so it
    4172             :                 // can be distinguished from 2 digits display and edited
    4173             :                 // without suddenly being hit by the 2-digit year magic.
    4174           0 :                 OUStringBuffer aBuf;
    4175           0 :                 padToLength(aBuf, 4 - aYear.getLength(), '0');
    4176           0 :                 impTransliterate(aBuf, NumFor[nIx].GetNatNum());
    4177           0 :                 aBuf.append(aYear);
    4178           0 :                 sBuff.append(aBuf);
    4179             :             }
    4180             :             else
    4181             :             {
    4182          22 :                 sBuff.append(aYear);
    4183             :             }
    4184          22 :             if ( bOtherCalendar )
    4185             :             {
    4186           0 :                 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
    4187             :             }
    4188          22 :             break;
    4189             :         case NF_KEY_EC:                 // E
    4190           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
    4191           0 :             break;
    4192             :         case NF_KEY_EEC:                // EE
    4193             :         case NF_KEY_R:                  // R
    4194           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ));
    4195           0 :             break;
    4196             :         case NF_KEY_NN:                 // NN
    4197             :         case NF_KEY_AAA:                // AAA
    4198           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
    4199           0 :             break;
    4200             :         case NF_KEY_NNN:                // NNN
    4201             :         case NF_KEY_AAAA:               // AAAA
    4202           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    4203           0 :             break;
    4204             :         case NF_KEY_NNNN:               // NNNN
    4205           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
    4206           0 :             sBuff.append(rLoc().getLongDateDayOfWeekSep());
    4207           0 :             break;
    4208             :         case NF_KEY_WW :                // WW
    4209           0 :             sBuff.append(ImpIntToString( nIx, rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR )));
    4210           0 :             break;
    4211             :         case NF_KEY_G:                  // G
    4212           0 :             ImpAppendEraG( sBuff, rCal, nNatNum );
    4213           0 :             break;
    4214             :         case NF_KEY_GG:                 // GG
    4215           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
    4216           0 :             break;
    4217             :         case NF_KEY_GGG:                // GGG
    4218           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum ));
    4219           0 :             break;
    4220             :         case NF_KEY_RR:                 // RR => GGGEE
    4221           0 :             sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ));
    4222           0 :             break;
    4223             :         }
    4224             :     }
    4225          26 :     if ( aOrgCalendar.getLength() )
    4226             :     {
    4227           0 :         rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() );  // restore calendar
    4228             :     }
    4229          52 :     return bRes;
    4230             : }
    4231             : 
    4232        6240 : bool SvNumberformat::ImpGetNumberOutput(double fNumber,
    4233             :                                         sal_uInt16 nIx,
    4234             :                                         OUStringBuffer& sStr)
    4235             : {
    4236        6240 :     bool bRes = false;
    4237             :     bool bSign;
    4238        6240 :     if (fNumber < 0.0)
    4239             :     {
    4240         362 :         if (nIx == 0) // Not in the ones at the back
    4241             :         {
    4242         362 :             bSign = true; // Formats
    4243             :         }
    4244             :         else
    4245             :         {
    4246           0 :             bSign = false;
    4247             :         }
    4248         362 :         fNumber = -fNumber;
    4249             :     }
    4250             :     else
    4251             :     {
    4252        5878 :         bSign = false;
    4253        5878 :         if ( ::rtl::math::isSignBitSet( fNumber ) )
    4254             :         {
    4255           0 :             fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
    4256             :         }
    4257             :     }
    4258        6240 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    4259        6240 :     if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
    4260             :     {
    4261        2070 :         if (fNumber < _D_MAX_D_BY_100)
    4262             :         {
    4263        2070 :             fNumber *= 100.0;
    4264             :         }
    4265             :         else
    4266             :         {
    4267           0 :             sStr = rScan.GetErrorString();
    4268           0 :             return false;
    4269             :         }
    4270             :     }
    4271             :     sal_uInt16 i, j;
    4272             :     sal_Int32 k;
    4273        6240 :     bool bInteger = false;
    4274        6240 :     if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
    4275             :     {
    4276             :         // Special formatting only if no GENERAL keyword in format code
    4277        6204 :         const sal_uInt16 nThousand = rInfo.nThousand;
    4278             :         long nPrecExp;
    4279        6204 :         for (i = 0; i < nThousand; i++)
    4280             :         {
    4281           0 :            if (fNumber > _D_MIN_M_BY_1000)
    4282             :            {
    4283           0 :                fNumber /= 1000.0;
    4284             :            }
    4285             :            else
    4286             :            {
    4287           0 :                fNumber = 0.0;
    4288             :            }
    4289             :         }
    4290        6204 :         if (fNumber > 0.0)
    4291             :         {
    4292        5424 :             nPrecExp = GetPrecExp( fNumber );
    4293             :         }
    4294             :         else
    4295             :         {
    4296         780 :             nPrecExp = 0;
    4297             :         }
    4298        6204 :         if (rInfo.nCntPost) // Decimal places
    4299             :         {
    4300        4060 :             if ((rInfo.nCntPost + nPrecExp) > 15 && nPrecExp < 15)
    4301             :             {
    4302           0 :                 sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 15-nPrecExp, '.');
    4303           0 :                 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
    4304             :                 {
    4305           0 :                     sStr.append('0');
    4306           0 :                 }
    4307             :             }
    4308             :             else
    4309             :             {
    4310        4060 :                 sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
    4311             :             }
    4312        4060 :             sStr.stripStart('0'); // Strip leading zeros
    4313             :         }
    4314        2144 :         else if (fNumber == 0.0) // Null
    4315             :         {
    4316             :             // Nothing to be done here, keep empty string sStr,
    4317             :             // ImpNumberFillWithThousands does the rest
    4318             :         }
    4319             :         else // Integer
    4320             :         {
    4321        2124 :             sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 0, '.');
    4322        2124 :             sStr.stripStart('0'); // Strip leading zeros
    4323             :         }
    4324        6204 :         sal_Int32 nPoint = sStr.indexOf('.' );
    4325        6204 :         if ( nPoint >= 0)
    4326             :         {
    4327        4060 :             const sal_Unicode* p = sStr.getStr() + nPoint;
    4328        4060 :             while ( *++p == '0' )
    4329             :                 ;
    4330        4060 :             if ( !*p )
    4331             :             {
    4332        2580 :                 bInteger = true;
    4333             :             }
    4334        4060 :             sStr.remove( nPoint, 1 ); //  Remove .
    4335             :         }
    4336       18974 :         if (bSign && (sStr.isEmpty() ||
    4337        7290 :                       comphelper::string::getTokenCount(sStr.toString(), '0') == sStr.getLength()+1))   // Only 00000
    4338             :         {
    4339           0 :             bSign = false;              // Not -0.00
    4340             :         }
    4341             :     }                                   // End of != FLAG_STANDARD_IN_FORMAT
    4342             : 
    4343             :                                         // Edit backwards:
    4344        6240 :     k = sStr.getLength();               // After last figure
    4345        6240 :     j = NumFor[nIx].GetCount()-1;       // Last symbol
    4346             :                                         // Decimal places:
    4347        6240 :     if (rInfo.nCntPost > 0)
    4348             :     {
    4349        4060 :         bool bTrailing = true;          // Trailing zeros?
    4350        4060 :         bool bFilled = false;           // Was filled?
    4351             :         short nType;
    4352       20732 :         while (j > 0 &&                 // Backwards
    4353        8336 :                (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
    4354             :         {
    4355        4276 :             switch ( nType )
    4356             :             {
    4357             :             case NF_SYMBOLTYPE_STAR:
    4358           0 :                 if( bStarFlag )
    4359             :                 {
    4360           0 :                     bRes = lcl_insertStarFillChar( sStr, k, rInfo.sStrArray[j]);
    4361             :                 }
    4362           0 :                 break;
    4363             :             case NF_SYMBOLTYPE_BLANK:
    4364           0 :                 if (rInfo.sStrArray[j].getLength() >= 2)
    4365           0 :                     /*k = */ InsertBlanks(sStr, k, rInfo.sStrArray[j][1] );
    4366           0 :                 break;
    4367             :             case NF_SYMBOLTYPE_STRING:
    4368             :             case NF_SYMBOLTYPE_CURRENCY:
    4369             :             case NF_SYMBOLTYPE_PERCENT:
    4370         160 :                 sStr.insert(k, rInfo.sStrArray[j]);
    4371         160 :                 break;
    4372             :             case NF_SYMBOLTYPE_THSEP:
    4373           0 :                 if (rInfo.nThousand == 0)
    4374             :                 {
    4375           0 :                     sStr.insert(k, rInfo.sStrArray[j]);
    4376             :                 }
    4377           0 :                 break;
    4378             :             case NF_SYMBOLTYPE_DIGIT:
    4379             :             {
    4380        4060 :                 const OUString& rStr = rInfo.sStrArray[j];
    4381        4060 :                 const sal_Unicode* p1 = rStr.getStr();
    4382        4060 :                 const sal_Unicode* p = p1 + rStr.getLength();
    4383       16440 :                 while (k && p1 < p--)
    4384             :                 {
    4385        8320 :                     const sal_Unicode c = *p;
    4386        8320 :                     k--;
    4387        8320 :                     if ( sStr[k] != '0' )
    4388             :                     {
    4389        2182 :                         bTrailing = false;
    4390             :                     }
    4391        8320 :                     if (bTrailing)
    4392             :                     {
    4393        5832 :                         if ( c == '0' )
    4394             :                         {
    4395        5820 :                             bFilled = true;
    4396             :                         }
    4397          12 :                         else if ( c == '-' )
    4398             :                         {
    4399           0 :                             if ( bInteger )
    4400             :                             {
    4401           0 :                                 sStr[ k ] = '-';
    4402             :                             }
    4403           0 :                             bFilled = true;
    4404             :                         }
    4405          12 :                         else if ( c == '?' )
    4406             :                         {
    4407           0 :                             sStr[ k ] = ' ';
    4408           0 :                             bFilled = true;
    4409             :                         }
    4410          12 :                         else if ( !bFilled ) // #
    4411             :                         {
    4412          12 :                             sStr.remove(k,1);
    4413             :                         }
    4414             :                     }
    4415             :                 } // of for
    4416        4060 :                 break;
    4417             :             } // of case digi
    4418             :             case NF_KEY_CCC: // CCC currency
    4419           0 :                 sStr.insert(k, rScan.GetCurAbbrev());
    4420           0 :                 break;
    4421             :             case NF_KEY_GENERAL: // Standard in the String
    4422             :             {
    4423           0 :                 OUStringBuffer sNum;
    4424           0 :                 ImpGetOutputStandard(fNumber, sNum);
    4425           0 :                 sNum.stripStart('-');
    4426           0 :                 sStr.insert(k, sNum.makeStringAndClear());
    4427           0 :                 break;
    4428             :             }
    4429             :             default:
    4430          56 :                 break;
    4431             :             } // of switch
    4432        4276 :             j--;
    4433             :         } // of while
    4434             :     } // of decimal places
    4435             : 
    4436             :     bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // Fill with . if needed
    4437        6240 :                                        rInfo.nCntPre);
    4438        6240 :     if ( rInfo.nCntPost > 0 )
    4439             :     {
    4440        4060 :         const OUString& rDecSep = GetFormatter().GetNumDecimalSep();
    4441        4060 :         sal_Int32 nLen = rDecSep.getLength();
    4442        4060 :         if ( sStr.getLength() > nLen && ( sStr.indexOf( rDecSep, sStr.getLength() - nLen) == sStr.getLength() - nLen) )
    4443             :         {
    4444           4 :             sStr.truncate( sStr.getLength() - nLen ); // no decimals => strip DecSep
    4445             :         }
    4446             :     }
    4447        6240 :     if (bSign)
    4448             :     {
    4449         362 :         sStr.insert(0, '-');
    4450             :     }
    4451        6240 :     impTransliterate(sStr, NumFor[nIx].GetNatNum());
    4452        6240 :     return bRes;
    4453             : }
    4454             : 
    4455        6274 : bool SvNumberformat::ImpNumberFillWithThousands( OUStringBuffer& sBuff,  // number string
    4456             :                                                  double& rNumber,       // number
    4457             :                                                  sal_Int32 k,           // position within string
    4458             :                                                  sal_uInt16 j,          // symbol index within format code
    4459             :                                                  sal_uInt16 nIx,        // subformat index
    4460             :                                                  sal_Int32 nDigCnt)     // count of integer digits in format
    4461             : {
    4462        6274 :     bool bRes = false;
    4463        6274 :     sal_Int32 nLeadingStringChars = 0; // inserted StringChars before number
    4464        6274 :     sal_Int32 nDigitCount = 0;         // count of integer digits from the right
    4465        6274 :     bool bStop = false;
    4466        6274 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    4467             :     // no normal thousands separators if number divided by thousands
    4468        6274 :     bool bDoThousands = (rInfo.nThousand == 0);
    4469        6274 :     utl::DigitGroupingIterator aGrouping( GetFormatter().GetLocaleData()->getDigitGrouping());
    4470             : 
    4471       32392 :     while (!bStop) // backwards
    4472             :     {
    4473       19844 :         if (j == 0)
    4474             :         {
    4475        6274 :             bStop = true;
    4476             :         }
    4477       19844 :         switch (rInfo.nTypeArray[j])
    4478             :         {
    4479             :         case NF_SYMBOLTYPE_DECSEP:
    4480        4076 :             aGrouping.reset();
    4481             :             // fall thru
    4482             :         case NF_SYMBOLTYPE_STRING:
    4483             :         case NF_SYMBOLTYPE_CURRENCY:
    4484             :         case NF_SYMBOLTYPE_PERCENT:
    4485        6430 :             sBuff.insert(k, rInfo.sStrArray[j]);
    4486        6430 :             if ( k == 0 )
    4487             :             {
    4488        1380 :                 nLeadingStringChars = nLeadingStringChars + rInfo.sStrArray[j].getLength();
    4489             :             }
    4490        6430 :             break;
    4491             :         case NF_SYMBOLTYPE_STAR:
    4492          26 :             if( bStarFlag )
    4493             :             {
    4494           0 :                 bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]);
    4495             :             }
    4496          26 :             break;
    4497             :         case NF_SYMBOLTYPE_BLANK:
    4498          52 :             if (rInfo.sStrArray[j].getLength() >= 2)
    4499          52 :                 /*k = */ InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] );
    4500          52 :             break;
    4501             :         case NF_SYMBOLTYPE_THSEP:
    4502             :             // #i7284# #102685# Insert separator also if number is divided
    4503             :             // by thousands and the separator is specified somewhere in
    4504             :             // between and not only at the end.
    4505             :             // #i12596# But do not insert if it's a parenthesized negative
    4506             :             // format like (#,)
    4507             :             // In fact, do not insert if divided and regex [0#,],[^0#] and
    4508             :             // no other digit symbol follows (which was already detected
    4509             :             // during scan of format code, otherwise there would be no
    4510             :             // division), else do insert. Same in ImpNumberFill() below.
    4511        3205 :             if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 )
    4512             :             {
    4513           0 :                 bDoThousands = ((j == 0) ||
    4514           0 :                                 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
    4515           0 :                                  rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
    4516           0 :                                 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
    4517             :             }
    4518        3205 :             if ( bDoThousands )
    4519             :             {
    4520        3205 :                 if (k > 0)
    4521             :                 {
    4522         502 :                     sBuff.insert(k, rInfo.sStrArray[j]);
    4523             :                 }
    4524        2703 :                 else if (nDigitCount < nDigCnt)
    4525             :                 {
    4526             :                     // Leading '#' displays nothing (e.g. no leading
    4527             :                     // separator for numbers <1000 with #,##0 format).
    4528             :                     // Leading '?' displays blank.
    4529             :                     // Everything else, including nothing, displays the
    4530             :                     // separator.
    4531        2703 :                     sal_Unicode cLeader = 0;
    4532        2703 :                     if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
    4533             :                     {
    4534        2703 :                         const OUString& rStr = rInfo.sStrArray[j-1];
    4535        2703 :                         sal_Int32 nLen = rStr.getLength();
    4536        2703 :                         if (nLen)
    4537             :                         {
    4538        2703 :                             cLeader = rStr[ nLen - 1 ];
    4539             :                         }
    4540             :                     }
    4541        2703 :                     switch (cLeader)
    4542             :                     {
    4543             :                     case '#':
    4544             :                         ;   // nothing
    4545        2703 :                         break;
    4546             :                     case '?':
    4547             :                         // erAck: 2008-04-03T16:24+0200
    4548             :                         // Actually this currently isn't executed
    4549             :                         // because the format scanner in the context of
    4550             :                         // "?," doesn't generate a group separator but
    4551             :                         // a literal ',' character instead that is
    4552             :                         // inserted unconditionally. Should be changed
    4553             :                         // on some occasion.
    4554           0 :                         sBuff.insert(k, ' ');
    4555           0 :                         break;
    4556             :                     default:
    4557           0 :                         sBuff.insert(k, rInfo.sStrArray[j]);
    4558             :                     }
    4559             :                 }
    4560        3205 :                 aGrouping.advance();
    4561             :             }
    4562        3205 :             break;
    4563             :         case NF_SYMBOLTYPE_DIGIT:
    4564             :         {
    4565        9459 :             const OUString& rStr = rInfo.sStrArray[j];
    4566        9459 :             const sal_Unicode* p1 = rStr.getStr();
    4567        9459 :             const sal_Unicode* p = p1 + rStr.getLength();
    4568       34855 :             while ( p1 < p-- )
    4569             :             {
    4570       15937 :                 nDigitCount++;
    4571       15937 :                 if (k > 0)
    4572             :                 {
    4573        8555 :                     k--;
    4574             :                 }
    4575             :                 else
    4576             :                 {
    4577        7382 :                     switch (*p)
    4578             :                     {
    4579             :                     case '0':
    4580        1058 :                         sBuff.insert(0, '0');
    4581        1058 :                         break;
    4582             :                     case '?':
    4583           0 :                         sBuff.insert(0, ' ');
    4584           0 :                         break;
    4585             :                     }
    4586             :                 }
    4587       15937 :                 if (nDigitCount == nDigCnt && k > 0)
    4588             :                 {
    4589             :                     // more digits than specified
    4590        2707 :                     ImpDigitFill(sBuff, 0, k, nIx, nDigitCount, aGrouping);
    4591             :                 }
    4592             :             }
    4593        9459 :             break;
    4594             :         }
    4595             :         case NF_KEY_CCC: // CCC currency
    4596           0 :             sBuff.insert(k, rScan.GetCurAbbrev());
    4597           0 :             break;
    4598             :         case NF_KEY_GENERAL: // "General" in string
    4599             :         {
    4600          36 :             OUStringBuffer sNum;
    4601          36 :             ImpGetOutputStandard(rNumber, sNum);
    4602          36 :             sNum.stripStart('-');
    4603          36 :             sBuff.insert(k, sNum.makeStringAndClear());
    4604          36 :             break;
    4605             :         }
    4606             :         default:
    4607         636 :             break;
    4608             :         } // switch
    4609       19844 :         j--; // next format code string
    4610             :     } // while
    4611             : 
    4612        6274 :     k = k + nLeadingStringChars;    // MSC converts += to int and then warns, so ...
    4613        6274 :     if (k > nLeadingStringChars)
    4614             :     {
    4615           0 :         ImpDigitFill(sBuff, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
    4616             :     }
    4617        6274 :     return bRes;
    4618             : }
    4619             : 
    4620        2707 : void SvNumberformat::ImpDigitFill(OUStringBuffer& sStr,     // number string
    4621             :                                   sal_Int32 nStart,         // start of digits
    4622             :                                   sal_Int32 & k,            // position within string
    4623             :                                   sal_uInt16 nIx,           // subformat index
    4624             :                                   sal_Int32 & nDigitCount,  // count of integer digits from the right so far
    4625             :                                   utl::DigitGroupingIterator & rGrouping )  // current grouping
    4626             : {
    4627        2707 :     if (NumFor[nIx].Info().bThousand) // Only if grouping fill in separators
    4628             :     {
    4629         104 :         const OUString& rThousandSep = GetFormatter().GetNumThousandSep();
    4630         354 :         while (k > nStart)
    4631             :         {
    4632         146 :             if (nDigitCount == rGrouping.getPos())
    4633             :             {
    4634          10 :                 sStr.insert( k, rThousandSep );
    4635          10 :                 rGrouping.advance();
    4636             :             }
    4637         146 :             nDigitCount++;
    4638         146 :             k--;
    4639             :         }
    4640             :     }
    4641             :     else // simply skip
    4642             :     {
    4643        2603 :         k = nStart;
    4644             :     }
    4645        2707 : }
    4646             : 
    4647          50 : bool SvNumberformat::ImpNumberFill( OUStringBuffer& sBuff, // number string
    4648             :                                     double& rNumber,       // number for "General" format
    4649             :                                     sal_Int32& k,          // position within string
    4650             :                                     sal_uInt16& j,         // symbol index within format code
    4651             :                                     sal_uInt16 nIx,        // subformat index
    4652             :                                     short eSymbolType )    // type of stop condition
    4653             : {
    4654          50 :     bool bRes = false;
    4655          50 :     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
    4656             :     // no normal thousands separators if number divided by thousands
    4657          50 :     bool bDoThousands = (rInfo.nThousand == 0);
    4658             :     short nType;
    4659             : 
    4660          50 :     k = sBuff.getLength(); // behind last digit
    4661             : 
    4662         150 :     while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) // Backwards
    4663             :     {
    4664          50 :         switch ( nType )
    4665             :         {
    4666             :         case NF_SYMBOLTYPE_STAR:
    4667           0 :             if( bStarFlag )
    4668             :             {
    4669           0 :                 bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]);
    4670             :             }
    4671           0 :             break;
    4672             :         case NF_SYMBOLTYPE_BLANK:
    4673           0 :             k = InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] );
    4674           0 :             break;
    4675             :         case NF_SYMBOLTYPE_THSEP:
    4676             :             // Same as in ImpNumberFillWithThousands() above, do not insert
    4677             :             // if divided and regex [0#,],[^0#] and no other digit symbol
    4678             :             // follows (which was already detected during scan of format
    4679             :             // code, otherwise there would be no division), else do insert.
    4680           0 :             if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 )
    4681             :             {
    4682           0 :                 bDoThousands = ((j == 0) ||
    4683           0 :                                 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
    4684           0 :                                  rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
    4685           0 :                                 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
    4686             :             }
    4687           0 :             if ( bDoThousands && k > 0 )
    4688             :             {
    4689           0 :                 sBuff.insert(k, rInfo.sStrArray[j]);
    4690             :             }
    4691           0 :             break;
    4692             :         case NF_SYMBOLTYPE_DIGIT:
    4693             :         {
    4694          50 :             const OUString& rStr = rInfo.sStrArray[j];
    4695          50 :             const sal_Unicode* p1 = rStr.getStr();
    4696          50 :             const sal_Unicode* p = p1 + rStr.getLength();
    4697         196 :             while ( p1 < p-- )
    4698             :             {
    4699          96 :                 if (k > 0)
    4700             :                 {
    4701          90 :                     k--;
    4702             :                 }
    4703             :                 else
    4704             :                 {
    4705           6 :                     switch (*p)
    4706             :                     {
    4707             :                     case '0':
    4708           0 :                         sBuff.insert(0, '0');
    4709           0 :                         break;
    4710             :                     case '?':
    4711           2 :                         sBuff.insert(0, ' ');
    4712           2 :                         break;
    4713             :                     }
    4714             :                 }
    4715             :             }
    4716             :         }
    4717          50 :         break;
    4718             :         case NF_KEY_CCC:                // CCC currency
    4719           0 :             sBuff.insert(k, rScan.GetCurAbbrev());
    4720           0 :             break;
    4721             :         case NF_KEY_GENERAL: // Standard in the String
    4722             :         {
    4723           0 :             OUStringBuffer sNum;
    4724           0 :             ImpGetOutputStandard(rNumber, sNum);
    4725           0 :             sNum.stripStart('-');
    4726           0 :             sBuff.insert(k, sNum.makeStringAndClear());
    4727             :         }
    4728           0 :         break;
    4729             :         case NF_SYMBOLTYPE_FRAC_FDIV: // Do Nothing
    4730           0 :             break;
    4731             : 
    4732             :         default:
    4733           0 :             sBuff.insert(k, rInfo.sStrArray[j]);
    4734           0 :             break;
    4735             :         } // of switch
    4736          50 :         j--; // Next String
    4737             :     } // of while
    4738          50 :     return bRes;
    4739             : }
    4740             : 
    4741         657 : void SvNumberformat::GetFormatSpecialInfo(bool& bThousand,
    4742             :                                           bool& IsRed,
    4743             :                                           sal_uInt16& nPrecision,
    4744             :                                           sal_uInt16& nAnzLeading) const
    4745             : {
    4746             :     // as before: take info from nNumFor=0 for whole format (for dialog etc.)
    4747             : 
    4748             :     short nDummyType;
    4749         657 :     GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
    4750             : 
    4751             :     // "negative in red" is only useful for the whole format
    4752             : 
    4753         657 :     const Color* pColor = NumFor[1].GetColor();
    4754        1971 :     if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
    4755         657 :         && (*pColor == rScan.GetRedColor()))
    4756             :     {
    4757           0 :         IsRed = true;
    4758             :     }
    4759             :     else
    4760             :     {
    4761         657 :         IsRed = false;
    4762             :     }
    4763         657 : }
    4764             : 
    4765        2193 : void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType,
    4766             :                     bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const
    4767             : {
    4768             :     // take info from a specified sub-format (for XML export)
    4769             : 
    4770        2193 :     if ( nNumFor > 3 )
    4771             :     {
    4772        2193 :         return; // invalid
    4773             :     }
    4774             : 
    4775        2193 :     const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
    4776        2193 :     rScannedType = rInfo.eScannedType;
    4777        2193 :     bThousand = rInfo.bThousand;
    4778        2193 :     nPrecision = rInfo.nCntPost;
    4779        2193 :     if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
    4780             :     {
    4781             :         // StandardFormat
    4782         680 :         nAnzLeading = 1;
    4783             :     }
    4784             :     else
    4785             :     {
    4786        1513 :         nAnzLeading = 0;
    4787        1513 :         bool bStop = false;
    4788        1513 :         sal_uInt16 i = 0;
    4789        1513 :         const sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
    4790        9980 :         while (!bStop && i < nAnz)
    4791             :         {
    4792        6954 :             short nType = rInfo.nTypeArray[i];
    4793        6954 :             if ( nType == NF_SYMBOLTYPE_DIGIT)
    4794             :             {
    4795        1410 :                 const sal_Unicode* p = rInfo.sStrArray[i].getStr();
    4796        4057 :                 while ( *p == '#' )
    4797             :                 {
    4798        1237 :                     p++;
    4799             :                 }
    4800        3797 :                 while ( *p++ == '0' )
    4801             :                 {
    4802         977 :                     nAnzLeading++;
    4803             :                 }
    4804             :             }
    4805        5544 :             else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
    4806             :             {
    4807         649 :                 bStop = true;
    4808             :             }
    4809        6954 :             i++;
    4810             :         }
    4811             :     }
    4812             : }
    4813             : 
    4814       46826 : const OUString* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
    4815             :             bool bString /* = false */ ) const
    4816             : {
    4817       46826 :     if ( nNumFor > 3 )
    4818             :     {
    4819           0 :         return NULL;
    4820             :     }
    4821       46826 :     sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
    4822       46826 :     if ( !nAnz )
    4823             :     {
    4824       21068 :         return NULL;
    4825             :     }
    4826       25758 :     if ( nPos == 0xFFFF )
    4827             :     {
    4828        1810 :         nPos = nAnz - 1;
    4829        1810 :         if ( bString )
    4830             :         {   // Backwards
    4831        1810 :             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
    4832        3620 :             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
    4833           0 :                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4834             :             {
    4835           0 :                 pType--;
    4836           0 :                 nPos--;
    4837             :             }
    4838        1810 :             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4839             :             {
    4840        1810 :                 return NULL;
    4841             :             }
    4842             :         }
    4843             :     }
    4844       23948 :     else if ( nPos > nAnz - 1 )
    4845             :     {
    4846        4316 :         return NULL;
    4847             :     }
    4848       19632 :     else if ( bString )
    4849             :     {
    4850             :         // vorwaerts
    4851        6806 :         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
    4852       27404 :         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
    4853        6916 :                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4854             :         {
    4855        6876 :             pType++;
    4856        6876 :             nPos++;
    4857             :         }
    4858        6846 :         if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
    4859          40 :                               (*pType != NF_SYMBOLTYPE_CURRENCY)) )
    4860             :         {
    4861        6766 :             return NULL;
    4862             :         }
    4863             :     }
    4864       12866 :     return &NumFor[nNumFor].Info().sStrArray[nPos];
    4865             : }
    4866             : 
    4867       21410 : short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos,
    4868             :                                      bool bString /* = false */ ) const
    4869             : {
    4870       21410 :     if ( nNumFor > 3 )
    4871             :     {
    4872           0 :         return 0;
    4873             :     }
    4874       21410 :     sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
    4875       21410 :     if ( !nAnz )
    4876             :     {
    4877        2442 :         return 0;
    4878             :     }
    4879       18968 :     if ( nPos == 0xFFFF )
    4880             :     {
    4881           0 :         nPos = nAnz - 1;
    4882           0 :         if ( bString )
    4883             :         {
    4884             :             // Backwards
    4885           0 :             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
    4886           0 :             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
    4887           0 :                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4888             :             {
    4889           0 :                 pType--;
    4890           0 :                 nPos--;
    4891             :             }
    4892           0 :             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4893             :             {
    4894           0 :                 return 0;
    4895             :             }
    4896             :         }
    4897             :     }
    4898       18968 :     else if ( nPos > nAnz - 1 )
    4899             :     {
    4900        2746 :         return 0;
    4901             :     }
    4902       16222 :     else if ( bString )
    4903             :     {
    4904             :         // Forwards
    4905           0 :         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
    4906           0 :         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
    4907           0 :                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4908             :         {
    4909           0 :             pType++;
    4910           0 :             nPos++;
    4911             :         }
    4912           0 :         if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
    4913             :         {
    4914           0 :             return 0;
    4915             :         }
    4916             :     }
    4917       16222 :     return NumFor[nNumFor].Info().nTypeArray[nPos];
    4918             : }
    4919             : 
    4920           0 : bool SvNumberformat::IsNegativeWithoutSign() const
    4921             : {
    4922           0 :     if ( IsSecondSubformatRealNegative() )
    4923             :     {
    4924           0 :         const OUString* pStr = GetNumForString( 1, 0, true );
    4925           0 :         if ( pStr )
    4926             :         {
    4927           0 :             return !HasStringNegativeSign( *pStr );
    4928             :         }
    4929             :     }
    4930           0 :     return false;
    4931             : }
    4932             : 
    4933        2432 : bool SvNumberformat::IsNegativeInBracket() const
    4934             : {
    4935        2432 :     sal_uInt16 nAnz = NumFor[1].GetCount();
    4936        2432 :     if (!nAnz)
    4937             :     {
    4938        2432 :         return false;
    4939             :     }
    4940           0 :     OUString *tmpStr = NumFor[1].Info().sStrArray;
    4941             :     using comphelper::string::equals;
    4942           0 :     return (equals(tmpStr[0], '(') && equals(tmpStr[nAnz-1], ')'));
    4943             : }
    4944             : 
    4945           0 : bool SvNumberformat::HasPositiveBracketPlaceholder() const
    4946             : {
    4947           0 :     sal_uInt16 nAnz = NumFor[0].GetCount();
    4948           0 :     OUString *tmpStr = NumFor[0].Info().sStrArray;
    4949           0 :     return (tmpStr[nAnz-1].equalsAscii( "_)" ));
    4950             : }
    4951             : 
    4952           0 : DateFormat SvNumberformat::GetDateOrder() const
    4953             : {
    4954           0 :     if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
    4955             :     {
    4956           0 :         short const * const pType = NumFor[0].Info().nTypeArray;
    4957           0 :         sal_uInt16 nAnz = NumFor[0].GetCount();
    4958           0 :         for ( sal_uInt16 j=0; j<nAnz; j++ )
    4959             :         {
    4960           0 :             switch ( pType[j] )
    4961             :             {
    4962             :             case NF_KEY_D :
    4963             :             case NF_KEY_DD :
    4964           0 :                 return DMY;
    4965             :             case NF_KEY_M :
    4966             :             case NF_KEY_MM :
    4967             :             case NF_KEY_MMM :
    4968             :             case NF_KEY_MMMM :
    4969             :             case NF_KEY_MMMMM :
    4970           0 :                 return MDY;
    4971             :             case NF_KEY_YY :
    4972             :             case NF_KEY_YYYY :
    4973             :             case NF_KEY_EC :
    4974             :             case NF_KEY_EEC :
    4975             :             case NF_KEY_R :
    4976             :             case NF_KEY_RR :
    4977           0 :                 return YMD;
    4978             :             }
    4979             :         }
    4980             :     }
    4981             :     else
    4982             :     {
    4983             :        SAL_WARN( "svl.numbers", "SvNumberformat::GetDateOrder: no date" );
    4984             :     }
    4985           0 :     return rLoc().getDateFormat();
    4986             : }
    4987             : 
    4988           0 : sal_uInt32 SvNumberformat::GetExactDateOrder() const
    4989             : {
    4990           0 :     sal_uInt32 nRet = 0;
    4991           0 :     if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
    4992             :     {
    4993             :         SAL_WARN( "svl.numbers", "SvNumberformat::GetExactDateOrder: no date" );
    4994           0 :         return nRet;
    4995             :     }
    4996           0 :     short const * const pType = NumFor[0].Info().nTypeArray;
    4997           0 :     sal_uInt16 nAnz = NumFor[0].GetCount();
    4998           0 :     int nShift = 0;
    4999           0 :     for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ )
    5000             :     {
    5001           0 :         switch ( pType[j] )
    5002             :         {
    5003             :         case NF_KEY_D :
    5004             :         case NF_KEY_DD :
    5005           0 :             nRet = (nRet << 8) | 'D';
    5006           0 :             ++nShift;
    5007           0 :             break;
    5008             :         case NF_KEY_M :
    5009             :         case NF_KEY_MM :
    5010             :         case NF_KEY_MMM :
    5011             :         case NF_KEY_MMMM :
    5012             :         case NF_KEY_MMMMM :
    5013           0 :             nRet = (nRet << 8) | 'M';
    5014           0 :             ++nShift;
    5015           0 :             break;
    5016             :         case NF_KEY_YY :
    5017             :         case NF_KEY_YYYY :
    5018             :         case NF_KEY_EC :
    5019             :         case NF_KEY_EEC :
    5020             :         case NF_KEY_R :
    5021             :         case NF_KEY_RR :
    5022           0 :             nRet = (nRet << 8) | 'Y';
    5023           0 :             ++nShift;
    5024           0 :             break;
    5025             :         }
    5026             :     }
    5027           0 :     return nRet;
    5028             : }
    5029             : 
    5030        2632 : void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
    5031             :                                     SvNumberformatLimitOps& rOper2, double& rVal2 ) const
    5032             : {
    5033        2632 :     rOper1 = eOp1;
    5034        2632 :     rOper2 = eOp2;
    5035        2632 :     rVal1  = fLimit1;
    5036        2632 :     rVal2  = fLimit2;
    5037        2632 : }
    5038             : 
    5039        1538 : Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const
    5040             : {
    5041        1538 :     if ( nNumFor > 3 )
    5042             :     {
    5043           0 :         return NULL;
    5044             :     }
    5045        1538 :     return NumFor[nNumFor].GetColor();
    5046             : }
    5047             : 
    5048           0 : static void lcl_SvNumberformat_AddLimitStringImpl( OUString& rStr,
    5049             :                                                    SvNumberformatLimitOps eOp,
    5050             :                                                    double fLimit, const OUString& rDecSep )
    5051             : {
    5052           0 :     if ( eOp != NUMBERFORMAT_OP_NO )
    5053             :     {
    5054           0 :         switch ( eOp )
    5055             :         {
    5056             :         case NUMBERFORMAT_OP_EQ :
    5057           0 :             rStr = "[=";
    5058           0 :             break;
    5059             :         case NUMBERFORMAT_OP_NE :
    5060           0 :             rStr = "[<>";
    5061           0 :             break;
    5062             :         case NUMBERFORMAT_OP_LT :
    5063           0 :             rStr = "[<";
    5064           0 :             break;
    5065             :         case NUMBERFORMAT_OP_LE :
    5066           0 :             rStr = "[<=";
    5067           0 :             break;
    5068             :         case NUMBERFORMAT_OP_GT :
    5069           0 :             rStr = "[>";
    5070           0 :             break;
    5071             :         case NUMBERFORMAT_OP_GE :
    5072           0 :             rStr = "[>=";
    5073           0 :             break;
    5074             :         default:
    5075             :             SAL_WARN( "svl.numbers", "unsupported number format" );
    5076           0 :             break;
    5077             :         }
    5078           0 :         rStr +=  ::rtl::math::doubleToUString( fLimit,
    5079             :                                                rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
    5080           0 :                                                rDecSep[0], true);
    5081           0 :         rStr += "]";
    5082             :     }
    5083           0 : }
    5084             : 
    5085         148 : OUString SvNumberformat::GetMappedFormatstring( const NfKeywordTable& rKeywords,
    5086             :                                                 const LocaleDataWrapper& rLocWrp,
    5087             :                                                 bool bDontQuote ) const
    5088             : {
    5089         148 :     OUStringBuffer aStr;
    5090             :     bool bDefault[4];
    5091             :     // 1 subformat matches all if no condition specified,
    5092         148 :     bDefault[0] = ( NumFor[1].GetCount() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
    5093             :     // with 2 subformats [>=0];[<0] is implied if no condition specified
    5094         154 :     bDefault[1] = ( !bDefault[0] && NumFor[2].GetCount() == 0 &&
    5095           0 :                     eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
    5096         148 :                     eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
    5097             :     // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
    5098             :     // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
    5099         160 :     bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
    5100          18 :                     eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
    5101         160 :                     eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
    5102         148 :     bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
    5103             :     // from now on bDefault[] values are used to append empty subformats at the end
    5104         148 :     bDefault[3] = false;
    5105         148 :     if ( !bDefaults )
    5106             :     {
    5107             :         // conditions specified
    5108           0 :         if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
    5109             :         {
    5110           0 :             bDefault[0] = bDefault[1] = true;                               // [];x
    5111             :         }
    5112           0 :         else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
    5113           0 :                   NumFor[2].GetCount() == 0 )
    5114             :         {
    5115           0 :             bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = true;   // [];[];;
    5116             :         }
    5117             :         // nothing to do if conditions specified for every subformat
    5118             :     }
    5119         148 :     else if ( bDefault[0] )
    5120             :     {
    5121         142 :         bDefault[0] = false; // a single unconditional subformat is never delimited
    5122             :     }
    5123             :     else
    5124             :     {
    5125           6 :         if ( bDefault[2] && NumFor[2].GetCount() == 0 && NumFor[1].GetCount() > 0 )
    5126             :         {
    5127           0 :             bDefault[3] = true; // special cases x;x;; and ;x;;
    5128             :         }
    5129          18 :         for ( int i=0; i<3 && !bDefault[i]; ++i )
    5130             :         {
    5131          12 :             bDefault[i] = true;
    5132             :         }
    5133             :     }
    5134         148 :     int nSem = 0; // needed ';' delimiters
    5135         148 :     int nSub = 0; // subformats delimited so far
    5136         740 :     for ( int n=0; n<4; n++ )
    5137             :     {
    5138         592 :         if ( n > 0 )
    5139             :         {
    5140         444 :             nSem++;
    5141             :         }
    5142         592 :         OUString aPrefix;
    5143         592 :         bool LCIDInserted = false;
    5144             : 
    5145         592 :         if ( !bDefaults )
    5146             :         {
    5147           0 :             switch ( n )
    5148             :             {
    5149             :             case 0 :
    5150             :                 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
    5151           0 :                                                        fLimit1, rLocWrp.getNumDecimalSep() );
    5152           0 :                 break;
    5153             :             case 1 :
    5154             :                 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
    5155           0 :                                                        fLimit2, rLocWrp.getNumDecimalSep() );
    5156           0 :                 break;
    5157             :             }
    5158             :         }
    5159             : 
    5160         592 :         const OUString& rColorName = NumFor[n].GetColorName();
    5161         592 :         if ( !rColorName.isEmpty() )
    5162             :         {
    5163           0 :             const NfKeywordTable & rKey = rScan.GetKeywords();
    5164           0 :             for ( int j = NF_KEY_FIRSTCOLOR; j <= NF_KEY_LASTCOLOR; j++ )
    5165             :             {
    5166           0 :                 if ( rKey[j] == rColorName )
    5167             :                 {
    5168           0 :                     aPrefix += "[";
    5169           0 :                     aPrefix += rKeywords[j];
    5170           0 :                     aPrefix += "]";
    5171           0 :                     break;  // for
    5172             :                 }
    5173             :             }
    5174             :         }
    5175             : 
    5176         592 :         const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
    5177             : 
    5178         592 :         sal_uInt16 nAnz = NumFor[n].GetCount();
    5179         592 :         if ( nSem && (nAnz || !aPrefix.isEmpty()) )
    5180             :         {
    5181          24 :             for ( ; nSem; --nSem )
    5182             :             {
    5183          12 :                 aStr.append( ';' );
    5184             :             }
    5185          30 :             for ( ; nSub <= n; ++nSub )
    5186             :             {
    5187          18 :                 bDefault[nSub] = false;
    5188             :             }
    5189             :         }
    5190             : 
    5191         592 :         if ( !aPrefix.isEmpty() )
    5192             :         {
    5193           0 :             aStr.append( aPrefix );
    5194             :         }
    5195         592 :         if ( nAnz )
    5196             :         {
    5197         160 :             const short* pType = NumFor[n].Info().nTypeArray;
    5198         160 :             const OUString* pStr = NumFor[n].Info().sStrArray;
    5199         448 :             for ( sal_uInt16 j=0; j<nAnz; j++ )
    5200             :             {
    5201         288 :                 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
    5202             :                 {
    5203         134 :                     aStr.append( rKeywords[pType[j]] );
    5204         268 :                     if( NF_KEY_NNNN == pType[j] )
    5205             :                     {
    5206           0 :                         aStr.append( rLocWrp.getLongDateDayOfWeekSep() );
    5207             :                     }
    5208             :                 }
    5209             :                 else
    5210             :                 {
    5211         154 :                     switch ( pType[j] )
    5212             :                     {
    5213             :                     case NF_SYMBOLTYPE_DECSEP :
    5214          36 :                         aStr.append( rLocWrp.getNumDecimalSep() );
    5215          36 :                         break;
    5216             :                     case NF_SYMBOLTYPE_THSEP :
    5217           0 :                         aStr.append( rLocWrp.getNumThousandSep() );
    5218           0 :                         break;
    5219             :                     case NF_SYMBOLTYPE_DATESEP :
    5220          28 :                         aStr.append( rLocWrp.getDateSep() );
    5221          28 :                         break;
    5222             :                     case NF_SYMBOLTYPE_TIMESEP :
    5223           0 :                         aStr.append( rLocWrp.getTimeSep() );
    5224           0 :                         break;
    5225             :                     case NF_SYMBOLTYPE_TIME100SECSEP :
    5226           0 :                         aStr.append( rLocWrp.getTime100SecSep() );
    5227           0 :                         break;
    5228             :                     case NF_SYMBOLTYPE_STRING :
    5229          18 :                         if( bDontQuote )
    5230             :                         {
    5231           0 :                             aStr.append( pStr[j] );
    5232             :                         }
    5233          18 :                         else if ( pStr[j].getLength() == 1 )
    5234             :                         {
    5235           0 :                             aStr.append( '\\' );
    5236           0 :                             aStr.append( pStr[j] );
    5237             :                         }
    5238             :                         else
    5239             :                         {
    5240          18 :                             aStr.append( '"' );
    5241          18 :                             aStr.append( pStr[j] );
    5242          18 :                             aStr.append( '"' );
    5243             :                         }
    5244          18 :                         break;
    5245             :                     case NF_SYMBOLTYPE_CALDEL :
    5246           0 :                         if ( pStr[j+1].equalsAscii("buddhist") )
    5247             :                         {
    5248           0 :                             aStr.insert( 0, "[$-" );
    5249           0 :                             if ( rNum.IsSet() && rNum.GetNatNum() == 1 &&
    5250           0 :                                  MsLangId::getRealLanguage( rNum.GetLang() ) ==
    5251             :                                  LANGUAGE_THAI )
    5252             :                             {
    5253           0 :                                 aStr.insert( 3, "D07041E]" ); // date in Thai digit, Buddhist era
    5254             :                             }
    5255             :                             else
    5256             :                             {
    5257           0 :                                 aStr.insert( 3, "107041E]" ); // date in Arabic digit, Buddhist era
    5258             :                             }
    5259           0 :                             j = j+2;
    5260             :                         }
    5261           0 :                         LCIDInserted = true;
    5262           0 :                         break;
    5263             :                     default:
    5264          72 :                         aStr.append( pStr[j] );
    5265             :                     }
    5266             :                 }
    5267             :             }
    5268             :         }
    5269             :         // The Thai T NatNum modifier during Xcl export.
    5270        1184 :         if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
    5271           0 :             rKeywords[NF_KEY_THAI_T].equalsAscii( "T") &&
    5272           0 :             MsLangId::getRealLanguage( rNum.GetLang()) ==
    5273         592 :             LANGUAGE_THAI && !LCIDInserted )
    5274             :         {
    5275             : 
    5276           0 :             aStr.insert( 0, "[$-D00041E]" ); // number in Thai digit
    5277             :         }
    5278         592 :     }
    5279         148 :     for ( ; nSub<4 && bDefault[nSub]; ++nSub )
    5280             :     {   // append empty subformats
    5281           0 :         aStr.append( ';' );
    5282             :     }
    5283         148 :     return aStr.makeStringAndClear();
    5284             : }
    5285             : 
    5286        2078 : OUString SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
    5287             :                                            sal_Int32 nVal, sal_uInt16 nMinDigits ) const
    5288             : {
    5289        2078 :     OUString aStr;
    5290        2078 :     if ( nMinDigits )
    5291             :     {
    5292        2078 :         if ( nMinDigits == 2 )
    5293             :         {
    5294             :             // speed up the most common case
    5295        2078 :             if ( 0 <= nVal && nVal < 10 )
    5296             :             {
    5297             :                 sal_Unicode aBuf[2];
    5298        1612 :                 aBuf[0] = '0';
    5299        1612 :                 aBuf[1] = '0' + nVal;
    5300        1612 :                 aStr = OUString(aBuf, SAL_N_ELEMENTS(aBuf));
    5301             :             }
    5302             :             else
    5303             :             {
    5304         466 :                 aStr = OUString::number( nVal );
    5305             :             }
    5306             :         }
    5307             :         else
    5308             :         {
    5309           0 :             OUString aValStr( OUString::number( nVal ) );
    5310           0 :             if ( aValStr.getLength() >= nMinDigits )
    5311             :             {
    5312           0 :                 aStr = aValStr;
    5313             :             }
    5314             :             else
    5315             :             {
    5316           0 :                 OUStringBuffer aBuf;
    5317           0 :                 for(sal_Int32 index = 0; index < nMinDigits - aValStr.getLength(); ++index)
    5318             :                 {
    5319           0 :                     aBuf.append('0');
    5320             :                 }
    5321           0 :                 aBuf.append(aValStr);
    5322           0 :                 aStr = aBuf.makeStringAndClear();
    5323           0 :             }
    5324             :         }
    5325             :     }
    5326             :     else
    5327             :     {
    5328           0 :         aStr = OUString::number( nVal );
    5329             :     }
    5330        2078 :     return impTransliterate(aStr, rNum);
    5331             : }
    5332             : 
    5333           0 : OUString SvNumberformat::impTransliterateImpl(const OUString& rStr,
    5334             :                                               const SvNumberNatNum& rNum ) const
    5335             : {
    5336           0 :     com::sun::star::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() );
    5337           0 :     return GetFormatter().GetNatNum()->getNativeNumberString( rStr,
    5338           0 :                                                               aLocale, rNum.GetNatNum() );
    5339             : }
    5340             : 
    5341           2 : void SvNumberformat::impTransliterateImpl(OUStringBuffer& rStr,
    5342             :                                           const SvNumberNatNum& rNum ) const
    5343             : {
    5344           2 :     com::sun::star::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() );
    5345             : 
    5346           4 :     OUString sTemp(rStr.makeStringAndClear());
    5347           2 :     sTemp = GetFormatter().GetNatNum()->getNativeNumberString( sTemp, aLocale, rNum.GetNatNum() );
    5348           4 :     rStr.append(sTemp);
    5349           2 : }
    5350             : 
    5351        1536 : void SvNumberformat::GetNatNumXml( com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
    5352             :                                    sal_uInt16 nNumFor ) const
    5353             : {
    5354        1536 :     if ( nNumFor <= 3 )
    5355             :     {
    5356        1536 :         const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
    5357        1536 :         if ( rNum.IsSet() )
    5358             :         {
    5359             :             com::sun::star::lang::Locale aLocale(
    5360           0 :                     LanguageTag( rNum.GetLang() ).getLocale() );
    5361           0 :             rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
    5362           0 :                     aLocale, rNum.GetNatNum() );
    5363             :         }
    5364             :         else
    5365             :         {
    5366        1536 :             rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
    5367             :         }
    5368             :     }
    5369             :     else
    5370             :     {
    5371           0 :         rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
    5372             :     }
    5373        1536 : }
    5374             : 
    5375             : // static
    5376           0 : bool SvNumberformat::HasStringNegativeSign( const OUString& rStr )
    5377             : {
    5378             :     // For Sign '-' needs to be at the start or at the end of the string (blanks ignored)
    5379           0 :     sal_Int32 nLen = rStr.getLength();
    5380           0 :     if ( !nLen )
    5381             :     {
    5382           0 :         return false;
    5383             :     }
    5384           0 :     const sal_Unicode* const pBeg = rStr.getStr();
    5385           0 :     const sal_Unicode* const pEnd = pBeg + nLen;
    5386           0 :     const sal_Unicode* p = pBeg;
    5387           0 :     do
    5388             :     {   // Start
    5389           0 :         if ( *p == '-' )
    5390             :         {
    5391           0 :             return true;
    5392             :         }
    5393             :     }
    5394           0 :     while ( *p == ' ' && ++p < pEnd );
    5395             : 
    5396           0 :     p = pEnd - 1;
    5397             : 
    5398           0 :     do
    5399             :     {   // End
    5400           0 :         if ( *p == '-' )
    5401             :         {
    5402           0 :             return true;
    5403             :         }
    5404             :     }
    5405           0 :     while ( *p == ' ' && pBeg < --p );
    5406           0 :     return false;
    5407             : }
    5408             : 
    5409             : // static
    5410      427363 : bool SvNumberformat::IsInQuote( const OUString& rStr, sal_Int32 nPos,
    5411             :                                 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
    5412             : {
    5413      427363 :     sal_Int32 nLen = rStr.getLength();
    5414      427363 :     if ( nPos >= nLen )
    5415             :     {
    5416           0 :         return false;
    5417             :     }
    5418      427363 :     const sal_Unicode* p0 = rStr.getStr();
    5419      427363 :     const sal_Unicode* p = p0;
    5420      427363 :     const sal_Unicode* p1 = p0 + nPos;
    5421      427363 :     bool bQuoted = false;
    5422     4628792 :     while ( p <= p1 )
    5423             :     {
    5424     3774066 :         if ( *p == cQuote )
    5425             :         {
    5426        1022 :             if ( p == p0 )
    5427             :             {
    5428         390 :                 bQuoted = true;
    5429             :             }
    5430         632 :             else if ( bQuoted )
    5431             :             {
    5432           8 :                 if ( *(p-1) != cEscIn )
    5433             :                 {
    5434           8 :                     bQuoted = false;
    5435             :                 }
    5436             :             }
    5437             :             else
    5438             :             {
    5439         624 :                 if ( *(p-1) != cEscOut )
    5440             :                 {
    5441         618 :                     bQuoted = true;
    5442             :                 }
    5443             :             }
    5444             :         }
    5445     3774066 :         p++;
    5446             :     }
    5447      427363 :     return bQuoted;
    5448             : }
    5449             : 
    5450             : // static
    5451      427363 : sal_Int32 SvNumberformat::GetQuoteEnd( const OUString& rStr, sal_Int32 nPos,
    5452             :                                        sal_Unicode cQuote, sal_Unicode cEscIn,
    5453             :                                        sal_Unicode cEscOut )
    5454             : {
    5455      427363 :     if ( nPos < 0 )
    5456             :     {
    5457           0 :         return -1;
    5458             :     }
    5459      427363 :     sal_Int32 nLen = rStr.getLength();
    5460      427363 :     if ( nPos >= nLen )
    5461             :     {
    5462           0 :         return -1;
    5463             :     }
    5464      427363 :     if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
    5465             :     {
    5466      426363 :         if ( rStr[ nPos ] == cQuote )
    5467             :         {
    5468           0 :             return nPos; // Closing cQuote
    5469             :         }
    5470      426363 :         return -1;
    5471             :     }
    5472        1000 :     const sal_Unicode* p0 = rStr.getStr();
    5473        1000 :     const sal_Unicode* p = p0 + nPos;
    5474        1000 :     const sal_Unicode* p1 = p0 + nLen;
    5475        3116 :     while ( p < p1 )
    5476             :     {
    5477        2116 :         if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
    5478             :         {
    5479        1000 :             return sal::static_int_cast< sal_Int32 >(p - p0);
    5480             :         }
    5481        1116 :         p++;
    5482             :     }
    5483           0 :     return nLen; // End of String
    5484             : }
    5485             : 
    5486           0 : sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const
    5487             : {
    5488           0 :     sal_uInt16 nCnt = 0;
    5489           0 :     sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
    5490           0 :     short const * const pType = NumFor[nNumFor].Info().nTypeArray;
    5491           0 :     for ( sal_uInt16 j=0; j<nAnz; ++j )
    5492             :     {
    5493           0 :         switch ( pType[j] )
    5494             :         {
    5495             :         case NF_SYMBOLTYPE_STRING:
    5496             :         case NF_SYMBOLTYPE_CURRENCY:
    5497             :         case NF_SYMBOLTYPE_DATESEP:
    5498             :         case NF_SYMBOLTYPE_TIMESEP:
    5499             :         case NF_SYMBOLTYPE_TIME100SECSEP:
    5500             :         case NF_SYMBOLTYPE_PERCENT:
    5501           0 :             ++nCnt;
    5502           0 :             break;
    5503             :         }
    5504             :     }
    5505           0 :     return nCnt;
    5506             : }
    5507             : 
    5508       80798 : const CharClass& SvNumberformat::rChrCls() const
    5509             : {
    5510       80798 :     return rScan.GetChrCls();
    5511             : }
    5512             : 
    5513          28 : const LocaleDataWrapper& SvNumberformat::rLoc() const
    5514             : {
    5515          28 :     return rScan.GetLoc();
    5516             : }
    5517             : 
    5518        7572 : CalendarWrapper& SvNumberformat::GetCal() const
    5519             : {
    5520        7572 :     return rScan.GetCal();
    5521             : }
    5522             : 
    5523      670914 : const SvNumberFormatter& SvNumberformat::GetFormatter() const
    5524             : {
    5525      670914 :     return *rScan.GetNumberformatter();
    5526             : }
    5527             : 
    5528             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10