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

Generated by: LCOV version 1.10