blob: 2a53c1ab7ee49ed60fa2ac204a5b2d61a4eeb055 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svl.hxx"
#include <stdio.h>
#include <ctype.h>
#include <float.h>
// #include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <tools/debug.hxx>
#include <i18npool/mslangid.hxx>
#include <rtl/math.hxx>
#include <rtl/instance.hxx>
#include <unotools/charclass.hxx>
#include <unotools/calendarwrapper.hxx>
#include <unotools/nativenumberwrapper.hxx>
#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
#include <com/sun/star/i18n/CalendarDisplayCode.hpp>
#include <com/sun/star/i18n/AmPmValue.hpp>
#define _ZFORMAT_CXX
#include <svl/zformat.hxx>
#include <zforscan.hxx>
#include "zforfind.hxx"
#include <svl/zforlist.hxx>
#include "numhead.hxx"
#include <unotools/digitgroupingiterator.hxx>
#include <svl/nfsymbol.hxx>
#include <cmath>
using namespace svt;
namespace {
struct Gregorian
: public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> {
const ::rtl::OUString operator () () {
return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
}
};
const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary...
const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value.
}
const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0
const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0
const sal_uInt16 _MAX_FRACTION_PREC = 3;
const double D_EPS = 1.0E-2;
const double _D_MAX_D_BY_100 = 1.7E306;
const double _D_MIN_M_BY_1000 = 2.3E-305;
static sal_uInt8 cCharWidths[ 128-32 ] = {
1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
};
// static
xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c )
{
if( c >= 32 )
{
sal_uInt16 n = 2; // Default fuer Zeichen > 128 (HACK!)
if( c <= 127 )
n = cCharWidths[ c - 32 ];
while( n-- )
r.Insert( ' ', nPos++ );
}
return nPos;
}
static long GetPrecExp( double fAbsVal )
{
DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" );
if ( fAbsVal < 1e-7 || fAbsVal > 1e7 )
{ // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7
return (long) floor( log10( fAbsVal ) ) + 1;
}
else
{
long nPrecExp = 1;
while( fAbsVal < 1 )
{
fAbsVal *= 10;
nPrecExp--;
}
while( fAbsVal >= 10 )
{
fAbsVal /= 10;
nPrecExp++;
}
return nPrecExp;
}
}
const sal_uInt16 nNewCurrencyVersionId = 0x434E; // "NC"
const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment
const sal_uInt16 nNewStandardFlagVersionId = 0x4653; // "SF"
/***********************Funktion SvNumberformatInfo******************************/
void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz )
{
for (sal_uInt16 i = 0; i < nAnz; i++)
{
sStrArray[i] = rNumFor.sStrArray[i];
nTypeArray[i] = rNumFor.nTypeArray[i];
}
eScannedType = rNumFor.eScannedType;
bThousand = rNumFor.bThousand;
nThousand = rNumFor.nThousand;
nCntPre = rNumFor.nCntPre;
nCntPost = rNumFor.nCntPost;
nCntExp = rNumFor.nCntExp;
}
void ImpSvNumberformatInfo::Save(SvStream& rStream, sal_uInt16 nAnz) const
{
for (sal_uInt16 i = 0; i < nAnz; i++)
{
rStream.WriteByteString( sStrArray[i], rStream.GetStreamCharSet() );
short nType = nTypeArray[i];
switch ( nType )
{ // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR
case NF_SYMBOLTYPE_CURRENCY :
rStream << short( NF_SYMBOLTYPE_STRING );
break;
case NF_SYMBOLTYPE_CURRDEL :
case NF_SYMBOLTYPE_CURREXT :
rStream << short(0); // werden ignoriert (hoffentlich..)
break;
default:
if ( nType > NF_KEY_LASTKEYWORD_SO5 )
rStream << short( NF_SYMBOLTYPE_STRING ); // all new keywords are string
else
rStream << nType;
}
}
rStream << eScannedType << bThousand << nThousand
<< nCntPre << nCntPost << nCntExp;
}
void ImpSvNumberformatInfo::Load(SvStream& rStream, sal_uInt16 nAnz)
{
for (sal_uInt16 i = 0; i < nAnz; i++)
{
SvNumberformat::LoadString( rStream, sStrArray[i] );
rStream >> nTypeArray[i];
}
rStream >> eScannedType >> bThousand >> nThousand
>> nCntPre >> nCntPost >> nCntExp;
}
//============================================================================
// static
sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, sal_Bool bDate )
{
sal_uInt8 nNatNum = 0;
eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
eLang &= 0x03FF; // 10 bit primary language
if ( bDate )
{
if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN )
nNatNum = 9;
else if ( nDBNum <= 3 )
nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3
}
else
{
switch ( nDBNum )
{
case 1:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 4; break;
case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break;
case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 1; break;
}
break;
case 2:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 5; break;
case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break;
case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 2; break;
}
break;
case 3:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 6; break;
case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break;
case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 3; break;
}
break;
case 4:
switch ( eLang )
{
case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break;
case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 9; break;
}
break;
}
}
return nNatNum;
}
// static
sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, sal_Bool bDate )
{
sal_uInt8 nDBNum = 0;
eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
eLang &= 0x03FF; // 10 bit primary language
if ( bDate )
{
if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN )
nDBNum = 4;
else if ( nNatNum <= 3 )
nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3
}
else
{
switch ( nNatNum )
{
case 1:
switch ( eLang )
{
case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break;
case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 1; break;
}
break;
case 2:
switch ( eLang )
{
case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 2; break;
}
break;
case 3:
switch ( eLang )
{
case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 3; break;
}
break;
case 4:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 1; break;
case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break;
}
break;
case 5:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 2; break;
case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break;
}
break;
case 6:
switch ( eLang )
{
case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 3; break;
}
break;
case 7:
switch ( eLang )
{
case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break;
}
break;
case 8:
break;
case 9:
switch ( eLang )
{
case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 4; break;
}
break;
case 10:
break;
case 11:
break;
}
}
return nDBNum;
}
/***********************Funktionen SvNumFor******************************/
ImpSvNumFor::ImpSvNumFor()
{
nAnzStrings = 0;
aI.nTypeArray = NULL;
aI.sStrArray = NULL;
aI.eScannedType = NUMBERFORMAT_UNDEFINED;
aI.bThousand = sal_False;
aI.nThousand = 0;
aI.nCntPre = 0;
aI.nCntPost = 0;
aI.nCntExp = 0;
pColor = NULL;
}
ImpSvNumFor::~ImpSvNumFor()
{
for (sal_uInt16 i = 0; i < nAnzStrings; i++)
aI.sStrArray[i].Erase();
delete [] aI.sStrArray;
delete [] aI.nTypeArray;
}
void ImpSvNumFor::Enlarge(sal_uInt16 nAnz)
{
if ( nAnzStrings != nAnz )
{
if ( aI.nTypeArray )
delete [] aI.nTypeArray;
if ( aI.sStrArray )
delete [] aI.sStrArray;
nAnzStrings = nAnz;
if ( nAnz )
{
aI.nTypeArray = new short[nAnz];
aI.sStrArray = new String[nAnz];
}
else
{
aI.nTypeArray = NULL;
aI.sStrArray = NULL;
}
}
}
void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
{
Enlarge( rNumFor.nAnzStrings );
aI.Copy( rNumFor.aI, nAnzStrings );
sColorName = rNumFor.sColorName;
if ( pSc )
pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents
else
pColor = rNumFor.pColor;
aNatNum = rNumFor.aNatNum;
}
void ImpSvNumFor::Save(SvStream& rStream) const
{
rStream << nAnzStrings;
aI.Save(rStream, nAnzStrings);
rStream.WriteByteString( sColorName, rStream.GetStreamCharSet() );
}
void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc,
String& rLoadedColorName )
{
sal_uInt16 nAnz;
rStream >> nAnz; //! noch nicht direkt nAnzStrings wg. Enlarge
Enlarge( nAnz );
aI.Load( rStream, nAnz );
rStream.ReadByteString( sColorName, rStream.GetStreamCharSet() );
rLoadedColorName = sColorName;
pColor = rSc.GetColor(sColorName);
}
sal_Bool ImpSvNumFor::HasNewCurrency() const
{
for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
{
if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
return sal_True;
}
return sal_False;
}
bool ImpSvNumFor::HasTextFormatCode() const
{
return aI.eScannedType == NUMBERFORMAT_TEXT;
}
sal_Bool ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol,
String& rExtension ) const
{
for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
{
if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
{
rSymbol = aI.sStrArray[j];
if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT )
rExtension = aI.sStrArray[j+1];
else
rExtension.Erase();
return sal_True;
}
}
//! kein Erase an rSymbol, rExtension
return sal_False;
}
void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
{
sal_uInt16 j;
sal_uInt16 nCnt = 0;
for ( j=0; j<nAnzStrings; j++ )
{
switch ( aI.nTypeArray[j] )
{
case NF_SYMBOLTYPE_CURRENCY :
case NF_SYMBOLTYPE_CURRDEL :
case NF_SYMBOLTYPE_CURREXT :
nCnt++;
break;
}
}
rStream << nCnt;
for ( j=0; j<nAnzStrings; j++ )
{
switch ( aI.nTypeArray[j] )
{
case NF_SYMBOLTYPE_CURRENCY :
case NF_SYMBOLTYPE_CURRDEL :
case NF_SYMBOLTYPE_CURREXT :
rStream << j << aI.nTypeArray[j];
break;
}
}
}
void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
{
sal_uInt16 nCnt;
rStream >> nCnt;
for ( sal_uInt16 j=0; j<nCnt; j++ )
{
sal_uInt16 nPos;
short nType;
rStream >> nPos >> nType;
if ( nPos < nAnzStrings )
aI.nTypeArray[nPos] = nType;
}
}
/***********************Funktionen SvNumberformat************************/
enum BracketFormatSymbolType
{
BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string
BRACKET_SYMBOLTYPE_COLOR = -2, // color
BRACKET_SYMBOLTYPE_ERROR = -3, // error
BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers
BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible.
BRACKET_SYMBOLTYPE_DBNUM3 = -6,
BRACKET_SYMBOLTYPE_DBNUM4 = -7,
BRACKET_SYMBOLTYPE_DBNUM5 = -8,
BRACKET_SYMBOLTYPE_DBNUM6 = -9,
BRACKET_SYMBOLTYPE_DBNUM7 = -10,
BRACKET_SYMBOLTYPE_DBNUM8 = -11,
BRACKET_SYMBOLTYPE_DBNUM9 = -12,
BRACKET_SYMBOLTYPE_LOCALE = -13,
BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII
BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent
BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ...
BRACKET_SYMBOLTYPE_NATNUM3 = -17,
BRACKET_SYMBOLTYPE_NATNUM4 = -18,
BRACKET_SYMBOLTYPE_NATNUM5 = -19,
BRACKET_SYMBOLTYPE_NATNUM6 = -20,
BRACKET_SYMBOLTYPE_NATNUM7 = -21,
BRACKET_SYMBOLTYPE_NATNUM8 = -22,
BRACKET_SYMBOLTYPE_NATNUM9 = -23,
BRACKET_SYMBOLTYPE_NATNUM10 = -24,
BRACKET_SYMBOLTYPE_NATNUM11 = -25,
BRACKET_SYMBOLTYPE_NATNUM12 = -26,
BRACKET_SYMBOLTYPE_NATNUM13 = -27,
BRACKET_SYMBOLTYPE_NATNUM14 = -28,
BRACKET_SYMBOLTYPE_NATNUM15 = -29,
BRACKET_SYMBOLTYPE_NATNUM16 = -30,
BRACKET_SYMBOLTYPE_NATNUM17 = -31,
BRACKET_SYMBOLTYPE_NATNUM18 = -32,
BRACKET_SYMBOLTYPE_NATNUM19 = -33
};
SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge )
:
rScan(rSc),
eLnge(eLge),
nNewStandardDefined(0),
bStarFlag( sal_False )
{
}
void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat )
{
sFormatstring = rFormat.sFormatstring;
eType = rFormat.eType;
eLnge = rFormat.eLnge;
fLimit1 = rFormat.fLimit1;
fLimit2 = rFormat.fLimit2;
eOp1 = rFormat.eOp1;
eOp2 = rFormat.eOp2;
bStandard = rFormat.bStandard;
bIsUsed = rFormat.bIsUsed;
sComment = rFormat.sComment;
nNewStandardDefined = rFormat.nNewStandardDefined;
// #121103# when copying between documents, get color pointers from own scanner
ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL;
for (sal_uInt16 i = 0; i < 4; i++)
NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
}
SvNumberformat::SvNumberformat( SvNumberformat& rFormat )
: rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag )
{
ImpCopyNumberformat( rFormat );
}
SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc )
: rScan(rSc), bStarFlag( rFormat.bStarFlag )
{
ImpCopyNumberformat( rFormat );
}
sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
{
if ( nSymbolType > 0 )
return sal_True; // conditions
switch ( nSymbolType )
{
case BRACKET_SYMBOLTYPE_COLOR :
case BRACKET_SYMBOLTYPE_DBNUM1 :
case BRACKET_SYMBOLTYPE_DBNUM2 :
case BRACKET_SYMBOLTYPE_DBNUM3 :
case BRACKET_SYMBOLTYPE_DBNUM4 :
case BRACKET_SYMBOLTYPE_DBNUM5 :
case BRACKET_SYMBOLTYPE_DBNUM6 :
case BRACKET_SYMBOLTYPE_DBNUM7 :
case BRACKET_SYMBOLTYPE_DBNUM8 :
case BRACKET_SYMBOLTYPE_DBNUM9 :
case BRACKET_SYMBOLTYPE_LOCALE :
case BRACKET_SYMBOLTYPE_NATNUM0 :
case BRACKET_SYMBOLTYPE_NATNUM1 :
case BRACKET_SYMBOLTYPE_NATNUM2 :
case BRACKET_SYMBOLTYPE_NATNUM3 :
case BRACKET_SYMBOLTYPE_NATNUM4 :
case BRACKET_SYMBOLTYPE_NATNUM5 :
case BRACKET_SYMBOLTYPE_NATNUM6 :
case BRACKET_SYMBOLTYPE_NATNUM7 :
case BRACKET_SYMBOLTYPE_NATNUM8 :
case BRACKET_SYMBOLTYPE_NATNUM9 :
case BRACKET_SYMBOLTYPE_NATNUM10 :
case BRACKET_SYMBOLTYPE_NATNUM11 :
case BRACKET_SYMBOLTYPE_NATNUM12 :
case BRACKET_SYMBOLTYPE_NATNUM13 :
case BRACKET_SYMBOLTYPE_NATNUM14 :
case BRACKET_SYMBOLTYPE_NATNUM15 :
case BRACKET_SYMBOLTYPE_NATNUM16 :
case BRACKET_SYMBOLTYPE_NATNUM17 :
case BRACKET_SYMBOLTYPE_NATNUM18 :
case BRACKET_SYMBOLTYPE_NATNUM19 :
return sal_True;
}
return sal_False;
}
SvNumberformat::SvNumberformat(String& rString,
ImpSvNumberformatScan* pSc,
ImpSvNumberInputScan* pISc,
xub_StrLen& nCheckPos,
LanguageType& eLan,
sal_Bool bStan)
:
rScan(*pSc),
nNewStandardDefined(0),
bStarFlag( sal_False )
{
// If the group (AKA thousand) separator is a Non-Breaking Space (French)
// replace all occurences by a simple space.
// The tokens will be changed to the LocaleData separator again later on.
const sal_Unicode cNBSp = 0xA0;
const String& rThSep = GetFormatter().GetNumThousandSep();
if ( rThSep.GetChar(0) == cNBSp && rThSep.Len() == 1 )
{
xub_StrLen nIndex = 0;
do
nIndex = rString.SearchAndReplace( cNBSp, ' ', nIndex );
while ( nIndex != STRING_NOTFOUND );
}
if (rScan.GetConvertMode())
{
eLnge = rScan.GetNewLnge();
eLan = eLnge; // Wechsel auch zurueckgeben
}
else
eLnge = eLan;
bStandard = bStan;
bIsUsed = sal_False;
fLimit1 = 0.0;
fLimit2 = 0.0;
eOp1 = NUMBERFORMAT_OP_NO;
eOp2 = NUMBERFORMAT_OP_NO;
eType = NUMBERFORMAT_DEFINED;
sal_Bool bCancel = sal_False;
sal_Bool bCondition = sal_False;
short eSymbolType;
xub_StrLen nPos = 0;
xub_StrLen nPosOld;
nCheckPos = 0;
String aComment;
// Split into 4 sub formats
sal_uInt16 nIndex;
for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ )
{
// Original language/country may have to be reestablished
if (rScan.GetConvertMode())
(rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge());
String sStr;
nPosOld = nPos; // Start position of substring
// first get bracketed prefixes; e.g. conditions, color
do
{
eSymbolType = ImpNextSymbol(rString, nPos, sStr);
if (eSymbolType > 0) // condition
{
if ( nIndex == 0 && !bCondition )
{
bCondition = sal_True;
eOp1 = (SvNumberformatLimitOps) eSymbolType;
}
else if ( nIndex == 1 && bCondition )
eOp2 = (SvNumberformatLimitOps) eSymbolType;
else // error
{
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
if (!bCancel)
{
double fNumber;
xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr);
if (nAnzChars > 0)
{
short F_Type = NUMBERFORMAT_UNDEFINED;
if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
( F_Type != NUMBERFORMAT_NUMBER &&
F_Type != NUMBERFORMAT_SCIENTIFIC) )
{
fNumber = 0.0;
nPos = nPos - nAnzChars;
rString.Erase(nPos, nAnzChars);
rString.Insert('0',nPos);
nPos++;
}
}
else
{
fNumber = 0.0;
rString.Insert('0',nPos++);
}
if (nIndex == 0)
fLimit1 = fNumber;
else
fLimit2 = fNumber;
if ( rString.GetChar(nPos) == ']' )
nPos++;
else
{
bCancel = sal_True; // break for
nCheckPos = nPos;
}
}
nPosOld = nPos; // position before string
}
else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
switch ( eSymbolType )
{
case BRACKET_SYMBOLTYPE_COLOR :
{
if ( NumFor[nIndex].GetColor() != NULL )
{ // error, more than one color
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
else
{
Color* pColor = pSc->GetColor( sStr);
NumFor[nIndex].SetColor( pColor, sStr);
if (pColor == NULL)
{ // error
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
}
}
break;
case BRACKET_SYMBOLTYPE_NATNUM0 :
case BRACKET_SYMBOLTYPE_NATNUM1 :
case BRACKET_SYMBOLTYPE_NATNUM2 :
case BRACKET_SYMBOLTYPE_NATNUM3 :
case BRACKET_SYMBOLTYPE_NATNUM4 :
case BRACKET_SYMBOLTYPE_NATNUM5 :
case BRACKET_SYMBOLTYPE_NATNUM6 :
case BRACKET_SYMBOLTYPE_NATNUM7 :
case BRACKET_SYMBOLTYPE_NATNUM8 :
case BRACKET_SYMBOLTYPE_NATNUM9 :
case BRACKET_SYMBOLTYPE_NATNUM10 :
case BRACKET_SYMBOLTYPE_NATNUM11 :
case BRACKET_SYMBOLTYPE_NATNUM12 :
case BRACKET_SYMBOLTYPE_NATNUM13 :
case BRACKET_SYMBOLTYPE_NATNUM14 :
case BRACKET_SYMBOLTYPE_NATNUM15 :
case BRACKET_SYMBOLTYPE_NATNUM16 :
case BRACKET_SYMBOLTYPE_NATNUM17 :
case BRACKET_SYMBOLTYPE_NATNUM18 :
case BRACKET_SYMBOLTYPE_NATNUM19 :
{
if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
else
{
sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) );
//! eSymbolType is negative
sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
sStr += String::CreateFromInt32( nNum );
NumFor[nIndex].SetNatNumNum( nNum, sal_False );
}
}
break;
case BRACKET_SYMBOLTYPE_DBNUM1 :
case BRACKET_SYMBOLTYPE_DBNUM2 :
case BRACKET_SYMBOLTYPE_DBNUM3 :
case BRACKET_SYMBOLTYPE_DBNUM4 :
case BRACKET_SYMBOLTYPE_DBNUM5 :
case BRACKET_SYMBOLTYPE_DBNUM6 :
case BRACKET_SYMBOLTYPE_DBNUM7 :
case BRACKET_SYMBOLTYPE_DBNUM8 :
case BRACKET_SYMBOLTYPE_DBNUM9 :
{
if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
else
{
sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) );
//! eSymbolType is negative
sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
sStr += static_cast< sal_Unicode >('0' + nNum);
NumFor[nIndex].SetNatNumNum( nNum, sal_True );
}
}
break;
case BRACKET_SYMBOLTYPE_LOCALE :
{
if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW )
{
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
else
{
xub_StrLen nTmp = 2;
LanguageType eLang = ImpGetLanguageType( sStr, nTmp );
if ( eLang == LANGUAGE_DONTKNOW )
{
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
else
{
sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) );
sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii();
NumFor[nIndex].SetNatNumLang( eLang );
}
}
}
break;
}
if ( !bCancel )
{
rString.Erase(nPosOld,nPos-nPosOld);
rString.Insert(sStr,nPosOld);
nPos = nPosOld + sStr.Len();
rString.Insert(']', nPos);
rString.Insert('[', nPosOld);
nPos += 2;
nPosOld = nPos; // position before string
}
}
} while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
// The remaining format code string
if ( !bCancel )
{
if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT)
{
if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO)
eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0
else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0
if (sStr.Len() == 0)
{ // empty sub format
}
else
{
xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment );
sal_uInt16 nAnz = pSc->GetAnzResStrings();
if (nAnz == 0) // error
nStrPos = 1;
if (nStrPos == 0) // ok
{
// e.g. Thai T speciality
if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
{
String aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum"));
aNat += String::CreateFromInt32( pSc->GetNatNumModifier());
aNat += ']';
sStr.Insert( aNat, 0);
NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), sal_False );
}
// #i53826# #i42727# For the Thai T speciality we need
// to freeze the locale and immunize it against
// conversions during exports, just in case we want to
// save to Xcl. This disables the feature of being able
// to convert a NatNum to another locale. You can't
// have both.
// FIXME: implement a specialized export conversion
// that works on tokens (have to tokenize all first)
// and doesn't use the format string and
// PutandConvertEntry() to LANGUAGE_ENGLISH_US in
// sc/source/filter/excel/xestyle.cxx
// XclExpNumFmtBuffer::WriteFormatRecord().
LanguageType eLanguage;
if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
((eLanguage =
MsLangId::getRealLanguage( eLan))
== LANGUAGE_THAI) &&
NumFor[nIndex].GetNatNum().GetLang() ==
LANGUAGE_DONTKNOW)
{
String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-"));
aLID += String::CreateFromInt32( sal_Int32(
eLanguage), 16 ).ToUpperAscii();
aLID += ']';
sStr.Insert( aLID, 0);
NumFor[nIndex].SetNatNumLang( eLanguage);
}
rString.Erase(nPosOld,nPos-nPosOld);
rString.Insert(sStr,nPosOld);
nPos = nPosOld + sStr.Len();
if (nPos < rString.Len())
{
rString.Insert(';',nPos);
nPos++;
}
NumFor[nIndex].Enlarge(nAnz);
pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
// type check
if (nIndex == 0)
eType = (short) NumFor[nIndex].Info().eScannedType;
else if (nIndex == 3)
{ // #77026# Everything recognized IS text
NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT;
}
else if ( (short) NumFor[nIndex].Info().eScannedType !=
eType)
eType = NUMBERFORMAT_DEFINED;
}
else
{
nCheckPos = nPosOld + nStrPos; // error in string
bCancel = sal_True; // break for
}
}
}
else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error
{
nCheckPos = nPosOld;
bCancel = sal_True;
}
else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
nCheckPos = nPosOld+1; // error, prefix in string
bCancel = sal_True; // break for
}
}
if ( bCancel && !nCheckPos )
nCheckPos = 1; // nCheckPos is used as an error condition
if ( !bCancel )
{
if ( NumFor[nIndex].GetNatNum().IsSet() &&
NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
NumFor[nIndex].SetNatNumLang( eLan );
}
if (rString.Len() == nPos)
{
if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT &&
rString.GetChar(nPos-1) == ';' )
{ // #83510# A 4th subformat explicitly specified to be empty
// hides any text. Need the type here for HasTextFormat()
NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT;
}
bCancel = sal_True;
}
if ( NumFor[nIndex].GetNatNum().IsSet() )
NumFor[nIndex].SetNatNumDate(
(NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 );
}
if ( bCondition && !nCheckPos )
{
if ( nIndex == 1 && NumFor[0].GetnAnz() == 0 &&
rString.GetChar(rString.Len()-1) != ';' )
{ // No format code => GENERAL but not if specified empty
String aAdd( pSc->GetStandardName() );
String aTmp;
if ( !pSc->ScanFormat( aAdd, aTmp ) )
{
sal_uInt16 nAnz = pSc->GetAnzResStrings();
if ( nAnz )
{
NumFor[0].Enlarge(nAnz);
pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
rString += aAdd;
}
}
}
else if ( nIndex == 1 && NumFor[nIndex].GetnAnz() == 0 &&
rString.GetChar(rString.Len()-1) != ';' &&
(NumFor[0].GetnAnz() > 1 || (NumFor[0].GetnAnz() == 1 &&
NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) )
{ // No trailing second subformat => GENERAL but not if specified empty
// and not if first subformat is GENERAL
String aAdd( pSc->GetStandardName() );
String aTmp;
if ( !pSc->ScanFormat( aAdd, aTmp ) )
{
sal_uInt16 nAnz = pSc->GetAnzResStrings();
if ( nAnz )
{
NumFor[nIndex].Enlarge(nAnz);
pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
rString += ';';
rString += aAdd;
}
}
}
else if ( nIndex == 2 && NumFor[nIndex].GetnAnz() == 0 &&
rString.GetChar(rString.Len()-1) != ';' &&
eOp2 != NUMBERFORMAT_OP_NO )
{ // No trailing third subformat => GENERAL but not if specified empty
String aAdd( pSc->GetStandardName() );
String aTmp;
if ( !pSc->ScanFormat( aAdd, aTmp ) )
{
sal_uInt16 nAnz = pSc->GetAnzResStrings();
if ( nAnz )
{
NumFor[nIndex].Enlarge(nAnz);
pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
rString += ';';
rString += aAdd;
}
}
}
}
sFormatstring = rString;
if ( aComment.Len() )
{
SetComment( aComment ); // setzt sComment und sFormatstring
rString = sFormatstring; // geaenderten sFormatstring uebernehmen
}
if (NumFor[2].GetnAnz() == 0 && // kein 3. Teilstring
eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
fLimit1 == 0.0 && fLimit2 == 0.0)
eOp1 = NUMBERFORMAT_OP_GE; // 0 zum ersten Format dazu
}
SvNumberformat::~SvNumberformat()
{
}
//---------------------------------------------------------------------------
// Next_Symbol
//---------------------------------------------------------------------------
// Zerlegt die Eingabe in Symbole fuer die weitere
// Verarbeitung (Turing-Maschine).
//---------------------------------------------------------------------------
// Ausgangs Zustand = SsStart
//---------------+-------------------+-----------------------+---------------
// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
//---------------+-------------------+-----------------------+---------------
// SsStart | ; | Pos-- | SsGetString
// | [ | Symbol += Zeichen | SsGetBracketed
// | ] | Fehler | SsStop
// | BLANK | |
// | Sonst | Symbol += Zeichen | SsGetString
//---------------+-------------------+-----------------------+---------------
// SsGetString | ; | | SsStop
// | Sonst | Symbol+=Zeichen |
//---------------+-------------------+-----------------------+---------------
// SsGetBracketed| <, > = | del [ |
// | | Symbol += Zeichen | SsGetCon
// | BLANK | |
// | h, H, m, M, s, S | Symbol += Zeichen | SsGetTime
// | sonst | del [ |
// | | Symbol += Zeichen | SsGetPrefix
//---------------+-------------------+-----------------------+---------------
// SsGetTime | ] | Symbol += Zeichen | SsGetString
// | h, H, m, M, s, S | Symbol += Zeichen, * | SsGetString
// | sonst | del [; Symbol+=Zeichen| SsGetPrefix
//---------------+-------------------+-----------------------+---------------
// SsGetPrefix | ] | | SsStop
// | sonst | Symbol += Zeichen |
//---------------+-------------------+-----------------------+---------------
// SsGetCon | >, = | Symbol+=Zeichen |
// | ] | | SsStop
// | sonst | Fehler | SsStop
//---------------+-------------------+-----------------------+---------------
// * : Sonderbedingung
enum ScanState
{
SsStop,
SsStart,
SsGetCon, // condition
SsGetString, // format string
SsGetPrefix, // color or NatNumN
SsGetTime, // [HH] for time
SsGetBracketed // any [...] not decided yet
};
// read a string until ']' and delete spaces in input
// static
xub_StrLen SvNumberformat::ImpGetNumber(String& rString,
xub_StrLen& nPos,
String& sSymbol)
{
xub_StrLen nStartPos = nPos;
sal_Unicode cToken;
xub_StrLen nLen = rString.Len();
sSymbol.Erase();
while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
{
if (cToken == ' ')
{ // delete spaces
rString.Erase(nPos,1);
nLen--;
}
else
{
nPos++;
sSymbol += cToken;
}
}
return nPos - nStartPos;
}
// static
LanguageType SvNumberformat::ImpGetLanguageType( const String& rString,
xub_StrLen& nPos )
{
sal_Int32 nNum = 0;
sal_Unicode cToken = 0;
xub_StrLen nLen = rString.Len();
while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
{
if ( '0' <= cToken && cToken <= '9' )
{
nNum *= 16;
nNum += cToken - '0';
}
else if ( 'a' <= cToken && cToken <= 'f' )
{
nNum *= 16;
nNum += cToken - 'a' + 10;
}
else if ( 'A' <= cToken && cToken <= 'F' )
{
nNum *= 16;
nNum += cToken - 'A' + 10;
}
else
return LANGUAGE_DONTKNOW;
++nPos;
}
return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum :
LANGUAGE_DONTKNOW;
}
sal_Bool IsSingleSymbol(String& rString, xub_StrLen nPos){
sal_Bool ret = sal_False;
while(nPos > 0){
if(rString.GetChar(nPos) == '*' || rString.GetChar(nPos) == '\\' || rString.GetChar(nPos) == '_'){
ret = !ret;
nPos--;
}
else
return ret;
}
return ret;
}
short SvNumberformat::ImpNextSymbol(String& rString,
xub_StrLen& nPos,
String& sSymbol)
{
short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
sal_Unicode cToken;
sal_Unicode cLetter = ' '; // Zwischenergebnis
xub_StrLen nLen = rString.Len();
ScanState eState = SsStart;
sSymbol.Erase();
const NfKeywordTable & rKeywords = rScan.GetKeywords();
while (nPos < nLen && eState != SsStop)
{
cToken = rString.GetChar(nPos);
nPos++;
switch (eState)
{
case SsStart:
{
if (cToken == '[')
{
eState = SsGetBracketed;
sSymbol += cToken;
}
else if (cToken == ';')
{
eState = SsGetString;
nPos--;
eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
}
else if (cToken == ']')
{
eState = SsStop;
eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
}
else if (cToken == ' ') // Skip Blanks
{
rString.Erase(nPos-1,1);
nPos--;
nLen--;
}
else
{
sSymbol += cToken;
eState = SsGetString;
eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
}
}
break;
case SsGetBracketed:
{
switch (cToken)
{
case '<':
case '>':
case '=':
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
cLetter = cToken;
eState = SsGetCon;
switch (cToken)
{
case '<': eSymbolType = NUMBERFORMAT_OP_LT; break;
case '>': eSymbolType = NUMBERFORMAT_OP_GT; break;
case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break;
default: break;
}
}
break;
case ' ':
{
rString.Erase(nPos-1,1);
nPos--;
nLen--;
}
break;
case '$' :
{
if ( rString.GetChar(nPos) == '-' )
{ // [$-xxx] locale
sSymbol.EraseAllChars('[');
eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
eState = SsGetPrefix;
}
else
{ // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
eState = SsGetString;
}
sSymbol += cToken;
}
break;
case '~' :
{ // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
sSymbol += cToken;
eState = SsGetString;
}
break;
default:
{
static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) );
static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) );
String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) );
String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) );
sal_Unicode cUpper = aUpperNatNum.GetChar(0);
sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32();
sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() );
if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 )
{
sSymbol.EraseAllChars('[');
sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 );
nPos += aNatNum.Len()+1;
//! SymbolType is negative
eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
eState = SsGetPrefix;
}
else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' )
{
sSymbol.EraseAllChars('[');
sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 );
nPos += aDBNum.Len()+1;
//! SymbolType is negative
eSymbolType = sal::static_int_cast< short >(
BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1'));
eState = SsGetPrefix;
}
else if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H
cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M
cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S
{
sSymbol += cToken;
eState = SsGetTime;
cLetter = cToken;
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
eState = SsGetPrefix;
}
}
break;
}
}
break;
case SsGetString:
{
if (cToken == ';' && (nPos>=2) &&!IsSingleSymbol(rString, nPos-2))
{
eState = SsStop;
}
else
sSymbol += cToken;
}
break;
case SsGetTime:
{
if (cToken == ']')
{
sSymbol += cToken;
eState = SsGetString;
eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
}
else
{
sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0);
if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H
cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M
cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S
{
if (cLetter == cToken)
{
sSymbol += cToken;
cLetter = ' ';
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eState = SsGetPrefix;
}
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
eState = SsGetPrefix;
}
}
}
break;
case SsGetCon:
{
switch (cToken)
{
case '<':
{
eState = SsStop;
eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
}
break;
case '>':
{
if (cLetter == '<')
{
sSymbol += cToken;
cLetter = ' ';
eState = SsStop;
eSymbolType = NUMBERFORMAT_OP_NE;
}
else
{
eState = SsStop;
eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
}
}
break;
case '=':
{
if (cLetter == '<')
{
sSymbol += cToken;
cLetter = ' ';
eSymbolType = NUMBERFORMAT_OP_LE;
}
else if (cLetter == '>')
{
sSymbol += cToken;
cLetter = ' ';
eSymbolType = NUMBERFORMAT_OP_GE;
}
else
{
eState = SsStop;
eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
}
}
break;
case ' ':
{
rString.Erase(nPos-1,1);
nPos--;
nLen--;
}
break;
default:
{
eState = SsStop;
nPos--;
}
break;
}
}
break;
case SsGetPrefix:
{
if (cToken == ']')
eState = SsStop;
else
sSymbol += cToken;
}
break;
default:
break;
} // of switch
} // of while
return eSymbolType;
}
NfHackConversion SvNumberformat::Load( SvStream& rStream,
ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
ImpSvNumberInputScan& rISc )
{
rHdr.StartEntry();
sal_uInt16 nOp1, nOp2;
SvNumberformat::LoadString( rStream, sFormatstring );
rStream >> eType >> fLimit1 >> fLimit2
>> nOp1 >> nOp2 >> bStandard >> bIsUsed;
NfHackConversion eHackConversion = NF_CONVERT_NONE;
sal_Bool bOldConvert = sal_False;
LanguageType eOldTmpLang = 0;
LanguageType eOldNewLang = 0;
if ( pHackConverter )
{ // werden nur hierbei gebraucht
bOldConvert = rScan.GetConvertMode();
eOldTmpLang = rScan.GetTmpLnge();
eOldNewLang = rScan.GetNewLnge();
}
String aLoadedColorName;
for (sal_uInt16 i = 0; i < 4; i++)
{
NumFor[i].Load( rStream, rScan, aLoadedColorName );
if ( pHackConverter && eHackConversion == NF_CONVERT_NONE )
{
//! HACK! ER 29.07.97 13:52
// leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/
// aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert..
// System-German FARBE nach System-xxx COLOR umsetzen und vice versa,
//! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in
//! ImpSvNumberformatScan existierten
if ( aLoadedColorName.Len() && !NumFor[i].GetColor()
&& aLoadedColorName != rScan.GetColorString() )
{
if ( rScan.GetColorString().EqualsAscii( "FARBE" ) )
{ // English -> German
eHackConversion = NF_CONVERT_ENGLISH_GERMAN;
rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US );
rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN );
}
else
{ // German -> English
eHackConversion = NF_CONVERT_GERMAN_ENGLISH;
rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN );
rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US );
}
String aColorName = NumFor[i].GetColorName();
const Color* pColor = rScan.GetColor( aColorName );
if ( !pColor && aLoadedColorName == aColorName )
eHackConversion = NF_CONVERT_NONE;
rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM );
rScan.SetConvertMode( eOldTmpLang, eOldNewLang );
rScan.SetConvertMode( bOldConvert );
}
}
}
eOp1 = (SvNumberformatLimitOps) nOp1;
eOp2 = (SvNumberformatLimitOps) nOp2;
String aComment; // wird nach dem NewCurrency-Geraffel richtig gesetzt
if ( rHdr.BytesLeft() )
{ // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
SvNumberformat::LoadString( rStream, aComment );
rStream >> nNewStandardDefined;
}
xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND;
sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic &&
(nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND );
sal_Bool bNewCurrencyLoaded = sal_False;
sal_Bool bNewCurrency = sal_False;
sal_Bool bGoOn = sal_True;
while ( rHdr.BytesLeft() && bGoOn )
{ // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
sal_uInt16 nId;
rStream >> nId;
switch ( nId )
{
case nNewCurrencyVersionId :
{
bNewCurrencyLoaded = sal_True;
rStream >> bNewCurrency;
if ( bNewCurrency )
{
for ( sal_uInt16 j=0; j<4; j++ )
{
NumFor[j].LoadNewCurrencyMap( rStream );
}
}
}
break;
case nNewStandardFlagVersionId :
rStream >> bStandard; // the real standard flag
break;
default:
DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" );
bGoOn = sal_False; // stop reading unknown stream left over of newer versions
// Would be nice to have multiple read/write headers instead
// but old versions wouldn't know it, TLOT.
}
}
rHdr.EndEntry();
if ( bNewCurrencyLoaded )
{
if ( bNewCurrency && bNewCurrencyComment )
{ // original Formatstring und Kommentar wiederherstellen
sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
aComment.Erase( 0, nNewCurrencyEnd+1 );
}
}
else if ( bNewCurrencyComment )
{ // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert
// original Formatstring und Kommentar wiederherstellen
sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
aComment.Erase( 0, nNewCurrencyEnd+1 );
// Zustaende merken
short nDefined = ( eType & NUMBERFORMAT_DEFINED );
sal_uInt16 nNewStandard = nNewStandardDefined;
// neu parsen etc.
String aStr( sFormatstring );
xub_StrLen nCheckPos = 0;
SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc,
nCheckPos, eLnge, bStandard );
DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
ImpCopyNumberformat( *pFormat );
delete pFormat;
// Zustaende wiederherstellen
eType |= nDefined;
if ( nNewStandard )
SetNewStandardDefined( nNewStandard );
}
SetComment( aComment );
if ( eHackConversion != NF_CONVERT_NONE )
{ //! und weiter mit dem HACK!
switch ( eHackConversion )
{
case NF_CONVERT_ENGLISH_GERMAN :
ConvertLanguage( *pHackConverter,
LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True );
break;
case NF_CONVERT_GERMAN_ENGLISH :
ConvertLanguage( *pHackConverter,
LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True );
break;
default:
DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
}
}
return eHackConversion;
}
void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem )
{
xub_StrLen nCheckPos;
sal_uInt32 nKey;
short nType = eType;
String aFormatString( sFormatstring );
if ( bSystem )
rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
nKey, eConvertFrom, eConvertTo );
else
rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
nKey, eConvertFrom, eConvertTo );
const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
if ( pFormat )
{
ImpCopyNumberformat( *pFormat );
// aus Formatter/Scanner uebernommene Werte zuruecksetzen
if ( bSystem )
eLnge = LANGUAGE_SYSTEM;
// pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner
for ( sal_uInt16 i = 0; i < 4; i++ )
{
String aColorName = NumFor[i].GetColorName();
Color* pColor = rScan.GetColor( aColorName );
NumFor[i].SetColor( pColor, aColorName );
}
}
}
// static
void SvNumberformat::LoadString( SvStream& rStream, String& rStr )
{
CharSet eStream = rStream.GetStreamCharSet();
ByteString aStr;
rStream.ReadByteString( aStr );
sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream );
if ( aStr.Search( cStream ) == STRING_NOTFOUND )
{ // simple conversion to unicode
rStr = UniString( aStr, eStream );
}
else
{
sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol();
register const sal_Char* p = aStr.GetBuffer();
register const sal_Char* const pEnd = p + aStr.Len();
register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() );
while ( p < pEnd )
{
if ( *p == cStream )
*pUni = cTarget;
else
*pUni = ByteString::ConvertToUnicode( *p, eStream );
p++;
pUni++;
}
*pUni = 0;
}
}
void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const
{
String aFormatstring( sFormatstring );
String aComment( sComment );
#if NF_COMMENT_IN_FORMATSTRING
// der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen
// nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung
// (z.B. im Dialog) zu ermoeglichen
SetComment( "", aFormatstring, aComment );
#endif
sal_Bool bNewCurrency = HasNewCurrency();
if ( bNewCurrency )
{ // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern
aComment.Insert( cNewCurrencyMagic, 0 );
aComment.Insert( cNewCurrencyMagic, 0 );
aComment.Insert( aFormatstring, 1 );
Build50Formatstring( aFormatstring ); // alten Formatstring generieren
}
// old SO5 versions do behave strange (no output) if standard flag is set
// on formats not prepared for it (not having the following exact types)
sal_Bool bOldStandard = bStandard;
if ( bOldStandard )
{
switch ( eType )
{
case NUMBERFORMAT_NUMBER :
case NUMBERFORMAT_DATE :
case NUMBERFORMAT_TIME :
case NUMBERFORMAT_DATETIME :
case NUMBERFORMAT_PERCENT :
case NUMBERFORMAT_SCIENTIFIC :
// ok to save
break;
default:
bOldStandard = sal_False;
}
}
rHdr.StartEntry();
rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() );
rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2
<< bOldStandard << bIsUsed;
for (sal_uInt16 i = 0; i < 4; i++)
NumFor[i].Save(rStream);
// ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
rStream.WriteByteString( aComment, rStream.GetStreamCharSet() );
rStream << nNewStandardDefined;
// ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
rStream << nNewCurrencyVersionId;
rStream << bNewCurrency;
if ( bNewCurrency )
{
for ( sal_uInt16 j=0; j<4; j++ )
{
NumFor[j].SaveNewCurrencyMap( rStream );
}
}
// the real standard flag to load with versions >638 if different
if ( bStandard != bOldStandard )
{
rStream << nNewStandardFlagVersionId;
rStream << bStandard;
}
rHdr.EndEntry();
}
sal_Bool SvNumberformat::HasNewCurrency() const
{
for ( sal_uInt16 j=0; j<4; j++ )
{
if ( NumFor[j].HasNewCurrency() )
return sal_True;
}
return sal_False;
}
bool SvNumberformat::HasTextFormatCode() const
{
for ( sal_uInt16 j=0; j<4; j++ )
{
if ( NumFor[j].HasTextFormatCode() )
return true;
}
return false;
}
sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol,
String& rExtension ) const
{
for ( sal_uInt16 j=0; j<4; j++ )
{
if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
return sal_True;
}
rSymbol.Erase();
rExtension.Erase();
return sal_False;
}
// static
String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
sal_Bool bQuoteSymbol )
{
String aTmp;
xub_StrLen nStartPos, nPos, nLen;
nLen = rStr.Len();
nStartPos = 0;
while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND )
{
xub_StrLen nEnd;
if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen )
{
aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos );
nStartPos = nEnd;
}
else
{
aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
nStartPos = nPos + 2;
xub_StrLen nDash;
nEnd = nStartPos - 1;
do
{
nDash = rStr.Search( '-', ++nEnd );
} while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen );
xub_StrLen nClose;
nEnd = nStartPos - 1;
do
{
nClose = rStr.Search( ']', ++nEnd );
} while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen );
nPos = ( nDash < nClose ? nDash : nClose );
if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' )
aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
else
{
aTmp += '"';
aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
aTmp += '"';
}
nStartPos = nClose + 1;
}
}
if ( nLen > nStartPos )
aTmp += rStr.Copy( nStartPos, nLen - nStartPos );
return aTmp;
}
void SvNumberformat::Build50Formatstring( String& rStr ) const
{
rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True );
}
void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
{
sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16
{
nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_E, nStandardPrec /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0));
}
else
ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec);
}
void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const
{
// Make sure the precision doesn't go over the maximum allowable precision.
nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
#if 0
{
// debugger test case for ANSI standard correctness
::rtl::OUString aTest;
// expect 0.00123 OK
aTest = ::rtl::math::doubleToUString( 0.001234567,
rtl_math_StringFormat_G, 3, '.', sal_True );
// expect 123 OK
aTest = ::rtl::math::doubleToUString( 123.4567,
rtl_math_StringFormat_G, 3, '.', sal_True );
// expect 123.5 OK
aTest = ::rtl::math::doubleToUString( 123.4567,
rtl_math_StringFormat_G, 4, '.', sal_True );
// expect 1e+03 (as 999.6 rounded to 3 significant digits results in
// 1000 with an exponent equal to significant digits)
// Currently (24-Jan-2003) we do fail in this case and output 1000
// instead, negligible.
aTest = ::rtl::math::doubleToUString( 999.6,
rtl_math_StringFormat_G, 3, '.', sal_True );
// expect what? result is 1.2e+004
aTest = ::rtl::math::doubleToUString( 12345.6789,
rtl_math_StringFormat_G, -3, '.', sal_True );
}
#endif
// We decided to strip trailing zeros unconditionally, since binary
// double-precision rounding error makes it impossible to determine e.g.
// whether 844.10000000000002273737 is what the user has typed, or the
// user has typed 844.1 but IEEE 754 represents it that way internally.
rOutString = ::rtl::math::doubleToUString( rNumber,
rtl_math_StringFormat_F, nPrecision /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0), true );
if (rOutString.GetChar(0) == '-' &&
rOutString.GetTokenCount('0') == rOutString.Len())
rOutString.EraseLeadingChars('-'); // nicht -0
ImpTransliterate( rOutString, NumFor[0].GetNatNum() );
}
void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
{
sal_Bool bModified = sal_False;
if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
{
if (fNumber == 0.0)
{
OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
return;
}
fNumber *= 100;
bModified = sal_True;
}
if (fNumber == 0.0)
{
OutString = '0';
return;
}
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
if ( eType & NUMBERFORMAT_PERCENT && bModified)
OutString += '%';
return;
}
short SvNumberformat::ImpCheckCondition(double& fNumber,
double& fLimit,
SvNumberformatLimitOps eOp)
{
switch(eOp)
{
case NUMBERFORMAT_OP_NO: return -1;
case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit);
case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit);
case NUMBERFORMAT_OP_LT: return (short) (fNumber < fLimit);
case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit);
case NUMBERFORMAT_OP_GT: return (short) (fNumber > fLimit);
case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit);
default: return -1;
}
}
sal_Bool SvNumberformat::GetOutputString(String& sString,
String& OutString,
Color** ppColor)
{
OutString.Erase();
sal_uInt16 nIx;
if (eType & NUMBERFORMAT_TEXT)
nIx = 0;
else if (NumFor[3].GetnAnz() > 0)
nIx = 3;
else
{
*ppColor = NULL; // no change of color
return sal_False;
}
*ppColor = NumFor[nIx].GetColor();
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
{
sal_Bool bRes = sal_False;
const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
for (sal_uInt16 i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
case NF_SYMBOLTYPE_DEL :
OutString += sString;
break;
default:
OutString += rInfo.sStrArray[i];
}
}
return bRes;
}
return sal_False;
}
/*
void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1,
sal_uLong y0, sal_uLong y1,
sal_uLong& x2,sal_uLong& y2)
{
x2 = ((y0+nPrec)/y1)*x1 - x0;
y2 = ((y0+nPrec)/y1)*y1 - y0;
}
*/
sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y)
{
if (y == 0)
return x;
else
{
sal_uLong z = x%y;
while (z)
{
x = y;
y = z;
z = x%y;
}
return y;
}
}
sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y)
{
if (y == 0)
return x;
else
{
sal_uLong z = x%y;
while ((double)z/(double)y > D_EPS)
{
x = y;
y = z;
z = x%y;
}
return y;
}
}
namespace {
void lcl_GetOutputStringScientific(
double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString)
{
bool bSign = ::rtl::math::isSignBitSet(fNumber);
// 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7).
sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0;
if (nPrec && bSign)
// Make room for the negative sign.
--nPrec;
nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
rOutString = ::rtl::math::doubleToUString(
fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0));
}
}
bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const
{
using namespace std;
if (eType != NUMBERFORMAT_NUMBER)
return false;
double fTestNum = fNumber;
bool bSign = ::rtl::math::isSignBitSet(fTestNum);
if (bSign)
fTestNum = -fTestNum;
if (fTestNum < EXP_LOWER_BOUND)
{
lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
return true;
}
double fExp = log10(fTestNum);
// Values < 1.0 always have one digit before the decimal point.
sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
if (nDigitPre > 15)
{
lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
return true;
}
sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
if (nPrec && bSign)
// Subtract the negative sign.
--nPrec;
if (nPrec)
// Subtract the decimal point.
--nPrec;
ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
if (rOutString.Len() > nCharCount)
// String still wider than desired. Switch to scientific notation.
lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
return true;
}
sal_Bool SvNumberformat::GetOutputString(double fNumber,
String& OutString,
Color** ppColor)
{
sal_Bool bRes = sal_False;
OutString.Erase(); // alles loeschen
*ppColor = NULL; // keine Farbaenderung
if (eType & NUMBERFORMAT_LOGICAL)
{
if (fNumber)
OutString = rScan.GetTrueString();
else
OutString = rScan.GetFalseString();
return sal_False;
}
if (eType & NUMBERFORMAT_TEXT)
{
ImpGetOutputStandard(fNumber, OutString);
return sal_False;
}
sal_Bool bHadStandard = sal_False;
if (bStandard) // einzelne Standardformate
{
if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine
{
ImpGetOutputInputLine(fNumber, OutString);
return false;
}
switch (eType)
{
case NUMBERFORMAT_NUMBER: // Standardzahlformat
{
if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
{
bool bSign = ::rtl::math::isSignBitSet(fNumber);
if (bSign)
fNumber = -fNumber;
ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format.
if (fNumber < EXP_LOWER_BOUND)
{
xub_StrLen nLen = OutString.Len();
if (!nLen)
return false;
// #i112250# With the 10-decimal limit, small numbers are formatted as "0".
// Switch to scientific in that case, too:
if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0))
{
sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_E, nStandardPrec /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0), true);
}
}
if (bSign)
OutString.Insert('-', 0);
return false;
}
ImpGetOutputStandard(fNumber, OutString);
bHadStandard = sal_True;
}
break;
case NUMBERFORMAT_DATE:
bRes |= ImpGetDateOutput(fNumber, 0, OutString);
bHadStandard = sal_True;
break;
case NUMBERFORMAT_TIME:
bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
bHadStandard = sal_True;
break;
case NUMBERFORMAT_DATETIME:
bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
bHadStandard = sal_True;
break;
}
}
if ( !bHadStandard )
{
sal_uInt16 nIx; // Index des Teilformats
short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
if (nCheck == -1 || nCheck == 1) // nur 1 String oder True
nIx = 0;
else
{
nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
if (nCheck == -1 || nCheck == 1)
nIx = 1;
else
nIx = 2;
}
if (nIx == 1 && // negatives Format
IsNegativeRealNegative() && fNumber < 0.0) // ohne Vorzeichen
fNumber = -fNumber; // Vorzeichen eliminieren
if(nIx == 0 &&
IsNegativeRealNegative2() && fNumber < 0.0)
fNumber = -fNumber;
*ppColor = NumFor[nIx].GetColor();
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
return sal_False; // leer => nichts
else if (nAnz == 0) // sonst Standard-Format
{
ImpGetOutputStandard(fNumber, OutString);
return sal_False;
}
switch (rInfo.eScannedType)
{
case NUMBERFORMAT_TEXT:
case NUMBERFORMAT_DEFINED:
{
for (sal_uInt16 i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
OutString += rInfo.sStrArray[i];
break;
case NF_SYMBOLTYPE_THSEP:
if (rInfo.nThousand == 0)
OutString += rInfo.sStrArray[i];
break;
default:
break;
}
}
}
break;
case NUMBERFORMAT_DATE:
bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
break;
case NUMBERFORMAT_TIME:
bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
break;
case NUMBERFORMAT_DATETIME:
bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
break;
case NUMBERFORMAT_NUMBER:
case NUMBERFORMAT_PERCENT:
case NUMBERFORMAT_CURRENCY:
bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
break;
case NUMBERFORMAT_FRACTION:
{
String sStr, sFrac, sDiv; // Strings, Wert fuer
sal_uLong nFrac, nDiv; // Vorkommaanteil
// Zaehler und Nenner
sal_Bool bSign = sal_False;
if (fNumber < 0)
{
if (nIx == 0) // nicht in hinteren
bSign = sal_True; // Formaten
fNumber = -fNumber;
}
double fNum = floor(fNumber); // Vorkommateil
fNumber -= fNum; // Nachkommateil
if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
// zu gross
{
OutString = rScan.GetErrorString();
return sal_False;
}
if (rInfo.nCntExp == 0)
{
DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
return sal_False;
}
sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,...
pow(10.0,rInfo.nCntExp))) - 1;
sal_uLong x0, y0, x1, y1;
if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
{
sal_Bool bUpperHalf;
if (fNumber > 0.5)
{
bUpperHalf = sal_True;
fNumber -= (fNumber - 0.5) * 2.0;
}
else
bUpperHalf = sal_False;
// Einstieg in Farey-Serie
// finden:
x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
if (x0 == 0) // => x0 = 2
{
y0 = 1;
x1 = 1;
y1 = nBasis;
}
else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2
{ // geht (nBasis ungerade)
y0 = nBasis;
x1 = 1;
y1 = 2;
}
else if (x0 == 1)
{
y0 = nBasis; // 1/n; 1/(n-1)
x1 = 1;
y1 = nBasis - 1;
}
else
{
y0 = nBasis; // z.B. 2/9 2/8
x1 = x0;
y1 = nBasis - 1;
double fUg = (double) x0 / (double) y0;
double fOg = (double) x1 / (double) y1;
sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
x0 /= nGgt;
y0 /= nGgt; // Einschachteln:
sal_uLong x2 = 0;
sal_uLong y2 = 0;
sal_Bool bStop = sal_False;
while (!bStop)
{
#ifdef GCC
// #i21648# GCC over-optimizes something resulting
// in wrong fTest values throughout the loops.
volatile
#endif
double fTest = (double)x1/(double)y1;
while (!bStop)
{
while (fTest > fOg)
{
x1--;
fTest = (double)x1/(double)y1;
}
while (fTest < fUg && y1 > 1)
{
y1--;
fTest = (double)x1/(double)y1;
}
if (fTest <= fOg)
{
fOg = fTest;
bStop = sal_True;
}
else if (y1 == 1)
bStop = sal_True;
} // of while
nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen
x2 = x1 / nGgt;
y2 = y1 / nGgt;
if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2
bStop = sal_True; // naechste Farey-Zahl
else
{
y1--;
bStop = sal_False;
}
} // of while
x1 = x2;
y1 = y2;
} // of else
double fup, flow;
flow = (double)x0/(double)y0;
fup = (double)x1/(double)y1;
while (fNumber > fup)
{
sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0;
// GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
x0 = x1;
y0 = y1;
x1 = x2;
y1 = y2;
flow = fup;
fup = (double)x1/(double)y1;
}
if (fNumber - flow < fup - fNumber)
{
nFrac = x0;
nDiv = y0;
}
else
{
nFrac = x1;
nDiv = y1;
}
if (bUpperHalf) // Original restaur.
{
if (nFrac == 0 && nDiv == 1) // 1/1
fNum += 1.0;
else
nFrac = nDiv - nFrac;
}
}
else // grosse Nenner
{ // 0,1234->123/1000
sal_uLong nGgt;
/*
nDiv = nBasis+1;
nFrac = ((sal_uLong)floor(0.5 + fNumber *
pow(10.0,rInfo.nCntExp)));
*/
nDiv = 10000000;
nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0));
nGgt = ImpGGT(nDiv, nFrac);
if (nGgt > 1)
{
nDiv /= nGgt;
nFrac /= nGgt;
}
if (nDiv > nBasis)
{
nGgt = ImpGGTRound(nDiv, nFrac);
if (nGgt > 1)
{
nDiv /= nGgt;
nFrac /= nGgt;
}
}
if (nDiv > nBasis)
{
nDiv = nBasis;
nFrac = ((sal_uLong)floor(0.5 + fNumber *
pow(10.0,rInfo.nCntExp)));
nGgt = ImpGGTRound(nDiv, nFrac);
if (nGgt > 1)
{
nDiv /= nGgt;
nFrac /= nGgt;
}
}
}
if (rInfo.nCntPre == 0) // unechter Bruch
{
double fNum1 = fNum * (double)nDiv + (double)nFrac;
if (fNum1 > _D_MAX_U_LONG_)
{
OutString = rScan.GetErrorString();
return sal_False;
}
nFrac = (sal_uLong) floor(fNum1);
sStr.Erase();
}
else if (fNum == 0.0 && nFrac != 0)
sStr.Erase();
else
{
char aBuf[100];
sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
sStr.AssignAscii( aBuf );
ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
}
if (rInfo.nCntPre > 0 && nFrac == 0)
{
sFrac.Erase();
sDiv.Erase();
}
else
{
sFrac = ImpIntToString( nIx, nFrac );
sDiv = ImpIntToString( nIx, nDiv );
}
sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw.
xub_StrLen k; // Nenner:
bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
sal_Bool bCont = sal_True;
if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
{
if (rInfo.nCntPre > 0 && nFrac == 0)
sDiv.Insert(' ',0);
else
sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
if ( j )
j--;
else
bCont = sal_False;
}
// weiter Zaehler:
if ( !bCont )
sFrac.Erase();
else
{
bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
{
sFrac.Insert(rInfo.sStrArray[j],0);
if ( j )
j--;
else
bCont = sal_False;
}
}
// weiter Hauptzahl
if ( !bCont )
sStr.Erase();
else
{
k = sStr.Len(); // hinter letzter Ziffer
bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
rInfo.nCntPre);
}
if (bSign && !(nFrac == 0 && fNum == 0.0))
OutString.Insert('-',0); // nicht -0
OutString += sStr;
OutString += sFrac;
OutString += sDiv;
}
break;
case NUMBERFORMAT_SCIENTIFIC:
{
sal_Bool bSign = sal_False;
if (fNumber < 0)
{
if (nIx == 0) // nicht in hinteren
bSign = sal_True; // Formaten
fNumber = -fNumber;
}
String sStr( ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_E,
rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
String ExpStr;
short nExpSign = 1;
xub_StrLen nExPos = sStr.Search('E');
if ( nExPos != STRING_NOTFOUND )
{
// split into mantisse and exponent and get rid of "E+" or "E-"
xub_StrLen nExpStart = nExPos + 1;
switch ( sStr.GetChar( nExpStart ) )
{
case '-' :
nExpSign = -1;
// fallthru
case '+' :
++nExpStart;
break;
}
ExpStr = sStr.Copy( nExpStart ); // part following the "E+"
sStr.Erase( nExPos );
sStr.EraseAllChars('.'); // cut any decimal delimiter
if ( rInfo.nCntPre != 1 ) // rescale Exp
{
sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
nExp -= sal_Int32(rInfo.nCntPre)-1;
if ( nExp < 0 )
{
nExpSign = -1;
nExp = -nExp;
}
else
nExpSign = 1;
ExpStr = String::CreateFromInt32( nExp );
}
}
sal_uInt16 j = nAnz-1; // last symbol
xub_StrLen k; // position in ExpStr
bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
xub_StrLen nZeros = 0; // erase leading zeros
while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
++nZeros;
if (nZeros)
ExpStr.Erase( 0, nZeros);
sal_Bool bCont = sal_True;
if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
{
const String& rStr = rInfo.sStrArray[j];
if (nExpSign == -1)
ExpStr.Insert('-',0);
else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
ExpStr.Insert('+',0);
ExpStr.Insert(rStr.GetChar(0),0);
if ( j )
j--;
else
bCont = sal_False;
}
// weiter Hauptzahl:
if ( !bCont )
sStr.Erase();
else
{
k = sStr.Len(); // hinter letzter Ziffer
bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
rInfo.nCntPre +
rInfo.nCntPost);
}
if (bSign)
sStr.Insert('-',0);
OutString = sStr;
OutString += ExpStr;
}
break;
}
}
return bRes;
}
sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber,
sal_uInt16 nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
sal_Bool bCalendarSet = sal_False;
double fNumberOrig = fNumber;
sal_Bool bRes = sal_False;
sal_Bool bSign = sal_False;
if (fNumber < 0.0)
{
fNumber = -fNumber;
if (nIx == 0)
bSign = sal_True;
}
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
if (rInfo.bThousand) // []-Format
{
if (fNumber > 1.0E10) // zu gross
{
OutString = rScan.GetErrorString();
return sal_False;
}
}
else
fNumber -= floor(fNumber); // sonst Datum abtrennen
sal_Bool bInputLine;
xub_StrLen nCntPost;
if ( rScan.GetStandardPrec() == 300 &&
0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
{ // round at 7 decimals (+5 of 86400 == 12 significant digits)
bInputLine = sal_True;
nCntPost = 7;
}
else
{
bInputLine = sal_False;
nCntPost = xub_StrLen(rInfo.nCntPost);
}
if (bSign && !rInfo.bThousand) // kein []-Format
fNumber = 1.0 - fNumber; // "Kehrwert"
double fTime = fNumber * 86400.0;
fTime = ::rtl::math::round( fTime, int(nCntPost) );
if (bSign && fTime == 0.0)
bSign = sal_False; // nicht -00:00:00
if( floor( fTime ) > _D_MAX_U_LONG_ )
{
OutString = rScan.GetErrorString();
return sal_False;
}
sal_uLong nSeconds = (sal_uLong)floor( fTime );
String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
rtl_math_StringFormat_F, int(nCntPost), '.'));
sSecStr.EraseLeadingChars('0');
sSecStr.EraseLeadingChars('.');
if ( bInputLine )
{
sSecStr.EraseTrailingChars('0');
if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
nCntPost = sSecStr.Len();
}
else
ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
xub_StrLen nSecPos = 0; // Zum Ziffernweisen
// abarbeiten
sal_uLong nHour, nMin, nSec;
if (!rInfo.bThousand) // kein [] Format
{
nHour = (nSeconds/3600) % 24;
nMin = (nSeconds%3600) / 60;
nSec = nSeconds%60;
}
else if (rInfo.nThousand == 3) // [ss]
{
nHour = 0;
nMin = 0;
nSec = nSeconds;
}
else if (rInfo.nThousand == 2) // [mm]:ss
{
nHour = 0;
nMin = nSeconds / 60;
nSec = nSeconds % 60;
}
else if (rInfo.nThousand == 1) // [hh]:mm:ss
{
nHour = nSeconds / 3600;
nMin = (nSeconds%3600) / 60;
nSec = nSeconds%60;
}
else {
// TODO What should these be set to?
nHour = 0;
nMin = 0;
nSec = 0;
}
sal_Unicode cAmPm = ' '; // a oder p
if (rInfo.nCntExp) // AM/PM
{
if (nHour == 0)
{
nHour = 12;
cAmPm = 'a';
}
else if (nHour < 12)
cAmPm = 'a';
else
{
cAmPm = 'p';
if (nHour > 12)
nHour -= 12;
}
}
const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
for (sal_uInt16 i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_DATESEP:
case NF_SYMBOLTYPE_TIMESEP:
case NF_SYMBOLTYPE_TIME100SECSEP:
OutString += rInfo.sStrArray[i];
break;
case NF_SYMBOLTYPE_DIGIT:
{
xub_StrLen nLen = ( bInputLine && i > 0 &&
(rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
nCntPost : rInfo.sStrArray[i].Len() );
for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
{
OutString += sSecStr.GetChar(nSecPos);
nSecPos++;
}
}
break;
case NF_KEY_AMPM: // AM/PM
{
if ( !bCalendarSet )
{
double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
fDiff += fNumberOrig;
GetCal().setLocalDateTime( fDiff );
bCalendarSet = sal_True;
}
if (cAmPm == 'a')
OutString += GetCal().getDisplayName(
CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
else
OutString += GetCal().getDisplayName(
CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
}
break;
case NF_KEY_AP: // A/P
{
if (cAmPm == 'a')
OutString += 'a';
else
OutString += 'p';
}
break;
case NF_KEY_MI: // M
OutString += ImpIntToString( nIx, nMin );
break;
case NF_KEY_MMI: // MM
OutString += ImpIntToString( nIx, nMin, 2 );
break;
case NF_KEY_H: // H
OutString += ImpIntToString( nIx, nHour );
break;
case NF_KEY_HH: // HH
OutString += ImpIntToString( nIx, nHour, 2 );
break;
case NF_KEY_S: // S
OutString += ImpIntToString( nIx, nSec );
break;
case NF_KEY_SS: // SS
OutString += ImpIntToString( nIx, nSec, 2 );
break;
default:
break;
}
}
if (bSign && rInfo.bThousand)
OutString.Insert('-',0);
return bRes;
}
sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
{
if ( GetCal().getUniqueID() != Gregorian::get() )
return sal_False;
const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
const sal_uInt16 nAnz = rNumFor.GetnAnz();
sal_uInt16 i;
for ( i = 0; i < nAnz; i++ )
{
switch ( rInfo.nTypeArray[i] )
{
case NF_SYMBOLTYPE_CALENDAR :
return sal_False;
case NF_KEY_EC :
case NF_KEY_EEC :
case NF_KEY_R :
case NF_KEY_RR :
case NF_KEY_AAA :
case NF_KEY_AAAA :
return sal_True;
}
}
return sal_False;
}
void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
double& fOrgDateTime ) const
{
CalendarWrapper& rCal = GetCal();
const rtl::OUString &rGregorian = Gregorian::get();
if ( rCal.getUniqueID() == rGregorian )
{
using namespace ::com::sun::star::i18n;
::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
= rCal.getAllCalendars( rLoc().getLocale() );
sal_Int32 nCnt = xCals.getLength();
if ( nCnt > 1 )
{
for ( sal_Int32 j=0; j < nCnt; j++ )
{
if ( xCals[j] != rGregorian )
{
if ( !rOrgCalendar.Len() )
{
rOrgCalendar = rCal.getUniqueID();
fOrgDateTime = rCal.getDateTime();
}
rCal.loadCalendar( xCals[j], rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
break; // for
}
}
}
}
}
void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
double fOrgDateTime ) const
{
CalendarWrapper& rCal = GetCal();
const rtl::OUString &rGregorian = Gregorian::get();
if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
{
rCal.loadCalendar( rGregorian, rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
}
}
sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
{
using namespace ::com::sun::star::i18n;
CalendarWrapper& rCal = GetCal();
const rtl::OUString &rGregorian = Gregorian::get();
if ( rCal.getUniqueID() != rGregorian )
{
sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
{
if ( !rOrgCalendar.Len() )
{
rOrgCalendar = rCal.getUniqueID();
fOrgDateTime = rCal.getDateTime();
}
else if ( rOrgCalendar == String(rGregorian) )
rOrgCalendar.Erase();
rCal.loadCalendar( rGregorian, rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
return sal_True;
}
}
return sal_False;
}
sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
{
const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
const sal_uInt16 nAnz = rNumFor.GetnAnz();
for ( sal_uInt16 i = 0; i < nAnz; i++ )
{
if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
{
CalendarWrapper& rCal = GetCal();
if ( !rOrgCalendar.Len() )
{
rOrgCalendar = rCal.getUniqueID();
fOrgDateTime = rCal.getDateTime();
}
rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
return sal_True;
}
}
return sal_False;
}
// static
void SvNumberformat::ImpAppendEraG( String& OutString,
const CalendarWrapper& rCal, sal_Int16 nNatNum )
{
using namespace ::com::sun::star::i18n;
if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
{
sal_Unicode cEra;
sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
switch ( nVal )
{
case 1 : cEra = 'M'; break;
case 2 : cEra = 'T'; break;
case 3 : cEra = 'S'; break;
case 4 : cEra = 'H'; break;
default:
cEra = '?';
}
OutString += cEra;
}
else
OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
}
sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber,
sal_uInt16 nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
sal_Bool bRes = sal_False;
CalendarWrapper& rCal = GetCal();
double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
fNumber += fDiff;
rCal.setLocalDateTime( fNumber );
String aOrgCalendar; // empty => not changed yet
double fOrgDateTime;
sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
bOtherCalendar = sal_False;
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
for (sal_uInt16 i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case NF_SYMBOLTYPE_CALENDAR :
if ( !aOrgCalendar.Len() )
{
aOrgCalendar = rCal.getUniqueID();
fOrgDateTime = rCal.getDateTime();
}
rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
break;
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_DATESEP:
case NF_SYMBOLTYPE_TIMESEP:
case NF_SYMBOLTYPE_TIME100SECSEP:
OutString += rInfo.sStrArray[i];
break;
case NF_KEY_M: // M
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_MONTH, nNatNum );
break;
case NF_KEY_MM: // MM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH, nNatNum );
break;
case NF_KEY_MMM: // MMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
break;
case NF_KEY_MMMM: // MMMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
break;
case NF_KEY_MMMMM: // MMMMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
break;
case NF_KEY_Q: // Q
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_QUARTER, nNatNum );
break;
case NF_KEY_QQ: // QQ
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_QUARTER, nNatNum );
break;
case NF_KEY_D: // D
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY, nNatNum );
break;
case NF_KEY_DD: // DD
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY, nNatNum );
break;
case NF_KEY_DDD: // DDD
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_DDDD: // DDDD
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_YY: // YY
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_YEAR, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_YYYY: // YYYY
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_EC: // E
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_YEAR, nNatNum );
break;
case NF_KEY_EEC: // EE
case NF_KEY_R: // R
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR, nNatNum );
break;
case NF_KEY_NN: // NN
case NF_KEY_AAA: // AAA
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
break;
case NF_KEY_NNN: // NNN
case NF_KEY_AAAA: // AAAA
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
break;
case NF_KEY_NNNN: // NNNN
{
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
OutString += rLoc().getLongDateDayOfWeekSep();
}
break;
case NF_KEY_WW : // WW
{
sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
OutString += ImpIntToString( nIx, nVal );
}
break;
case NF_KEY_G: // G
ImpAppendEraG( OutString, rCal, nNatNum );
break;
case NF_KEY_GG: // GG
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_ERA, nNatNum );
break;
case NF_KEY_GGG: // GGG
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_ERA, nNatNum );
break;
case NF_KEY_RR: // RR => GGGEE
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
break;
}
}
if ( aOrgCalendar.Len() )
rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
return bRes;
}
sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
sal_uInt16 nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
sal_Bool bRes = sal_False;
CalendarWrapper& rCal = GetCal();
double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
fNumber += fDiff;
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
sal_Bool bInputLine;
xub_StrLen nCntPost;
if ( rScan.GetStandardPrec() == 300 &&
0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
{ // round at 7 decimals (+5 of 86400 == 12 significant digits)
bInputLine = sal_True;
nCntPost = 7;
}
else
{
bInputLine = sal_False;
nCntPost = xub_StrLen(rInfo.nCntPost);
}
double fTime = (fNumber - floor( fNumber )) * 86400.0;
fTime = ::rtl::math::round( fTime, int(nCntPost) );
if (fTime >= 86400.0)
{
// result of fNumber==x.999999999... rounded up, use correct date/time
fTime -= 86400.0;
fNumber = floor( fNumber + 0.5) + fTime;
}
rCal.setLocalDateTime( fNumber );
String aOrgCalendar; // empty => not changed yet
double fOrgDateTime;
sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
bOtherCalendar = sal_False;
sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
sal_uLong nSeconds = (sal_uLong)floor( fTime );
String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
rtl_math_StringFormat_F, int(nCntPost), '.'));
sSecStr.EraseLeadingChars('0');
sSecStr.EraseLeadingChars('.');
if ( bInputLine )
{
sSecStr.EraseTrailingChars('0');
if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
nCntPost = sSecStr.Len();
}
else
ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
xub_StrLen nSecPos = 0; // Zum Ziffernweisen
// abarbeiten
sal_uLong nHour, nMin, nSec;
if (!rInfo.bThousand) // [] Format
{
nHour = (nSeconds/3600) % 24;
nMin = (nSeconds%3600) / 60;
nSec = nSeconds%60;
}
else if (rInfo.nThousand == 3) // [ss]
{
nHour = 0;
nMin = 0;
nSec = nSeconds;
}
else if (rInfo.nThousand == 2) // [mm]:ss
{
nHour = 0;
nMin = nSeconds / 60;
nSec = nSeconds % 60;
}
else if (rInfo.nThousand == 1) // [hh]:mm:ss
{
nHour = nSeconds / 3600;
nMin = (nSeconds%3600) / 60;
nSec = nSeconds%60;
}
else {
nHour = 0; // TODO What should these values be?
nMin = 0;
nSec = 0;
}
sal_Unicode cAmPm = ' '; // a oder p
if (rInfo.nCntExp) // AM/PM
{
if (nHour == 0)
{
nHour = 12;
cAmPm = 'a';
}
else if (nHour < 12)
cAmPm = 'a';
else
{
cAmPm = 'p';
if (nHour > 12)
nHour -= 12;
}
}
const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
for (sal_uInt16 i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case NF_SYMBOLTYPE_CALENDAR :
if ( !aOrgCalendar.Len() )
{
aOrgCalendar = rCal.getUniqueID();
fOrgDateTime = rCal.getDateTime();
}
rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
rCal.setDateTime( fOrgDateTime );
ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
break;
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_DATESEP:
case NF_SYMBOLTYPE_TIMESEP:
case NF_SYMBOLTYPE_TIME100SECSEP:
OutString += rInfo.sStrArray[i];
break;
case NF_SYMBOLTYPE_DIGIT:
{
xub_StrLen nLen = ( bInputLine && i > 0 &&
(rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
nCntPost : rInfo.sStrArray[i].Len() );
for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
{
OutString += sSecStr.GetChar(nSecPos);
nSecPos++;
}
}
break;
case NF_KEY_AMPM: // AM/PM
{
if (cAmPm == 'a')
OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
AmPmValue::AM, 0 );
else
OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
AmPmValue::PM, 0 );
}
break;
case NF_KEY_AP: // A/P
{
if (cAmPm == 'a')
OutString += 'a';
else
OutString += 'p';
}
break;
case NF_KEY_MI: // M
OutString += ImpIntToString( nIx, nMin );
break;
case NF_KEY_MMI: // MM
OutString += ImpIntToString( nIx, nMin, 2 );
break;
case NF_KEY_H: // H
OutString += ImpIntToString( nIx, nHour );
break;
case NF_KEY_HH: // HH
OutString += ImpIntToString( nIx, nHour, 2 );
break;
case NF_KEY_S: // S
OutString += ImpIntToString( nIx, nSec );
break;
case NF_KEY_SS: // SS
OutString += ImpIntToString( nIx, nSec, 2 );
break;
case NF_KEY_M: // M
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_MONTH, nNatNum );
break;
case NF_KEY_MM: // MM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH, nNatNum );
break;
case NF_KEY_MMM: // MMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
break;
case NF_KEY_MMMM: // MMMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
break;
case NF_KEY_MMMMM: // MMMMM
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
break;
case NF_KEY_Q: // Q
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_QUARTER, nNatNum );
break;
case NF_KEY_QQ: // QQ
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_QUARTER, nNatNum );
break;
case NF_KEY_D: // D
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY, nNatNum );
break;
case NF_KEY_DD: // DD
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY, nNatNum );
break;
case NF_KEY_DDD: // DDD
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_DDDD: // DDDD
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_YY: // YY
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_YEAR, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_YYYY: // YYYY
{
if ( bOtherCalendar )
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR, nNatNum );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
}
break;
case NF_KEY_EC: // E
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_YEAR, nNatNum );
break;
case NF_KEY_EEC: // EE
case NF_KEY_R: // R
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR, nNatNum );
break;
case NF_KEY_NN: // NN
case NF_KEY_AAA: // AAA
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
break;
case NF_KEY_NNN: // NNN
case NF_KEY_AAAA: // AAAA
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
break;
case NF_KEY_NNNN: // NNNN
{
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
OutString += rLoc().getLongDateDayOfWeekSep();
}
break;
case NF_KEY_WW : // WW
{
sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
OutString += ImpIntToString( nIx, nVal );
}
break;
case NF_KEY_G: // G
ImpAppendEraG( OutString, rCal, nNatNum );
break;
case NF_KEY_GG: // GG
OutString += rCal.getDisplayString(
CalendarDisplayCode::SHORT_ERA, nNatNum );
break;
case NF_KEY_GGG: // GGG
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_ERA, nNatNum );
break;
case NF_KEY_RR: // RR => GGGEE
OutString += rCal.getDisplayString(
CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
break;
}
}
if ( aOrgCalendar.Len() )
rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
return bRes;
}
sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber,
sal_uInt16 nIx,
String& OutString)
{
sal_Bool bRes = sal_False;
sal_Bool bSign;
if (fNumber < 0.0)
{
if (nIx == 0) // nicht in hinteren
bSign = sal_True; // Formaten
else
bSign = sal_False;
fNumber = -fNumber;
}
else
{
bSign = sal_False;
if ( ::rtl::math::isSignBitSet( fNumber ) )
fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
}
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
{
if (fNumber < _D_MAX_D_BY_100)
fNumber *= 100.0;
else
{
OutString = rScan.GetErrorString();
return sal_False;
}
}
sal_uInt16 i, j;
xub_StrLen k;
String sStr;
long nPrecExp;
sal_Bool bInteger = sal_False;
if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
{ // special formatting only if no GENERAL keyword in format code
const sal_uInt16 nThousand = rInfo.nThousand;
for (i = 0; i < nThousand; i++)
{
if (fNumber > _D_MIN_M_BY_1000)
fNumber /= 1000.0;
else
fNumber = 0.0;
}
if (fNumber > 0.0)
nPrecExp = GetPrecExp( fNumber );
else
nPrecExp = 0;
if (rInfo.nCntPost) // NachkommaStellen
{
if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
{
sStr = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_F, 15-nPrecExp, '.');
for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
sStr += '0';
}
else
sStr = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
}
else if (fNumber == 0.0) // Null
{
// nothing to be done here, keep empty string sStr,
// ImpNumberFillWithThousands does the rest
}
else // Integer
{
sStr = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_F, 0, '.');
sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
}
xub_StrLen nPoint = sStr.Search( '.' );
if ( nPoint != STRING_NOTFOUND )
{
register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
while ( *++p == '0' )
;
if ( !*p )
bInteger = sal_True;
sStr.Erase( nPoint, 1 ); // . herausnehmen
}
if (bSign &&
(sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000
bSign = sal_False; // nicht -0.00
} // End of != FLAG_STANDARD_IN_FORMAT
// von hinten nach vorn
// editieren:
k = sStr.Len(); // hinter letzter Ziffer
j = NumFor[nIx].GetnAnz()-1; // letztes Symbol
// Nachkommastellen:
if (rInfo.nCntPost > 0)
{
sal_Bool bTrailing = sal_True; // ob Endnullen?
sal_Bool bFilled = sal_False; // ob aufgefuellt wurde ?
short nType;
while (j > 0 && // rueckwaerts
(nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
{
switch ( nType )
{
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
/*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_PERCENT:
sStr.Insert(rInfo.sStrArray[j],k);
break;
case NF_SYMBOLTYPE_THSEP:
if (rInfo.nThousand == 0)
sStr.Insert(rInfo.sStrArray[j],k);
break;
case NF_SYMBOLTYPE_DIGIT:
{
const String& rStr = rInfo.sStrArray[j];
const sal_Unicode* p1 = rStr.GetBuffer();
register const sal_Unicode* p = p1 + rStr.Len();
while ( p1 < p-- )
{
const sal_Unicode c = *p;
k--;
if ( sStr.GetChar(k) != '0' )
bTrailing = sal_False;
if (bTrailing)
{
if ( c == '0' )
bFilled = sal_True;
else if ( c == '-' )
{
if ( bInteger )
sStr.SetChar( k, '-' );
bFilled = sal_True;
}
else if ( c == '?' )
{
sStr.SetChar( k, ' ' );
bFilled = sal_True;
}
else if ( !bFilled ) // #
sStr.Erase(k,1);
}
} // of for
} // of case digi
break;
case NF_KEY_CCC: // CCC-Waehrung
sStr.Insert(rScan.GetCurAbbrev(), k);
break;
case NF_KEY_GENERAL: // Standard im String
{
String sNum;
ImpGetOutputStandard(fNumber, sNum);
sNum.EraseLeadingChars('-');
sStr.Insert(sNum, k);
}
break;
default:
break;
} // of switch
j--;
} // of while
} // of Nachkomma
bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
rInfo.nCntPre);
if ( rInfo.nCntPost > 0 )
{
const String& rDecSep = GetFormatter().GetNumDecimalSep();
xub_StrLen nLen = rDecSep.Len();
if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep
}
if (bSign)
sStr.Insert('-',0);
ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
OutString = sStr;
return bRes;
}
sal_Bool SvNumberformat::ImpNumberFillWithThousands(
String& sStr, // number string
double& rNumber, // number
xub_StrLen k, // position within string
sal_uInt16 j, // symbol index within format code
sal_uInt16 nIx, // subformat index
sal_uInt16 nDigCnt) // count of integer digits in format
{
sal_Bool bRes = sal_False;
xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
xub_StrLen nDigitCount = 0; // count of integer digits from the right
sal_Bool bStop = sal_False;
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
// no normal thousands separators if number divided by thousands
sal_Bool bDoThousands = (rInfo.nThousand == 0);
utl::DigitGroupingIterator aGrouping(
GetFormatter().GetLocaleData()->getDigitGrouping());
while (!bStop) // backwards
{
if (j == 0)
bStop = sal_True;
switch (rInfo.nTypeArray[j])
{
case NF_SYMBOLTYPE_DECSEP:
aGrouping.reset();
// fall thru
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_PERCENT:
sStr.Insert(rInfo.sStrArray[j],k);
if ( k == 0 )
nLeadingStringChars =
nLeadingStringChars + rInfo.sStrArray[j].Len();
break;
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
/*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case NF_SYMBOLTYPE_THSEP:
{
// #i7284# #102685# Insert separator also if number is divided
// by thousands and the separator is specified somewhere in
// between and not only at the end.
// #i12596# But do not insert if it's a parenthesized negative
// format like (#,)
// In fact, do not insert if divided and regex [0#,],[^0#] and
// no other digit symbol follows (which was already detected
// during scan of format code, otherwise there would be no
// division), else do insert. Same in ImpNumberFill() below.
if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
bDoThousands = ((j == 0) ||
(rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
(rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
if ( bDoThousands )
{
if (k > 0)
sStr.Insert(rInfo.sStrArray[j],k);
else if (nDigitCount < nDigCnt)
{
// Leading '#' displays nothing (e.g. no leading
// separator for numbers <1000 with #,##0 format).
// Leading '?' displays blank.
// Everything else, including nothing, displays the
// separator.
sal_Unicode cLeader = 0;
if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
{
const String& rStr = rInfo.sStrArray[j-1];
xub_StrLen nLen = rStr.Len();
if (nLen)
cLeader = rStr.GetChar(nLen-1);
}
switch (cLeader)
{
case '#':
; // nothing
break;
case '?':
// erAck: 2008-04-03T16:24+0200
// Actually this currently isn't executed
// because the format scanner in the context of
// "?," doesn't generate a group separator but
// a literal ',' character instead that is
// inserted unconditionally. Should be changed
// on some occasion.
sStr.Insert(' ',k);
break;
default:
sStr.Insert(rInfo.sStrArray[j],k);
}
}
aGrouping.advance();
}
}
break;
case NF_SYMBOLTYPE_DIGIT:
{
const String& rStr = rInfo.sStrArray[j];
const sal_Unicode* p1 = rStr.GetBuffer();
register const sal_Unicode* p = p1 + rStr.Len();
while ( p1 < p-- )
{
nDigitCount++;
if (k > 0)
k--;
else
{
switch (*p)
{
case '0':
sStr.Insert('0',0);
break;
case '?':
sStr.Insert(' ',0);
break;
}
}
if (nDigitCount == nDigCnt && k > 0)
{ // more digits than specified
ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
}
}
}
break;
case NF_KEY_CCC: // CCC currency
sStr.Insert(rScan.GetCurAbbrev(), k);
break;
case NF_KEY_GENERAL: // "General" in string
{
String sNum;
ImpGetOutputStandard(rNumber, sNum);
sNum.EraseLeadingChars('-');
sStr.Insert(sNum, k);
}
break;
default:
break;
} // switch
j--; // next format code string
} // while
k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ...
if (k > nLeadingStringChars)
ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
return bRes;
}
void SvNumberformat::ImpDigitFill(
String& sStr, // number string
xub_StrLen nStart, // start of digits
xub_StrLen& k, // position within string
sal_uInt16 nIx, // subformat index
xub_StrLen & nDigitCount, // count of integer digits from the right so far
utl::DigitGroupingIterator & rGrouping ) // current grouping
{
if (NumFor[nIx].Info().bThousand) // only if grouping
{ // fill in separators
const String& rThousandSep = GetFormatter().GetNumThousandSep();
while (k > nStart)
{
if (nDigitCount == rGrouping.getPos())
{
sStr.Insert( rThousandSep, k );
rGrouping.advance();
}
nDigitCount++;
k--;
}
}
else // simply skip
k = nStart;
}
sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string
double& rNumber, // number for "General" format
xub_StrLen& k, // position within string
sal_uInt16& j, // symbol index within format code
sal_uInt16 nIx, // subformat index
short eSymbolType ) // type of stop condition
{
sal_Bool bRes = sal_False;
k = sStr.Len(); // behind last digit
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
// no normal thousands separators if number divided by thousands
sal_Bool bDoThousands = (rInfo.nThousand == 0);
short nType;
while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
{ // rueckwaerts:
switch ( nType )
{
case NF_SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( sal_Unicode(0x1B), k++ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = sal_True;
}
break;
case NF_SYMBOLTYPE_BLANK:
k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case NF_SYMBOLTYPE_THSEP:
{
// Same as in ImpNumberFillWithThousands() above, do not insert
// if divided and regex [0#,],[^0#] and no other digit symbol
// follows (which was already detected during scan of format
// code, otherwise there would be no division), else do insert.
if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
bDoThousands = ((j == 0) ||
(rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
(rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
if ( bDoThousands && k > 0 )
{
sStr.Insert(rInfo.sStrArray[j],k);
}
}
break;
case NF_SYMBOLTYPE_DIGIT:
{
const String& rStr = rInfo.sStrArray[j];
const sal_Unicode* p1 = rStr.GetBuffer();
register const sal_Unicode* p = p1 + rStr.Len();
while ( p1 < p-- )
{
if (k > 0)
k--;
else
{
switch (*p)
{
case '0':
sStr.Insert('0',0);
break;
case '?':
sStr.Insert(' ',0);
break;
}
}
}
}
break;
case NF_KEY_CCC: // CCC-Waehrung
sStr.Insert(rScan.GetCurAbbrev(), k);
break;
case NF_KEY_GENERAL: // Standard im String
{
String sNum;
ImpGetOutputStandard(rNumber, sNum);
sNum.EraseLeadingChars('-'); // Vorzeichen weg!!
sStr.Insert(sNum, k);
}
break;
default:
sStr.Insert(rInfo.sStrArray[j],k);
break;
} // of switch
j--; // naechster String
} // of while
return bRes;
}
void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand,
sal_Bool& IsRed,
sal_uInt16& nPrecision,
sal_uInt16& nAnzLeading) const
{
// as before: take info from nNumFor=0 for whole format (for dialog etc.)
short nDummyType;
GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
// "negative in red" is only useful for the whole format
const Color* pColor = NumFor[1].GetColor();
if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
&& (*pColor == rScan.GetRedColor()))
IsRed = sal_True;
else
IsRed = sal_False;
}
void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType,
sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const
{
// take info from a specified sub-format (for XML export)
if ( nNumFor > 3 )
return; // invalid
const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
rScannedType = rInfo.eScannedType;
bThousand = rInfo.bThousand;
nPrecision = rInfo.nCntPost;
if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
// StandardFormat
nAnzLeading = 1;
else
{
nAnzLeading = 0;
sal_Bool bStop = sal_False;
sal_uInt16 i = 0;
const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
while (!bStop && i < nAnz)
{
short nType = rInfo.nTypeArray[i];
if ( nType == NF_SYMBOLTYPE_DIGIT)
{
register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
while ( *p == '#' )
p++;
while ( *p++ == '0' )
nAnzLeading++;
}
else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
bStop = sal_True;
i++;
}
}
}
const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
sal_Bool bString /* = sal_False */ ) const
{
if ( nNumFor > 3 )
return NULL;
sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
if ( !nAnz )
return NULL;
if ( nPos == 0xFFFF )
{
nPos = nAnz - 1;
if ( bString )
{ // rueckwaerts
short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
(*pType != NF_SYMBOLTYPE_CURRENCY) )
{
pType--;
nPos--;
}
if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
return NULL;
}
}
else if ( nPos > nAnz - 1 )
return NULL;
else if ( bString )
{ // vorwaerts
short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
(*pType != NF_SYMBOLTYPE_CURRENCY) )
{
pType++;
nPos++;
}
if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
(*pType != NF_SYMBOLTYPE_CURRENCY)) )
return NULL;
}
return &NumFor[nNumFor].Info().sStrArray[nPos];
}
short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos,
sal_Bool bString /* = sal_False */ ) const
{
if ( nNumFor > 3 )
return 0;
sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
if ( !nAnz )
return 0;
if ( nPos == 0xFFFF )
{
nPos = nAnz - 1;
if ( bString )
{ // rueckwaerts
short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
(*pType != NF_SYMBOLTYPE_CURRENCY) )
{
pType--;
nPos--;
}
if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
return 0;
}
}
else if ( nPos > nAnz - 1 )
return 0;
else if ( bString )
{ // vorwaerts
short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
(*pType != NF_SYMBOLTYPE_CURRENCY) )
{
pType++;
nPos++;
}
if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
return 0;
}
return NumFor[nNumFor].Info().nTypeArray[nPos];
}
sal_Bool SvNumberformat::IsNegativeWithoutSign() const
{
if ( IsNegativeRealNegative() )
{
const String* pStr = GetNumForString( 1, 0, sal_True );
if ( pStr )
return !HasStringNegativeSign( *pStr );
}
return sal_False;
}
DateFormat SvNumberformat::GetDateOrder() const
{
if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
{
short const * const pType = NumFor[0].Info().nTypeArray;
sal_uInt16 nAnz = NumFor[0].GetnAnz();
for ( sal_uInt16 j=0; j<nAnz; j++ )
{
switch ( pType[j] )
{
case NF_KEY_D :
case NF_KEY_DD :
return DMY;
case NF_KEY_M :
case NF_KEY_MM :
case NF_KEY_MMM :
case NF_KEY_MMMM :
case NF_KEY_MMMMM :
return MDY;
case NF_KEY_YY :
case NF_KEY_YYYY :
case NF_KEY_EC :
case NF_KEY_EEC :
case NF_KEY_R :
case NF_KEY_RR :
return YMD;
}
}
}
else
{
DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
}
return rLoc().getDateFormat();
}
sal_uInt32 SvNumberformat::GetExactDateOrder() const
{
sal_uInt32 nRet = 0;
if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
{
DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
return nRet;
}
short const * const pType = NumFor[0].Info().nTypeArray;
sal_uInt16 nAnz = NumFor[0].GetnAnz();
int nShift = 0;
for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ )
{
switch ( pType[j] )
{
case NF_KEY_D :
case NF_KEY_DD :
nRet = (nRet << 8) | 'D';
++nShift;
break;
case NF_KEY_M :
case NF_KEY_MM :
case NF_KEY_MMM :
case NF_KEY_MMMM :
case NF_KEY_MMMMM :
nRet = (nRet << 8) | 'M';
++nShift;
break;
case NF_KEY_YY :
case NF_KEY_YYYY :
case NF_KEY_EC :
case NF_KEY_EEC :
case NF_KEY_R :
case NF_KEY_RR :
nRet = (nRet << 8) | 'Y';
++nShift;
break;
}
}
return nRet;
}
void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
SvNumberformatLimitOps& rOper2, double& rVal2 ) const
{
rOper1 = eOp1;
rOper2 = eOp2;
rVal1 = fLimit1;
rVal2 = fLimit2;
}
Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const
{
if ( nNumFor > 3 )
return NULL;
return NumFor[nNumFor].GetColor();
}
void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
{
if ( eOp != NUMBERFORMAT_OP_NO )
{
switch ( eOp )
{
case NUMBERFORMAT_OP_EQ :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
break;
case NUMBERFORMAT_OP_NE :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
break;
case NUMBERFORMAT_OP_LT :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
break;
case NUMBERFORMAT_OP_LE :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
break;
case NUMBERFORMAT_OP_GT :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
break;
case NUMBERFORMAT_OP_GE :
rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
break;
default:
OSL_ASSERT( "unsupported number format" );
break;
}
rStr += String( ::rtl::math::doubleToUString( fLimit,
rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
rDecSep.GetChar(0), sal_True));
rStr += ']';
}
}
String SvNumberformat::GetMappedFormatstring(
const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
sal_Bool bDontQuote ) const
{
String aStr;
sal_Bool bDefault[4];
// 1 subformat matches all if no condition specified,
bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
// with 2 subformats [>=0];[<0] is implied if no condition specified
bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
// with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
// note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
// from now on bDefault[] values are used to append empty subformats at the end
bDefault[3] = sal_False;
if ( !bDefaults )
{ // conditions specified
if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
bDefault[0] = bDefault[1] = sal_True; // [];x
else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
NumFor[2].GetnAnz() == 0 )
bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];;
// nothing to do if conditions specified for every subformat
}
else if ( bDefault[0] )
bDefault[0] = sal_False; // a single unconditional subformat is never delimited
else
{
if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
bDefault[3] = sal_True; // special cases x;x;; and ;x;;
for ( int i=0; i<3 && !bDefault[i]; ++i )
bDefault[i] = sal_True;
}
int nSem = 0; // needed ';' delimiters
int nSub = 0; // subformats delimited so far
for ( int n=0; n<4; n++ )
{
if ( n > 0 )
nSem++;
String aPrefix;
if ( !bDefaults )
{
switch ( n )
{
case 0 :
lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
fLimit1, rLocWrp.getNumDecimalSep() );
break;
case 1 :
lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
fLimit2, rLocWrp.getNumDecimalSep() );
break;
}
}
const String& rColorName = NumFor[n].GetColorName();
if ( rColorName.Len() )
{
const NfKeywordTable & rKey = rScan.GetKeywords();
for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ )
{
if ( rKey[j] == rColorName )
{
aPrefix += '[';
aPrefix += rKeywords[j];
aPrefix += ']';
break; // for
}
}
}
const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
// The Thai T NatNum modifier during Xcl export.
if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
MsLangId::getRealLanguage( rNum.GetLang()) ==
LANGUAGE_THAI)
{
aPrefix += 't'; // must be lowercase, otherwise taken as literal
}
sal_uInt16 nAnz = NumFor[n].GetnAnz();
if ( nSem && (nAnz || aPrefix.Len()) )
{
for ( ; nSem; --nSem )
aStr += ';';
for ( ; nSub <= n; ++nSub )
bDefault[nSub] = sal_False;
}
if ( aPrefix.Len() )
aStr += aPrefix;
if ( nAnz )
{
const short* pType = NumFor[n].Info().nTypeArray;
const String* pStr = NumFor[n].Info().sStrArray;
for ( sal_uInt16 j=0; j<nAnz; j++ )
{
if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
{
aStr += rKeywords[pType[j]];
if( NF_KEY_NNNN == pType[j] )
aStr += rLocWrp.getLongDateDayOfWeekSep();
}
else
{
switch ( pType[j] )
{
case NF_SYMBOLTYPE_DECSEP :
aStr += rLocWrp.getNumDecimalSep();
break;
case NF_SYMBOLTYPE_THSEP :
aStr += rLocWrp.getNumThousandSep();
break;
case NF_SYMBOLTYPE_DATESEP :
aStr += rLocWrp.getDateSep();
break;
case NF_SYMBOLTYPE_TIMESEP :
aStr += rLocWrp.getTimeSep();
break;
case NF_SYMBOLTYPE_TIME100SECSEP :
aStr += rLocWrp.getTime100SecSep();
break;
case NF_SYMBOLTYPE_STRING :
if( bDontQuote )
aStr += pStr[j];
else if ( pStr[j].Len() == 1 )
{
aStr += '\\';
aStr += pStr[j];
}
else
{
aStr += '"';
aStr += pStr[j];
aStr += '"';
}
break;
default:
aStr += pStr[j];
}
}
}
}
}
for ( ; nSub<4 && bDefault[nSub]; ++nSub )
{ // append empty subformats
aStr += ';';
}
return aStr;
}
String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
sal_Int32 nVal, sal_uInt16 nMinDigits ) const
{
String aStr;
if ( nMinDigits )
{
if ( nMinDigits == 2 )
{ // speed up the most common case
if ( 0 <= nVal && nVal < 10 )
{
sal_Unicode* p = aStr.AllocBuffer( 2 );
*p++ = '0';
*p = sal_Unicode( '0' + nVal );
}
else
aStr = String::CreateFromInt32( nVal );
}
else
{
String aValStr( String::CreateFromInt32( nVal ) );
if ( aValStr.Len() >= nMinDigits )
aStr = aValStr;
else
{
aStr.Fill( nMinDigits - aValStr.Len(), '0' );
aStr += aValStr;
}
}
}
else
aStr = String::CreateFromInt32( nVal );
ImpTransliterate( aStr, rNum );
return aStr;
}
void SvNumberformat::ImpTransliterateImpl( String& rStr,
const SvNumberNatNum& rNum ) const
{
com::sun::star::lang::Locale aLocale(
MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
aLocale, rNum.GetNatNum() );
}
void SvNumberformat::GetNatNumXml(
com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
sal_uInt16 nNumFor ) const
{
if ( nNumFor <= 3 )
{
const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
if ( rNum.IsSet() )
{
com::sun::star::lang::Locale aLocale(
MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
aLocale, rNum.GetNatNum() );
}
else
rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
}
else
rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
}
// static
sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr )
{
// fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
xub_StrLen nLen = rStr.Len();
if ( !nLen )
return sal_False;
const sal_Unicode* const pBeg = rStr.GetBuffer();
const sal_Unicode* const pEnd = pBeg + nLen;
register const sal_Unicode* p = pBeg;
do
{ // Anfang
if ( *p == '-' )
return sal_True;
} while ( *p == ' ' && ++p < pEnd );
p = pEnd - 1;
do
{ // Ende
if ( *p == '-' )
return sal_True;
} while ( *p == ' ' && pBeg < --p );
return sal_False;
}
// static
void SvNumberformat::SetComment( const String& rStr, String& rFormat,
String& rComment )
{
if ( rComment.Len() )
{ // alten Kommentar aus Formatstring loeschen
//! nicht per EraseComment, der Kommentar muss matchen
String aTmp( '{' );
aTmp += ' ';
aTmp += rComment;
aTmp += ' ';
aTmp += '}';
xub_StrLen nCom = 0;
do
{
nCom = rFormat.Search( aTmp, nCom );
} while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
if ( nCom != STRING_NOTFOUND )
rFormat.Erase( nCom );
}
if ( rStr.Len() )
{ // neuen Kommentar setzen
rFormat += '{';
rFormat += ' ';
rFormat += rStr;
rFormat += ' ';
rFormat += '}';
rComment = rStr;
}
}
// static
void SvNumberformat::EraseCommentBraces( String& rStr )
{
xub_StrLen nLen = rStr.Len();
if ( nLen && rStr.GetChar(0) == '{' )
{
rStr.Erase( 0, 1 );
--nLen;
}
if ( nLen && rStr.GetChar(0) == ' ' )
{
rStr.Erase( 0, 1 );
--nLen;
}
if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
rStr.Erase( --nLen, 1 );
if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
rStr.Erase( --nLen, 1 );
}
// static
void SvNumberformat::EraseComment( String& rStr )
{
register const sal_Unicode* p = rStr.GetBuffer();
sal_Bool bInString = sal_False;
sal_Bool bEscaped = sal_False;
sal_Bool bFound = sal_False;
xub_StrLen nPos = 0;
while ( !bFound && *p )
{
switch ( *p )
{
case '\\' :
bEscaped = !bEscaped;
break;
case '\"' :
if ( !bEscaped )
bInString = !bInString;
break;
case '{' :
if ( !bEscaped && !bInString )
{
bFound = sal_True;
nPos = sal::static_int_cast< xub_StrLen >(
p - rStr.GetBuffer());
}
break;
}
if ( bEscaped && *p != '\\' )
bEscaped = sal_False;
++p;
}
if ( bFound )
rStr.Erase( nPos );
}
// static
sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
{
xub_StrLen nLen = rStr.Len();
if ( nPos >= nLen )
return sal_False;
register const sal_Unicode* p0 = rStr.GetBuffer();
register const sal_Unicode* p = p0;
register const sal_Unicode* p1 = p0 + nPos;
sal_Bool bQuoted = sal_False;
while ( p <= p1 )
{
if ( *p == cQuote )
{
if ( p == p0 )
bQuoted = sal_True;
else if ( bQuoted )
{
if ( *(p-1) != cEscIn )
bQuoted = sal_False;
}
else
{
if ( *(p-1) != cEscOut )
bQuoted = sal_True;
}
}
p++;
}
return bQuoted;
}
// static
xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
{
xub_StrLen nLen = rStr.Len();
if ( nPos >= nLen )
return STRING_NOTFOUND;
if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
{
if ( rStr.GetChar( nPos ) == cQuote )
return nPos; // schliessendes cQuote
return STRING_NOTFOUND;
}
register const sal_Unicode* p0 = rStr.GetBuffer();
register const sal_Unicode* p = p0 + nPos;
register const sal_Unicode* p1 = p0 + nLen;
while ( p < p1 )
{
if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
return sal::static_int_cast< xub_StrLen >(p - p0);
p++;
}
return nLen; // String Ende
}
sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const
{
sal_uInt16 nCnt = 0;
sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
short const * const pType = NumFor[nNumFor].Info().nTypeArray;
for ( sal_uInt16 j=0; j<nAnz; ++j )
{
switch ( pType[j] )
{
case NF_SYMBOLTYPE_STRING:
case NF_SYMBOLTYPE_CURRENCY:
case NF_SYMBOLTYPE_DATESEP:
case NF_SYMBOLTYPE_TIMESEP:
case NF_SYMBOLTYPE_TIME100SECSEP:
case NF_SYMBOLTYPE_PERCENT:
++nCnt;
break;
}
}
return nCnt;
}