LCOV - code coverage report
Current view: top level - svl/source/numbers - zformat.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1488 2328 63.9 %
Date: 2015-06-13 12:38:46 Functions: 71 88 80.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11