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

Generated by: LCOV version 1.10