LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/svl/source/numbers - zformat.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1365 2514 54.3 %
Date: 2013-07-09 Functions: 67 97 69.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10