Files
libreoffice/svtools/source/numbers/zformat.cxx
Rüdiger Timm 058ba1a2ea INTEGRATION: CWS ooo20040704 (1.58.34); FILE MERGED
2004/07/20 01:25:00 svesik 1.58.34.3: RESYNC: (1.58-1.59); FILE MERGED
2004/07/03 14:19:30 waratah 1.58.34.2: #i30874# Correct uninitiliased warnings
2004/07/02 23:59:20 waratah 1.58.34.1: #i30874# Add initial values to potentially uninitialised values
2004-09-08 14:22:58 +00:00

4433 lines
154 KiB
C++

/*************************************************************************
*
* $RCSfile: zformat.cxx,v $
*
* $Revision: 1.60 $
*
* last change: $Author: rt $ $Date: 2004-09-08 15:22:58 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (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.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#pragma hdrstop
#include <stdio.h>
#include <ctype.h>
#include <float.h>
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#ifndef _INTN_HXX //autogen
//#include <tools/intn.hxx>
#endif
#ifndef _DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif
#ifndef INCLUDED_RTL_MATH_HXX
#include <rtl/math.hxx>
#endif
#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif
#ifndef _UNOTOOLS_CHARCLASS_HXX
#include <unotools/charclass.hxx>
#endif
#ifndef _UNOTOOLS_CALENDARWRAPPER_HXX
#include <unotools/calendarwrapper.hxx>
#endif
#ifndef _UNOTOOLS_NATIVENUMBERWRAPPER_HXX
#include <unotools/nativenumberwrapper.hxx>
#endif
#ifndef _COM_SUN_STAR_I18N_CALENDARFIELDINDEX_HPP_
#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
#endif
#ifndef _COM_SUN_STAR_I18N_CALENDARDISPLAYINDEX_HPP_
#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
#endif
#ifndef _COM_SUN_STAR_I18N_CALENDARDISPLAYCODE_HPP_
#include <com/sun/star/i18n/CalendarDisplayCode.hpp>
#endif
#ifndef _COM_SUN_STAR_I18N_AMPMVALUE_HPP_
#include <com/sun/star/i18n/AmPmValue.hpp>
#endif
#define _ZFORMAT_CXX
#include "zformat.hxx"
#include "zforscan.hxx"
#include "zforfind.hxx"
#include "zforlist.hxx"
#include "numhead.hxx"
struct GregorianInit
{
const ::rtl::OUString* operator()()
{
static ::rtl::OUString sGregorian
(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
return &sGregorian;
}
};
namespace { struct Gregorian : public rtl::Static<const ::rtl::OUString, Gregorian, GregorianInit> {}; }
const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0
const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0
const USHORT _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 BYTE 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 )
{
USHORT 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 USHORT nNewCurrencyVersionId = 0x434E; // "NC"
const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment
const USHORT nNewStandardFlagVersionId = 0x4653; // "SF"
/***********************Funktion SvNumberformatInfo******************************/
void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, USHORT nAnz )
{
for (USHORT 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, USHORT nAnz) const
{
for (USHORT 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 SYMBOLTYPE_CURRENCY :
rStream << short( SYMBOLTYPE_STRING );
break;
case SYMBOLTYPE_CURRDEL :
case SYMBOLTYPE_CURREXT :
rStream << short(0); // werden ignoriert (hoffentlich..)
break;
default:
if ( nType > NF_KEY_LASTKEYWORD_SO5 )
rStream << short( SYMBOLTYPE_STRING ); // all new keywords are string
else
rStream << nType;
}
}
rStream << eScannedType << bThousand << nThousand
<< nCntPre << nCntPost << nCntExp;
}
void ImpSvNumberformatInfo::Load(SvStream& rStream, USHORT nAnz)
{
for (USHORT i = 0; i < nAnz; i++)
{
SvNumberformat::LoadString( rStream, sStrArray[i] );
rStream >> nTypeArray[i];
}
rStream >> eScannedType >> bThousand >> nThousand
>> nCntPre >> nCntPost >> nCntExp;
}
//============================================================================
// static
BYTE SvNumberNatNum::MapDBNumToNatNum( BYTE nDBNum, LanguageType eLang, BOOL bDate )
{
BYTE nNatNum = 0;
eLang = SvNumberFormatter::GetProperLanguage( 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
BYTE SvNumberNatNum::MapNatNumToDBNum( BYTE nNatNum, LanguageType eLang, BOOL bDate )
{
BYTE nDBNum = 0;
eLang = SvNumberFormatter::GetProperLanguage( 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 = FALSE;
aI.nThousand = 0;
aI.nCntPre = 0;
aI.nCntPost = 0;
aI.nCntExp = 0;
pColor = NULL;
}
ImpSvNumFor::~ImpSvNumFor()
{
for (USHORT i = 0; i < nAnzStrings; i++)
aI.sStrArray[i].Erase();
delete [] aI.sStrArray;
delete [] aI.nTypeArray;
}
void ImpSvNumFor::Enlarge(USHORT 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 )
{
Enlarge( rNumFor.nAnzStrings );
aI.Copy( rNumFor.aI, nAnzStrings );
pColor = rNumFor.pColor;
sColorName = rNumFor.sColorName;
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 )
{
USHORT 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);
}
BOOL ImpSvNumFor::HasNewCurrency() const
{
for ( USHORT j=0; j<nAnzStrings; j++ )
{
if ( aI.nTypeArray[j] == SYMBOLTYPE_CURRENCY )
return TRUE;
}
return FALSE;
}
BOOL ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol,
String& rExtension ) const
{
for ( USHORT j=0; j<nAnzStrings; j++ )
{
if ( aI.nTypeArray[j] == SYMBOLTYPE_CURRENCY )
{
rSymbol = aI.sStrArray[j];
if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == SYMBOLTYPE_CURREXT )
rExtension = aI.sStrArray[j+1];
else
rExtension.Erase();
return TRUE;
}
}
//! kein Erase an rSymbol, rExtension
return FALSE;
}
void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
{
USHORT j;
USHORT nCnt = 0;
for ( j=0; j<nAnzStrings; j++ )
{
switch ( aI.nTypeArray[j] )
{
case SYMBOLTYPE_CURRENCY :
case SYMBOLTYPE_CURRDEL :
case SYMBOLTYPE_CURREXT :
nCnt++;
break;
}
}
rStream << nCnt;
for ( j=0; j<nAnzStrings; j++ )
{
switch ( aI.nTypeArray[j] )
{
case SYMBOLTYPE_CURRENCY :
case SYMBOLTYPE_CURRDEL :
case SYMBOLTYPE_CURREXT :
rStream << j << aI.nTypeArray[j];
break;
}
}
}
void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
{
USHORT nCnt;
rStream >> nCnt;
for ( USHORT j=0; j<nCnt; j++ )
{
USHORT nPos;
short nType;
rStream >> nPos >> nType;
if ( nPos < nAnzStrings )
aI.nTypeArray[nPos] = nType;
}
}
/***********************Funktionen SvNumberformat************************/
enum Sc_FormatSymbolType
{
SYMBOLTYPE_FORMAT = -1, // subformat string
SYMBOLTYPE_COLOR = -2, // color
SYMBOLTYPE_ERROR = -3, // error
SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers
SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible.
SYMBOLTYPE_DBNUM3 = -6,
SYMBOLTYPE_DBNUM4 = -7,
SYMBOLTYPE_DBNUM5 = -8,
SYMBOLTYPE_DBNUM6 = -9,
SYMBOLTYPE_DBNUM7 = -10,
SYMBOLTYPE_DBNUM8 = -11,
SYMBOLTYPE_DBNUM9 = -12,
SYMBOLTYPE_LOCALE = -13,
SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII
SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent
SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ...
SYMBOLTYPE_NATNUM3 = -17,
SYMBOLTYPE_NATNUM4 = -18,
SYMBOLTYPE_NATNUM5 = -19,
SYMBOLTYPE_NATNUM6 = -20,
SYMBOLTYPE_NATNUM7 = -21,
SYMBOLTYPE_NATNUM8 = -22,
SYMBOLTYPE_NATNUM9 = -23,
SYMBOLTYPE_NATNUM10 = -24,
SYMBOLTYPE_NATNUM11 = -25,
SYMBOLTYPE_NATNUM12 = -26,
SYMBOLTYPE_NATNUM13 = -27,
SYMBOLTYPE_NATNUM14 = -28,
SYMBOLTYPE_NATNUM15 = -29,
SYMBOLTYPE_NATNUM16 = -30,
SYMBOLTYPE_NATNUM17 = -31,
SYMBOLTYPE_NATNUM18 = -32,
SYMBOLTYPE_NATNUM19 = -33
};
SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge )
:
rScan(rSc),
eLnge(eLge),
bStarFlag( FALSE ),
nNewStandardDefined(0)
{
}
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;
for (USHORT i = 0; i < 4; i++)
NumFor[i].Copy(rFormat.NumFor[i]);
}
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 );
}
BOOL lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
{
if ( nSymbolType > 0 )
return TRUE; // conditions
switch ( nSymbolType )
{
case SYMBOLTYPE_COLOR :
case SYMBOLTYPE_DBNUM1 :
case SYMBOLTYPE_DBNUM2 :
case SYMBOLTYPE_DBNUM3 :
case SYMBOLTYPE_DBNUM4 :
case SYMBOLTYPE_DBNUM5 :
case SYMBOLTYPE_DBNUM6 :
case SYMBOLTYPE_DBNUM7 :
case SYMBOLTYPE_DBNUM8 :
case SYMBOLTYPE_DBNUM9 :
case SYMBOLTYPE_LOCALE :
case SYMBOLTYPE_NATNUM0 :
case SYMBOLTYPE_NATNUM1 :
case SYMBOLTYPE_NATNUM2 :
case SYMBOLTYPE_NATNUM3 :
case SYMBOLTYPE_NATNUM4 :
case SYMBOLTYPE_NATNUM5 :
case SYMBOLTYPE_NATNUM6 :
case SYMBOLTYPE_NATNUM7 :
case SYMBOLTYPE_NATNUM8 :
case SYMBOLTYPE_NATNUM9 :
case SYMBOLTYPE_NATNUM10 :
case SYMBOLTYPE_NATNUM11 :
case SYMBOLTYPE_NATNUM12 :
case SYMBOLTYPE_NATNUM13 :
case SYMBOLTYPE_NATNUM14 :
case SYMBOLTYPE_NATNUM15 :
case SYMBOLTYPE_NATNUM16 :
case SYMBOLTYPE_NATNUM17 :
case SYMBOLTYPE_NATNUM18 :
case SYMBOLTYPE_NATNUM19 :
return TRUE;
}
return FALSE;
}
SvNumberformat::SvNumberformat(String& rString,
ImpSvNumberformatScan* pSc,
ImpSvNumberInputScan* pISc,
xub_StrLen& nCheckPos,
LanguageType& eLan,
BOOL bStan)
:
rScan(*pSc),
bStarFlag( FALSE ),
nNewStandardDefined(0)
{
// 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 = FALSE;
fLimit1 = 0.0;
fLimit2 = 0.0;
eOp1 = NUMBERFORMAT_OP_NO;
eOp2 = NUMBERFORMAT_OP_NO;
eType = NUMBERFORMAT_DEFINED;
BOOL bCancel = FALSE;
BOOL bCondition = FALSE;
short eSymbolType;
xub_StrLen nPos = 0;
xub_StrLen nPosOld;
nCheckPos = 0;
String aComment;
// Split into 4 sub formats
USHORT 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 = TRUE;
eOp1 = (SvNumberformatLimitOps) eSymbolType;
}
else if ( nIndex == 1 && bCondition )
eOp2 = (SvNumberformatLimitOps) eSymbolType;
else // error
{
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
if (!bCancel)
{
double fNumber;
xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr);
if (nAnzChars > 0)
{
short F_Type;
if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
( F_Type != NUMBERFORMAT_NUMBER &&
F_Type != NUMBERFORMAT_SCIENTIFIC) )
{
fNumber = 0.0;
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 = TRUE; // break for
nCheckPos = nPos;
}
}
nPosOld = nPos; // position before string
}
else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
switch ( eSymbolType )
{
case SYMBOLTYPE_COLOR :
{
if ( NumFor[nIndex].GetColor() != NULL )
{ // error, more than one color
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
else
{
NumFor[nIndex].SetColor(pSc->GetColor(sStr), sStr);
if (NumFor[nIndex].GetColor() == NULL)
{ // error
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
}
}
break;
case SYMBOLTYPE_NATNUM0 :
case SYMBOLTYPE_NATNUM1 :
case SYMBOLTYPE_NATNUM2 :
case SYMBOLTYPE_NATNUM3 :
case SYMBOLTYPE_NATNUM4 :
case SYMBOLTYPE_NATNUM5 :
case SYMBOLTYPE_NATNUM6 :
case SYMBOLTYPE_NATNUM7 :
case SYMBOLTYPE_NATNUM8 :
case SYMBOLTYPE_NATNUM9 :
case SYMBOLTYPE_NATNUM10 :
case SYMBOLTYPE_NATNUM11 :
case SYMBOLTYPE_NATNUM12 :
case SYMBOLTYPE_NATNUM13 :
case SYMBOLTYPE_NATNUM14 :
case SYMBOLTYPE_NATNUM15 :
case SYMBOLTYPE_NATNUM16 :
case SYMBOLTYPE_NATNUM17 :
case SYMBOLTYPE_NATNUM18 :
case SYMBOLTYPE_NATNUM19 :
{
if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
else
{
sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) );
//! eSymbolType is negative
BYTE nNum = 0 - (eSymbolType - SYMBOLTYPE_NATNUM0);
sStr += String::CreateFromInt32( nNum );
NumFor[nIndex].SetNatNumNum( nNum, FALSE );
}
}
break;
case SYMBOLTYPE_DBNUM1 :
case SYMBOLTYPE_DBNUM2 :
case SYMBOLTYPE_DBNUM3 :
case SYMBOLTYPE_DBNUM4 :
case SYMBOLTYPE_DBNUM5 :
case SYMBOLTYPE_DBNUM6 :
case SYMBOLTYPE_DBNUM7 :
case SYMBOLTYPE_DBNUM8 :
case SYMBOLTYPE_DBNUM9 :
{
if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
else
{
sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) );
//! eSymbolType is negative
BYTE nNum = 1 - (eSymbolType - SYMBOLTYPE_DBNUM1);
sStr += static_cast< sal_Unicode >('0' + nNum);
NumFor[nIndex].SetNatNumNum( nNum, TRUE );
}
}
break;
case SYMBOLTYPE_LOCALE :
{
if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW )
{
bCancel = TRUE; // break for
nCheckPos = nPosOld;
}
else
{
xub_StrLen nTmp = 2;
LanguageType eLang = ImpGetLanguageType( sStr, nTmp );
if ( eLang == LANGUAGE_DONTKNOW )
{
bCancel = 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 == 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 );
USHORT nAnz = pSc->GetAnzResStrings();
if (nAnz == 0) // error
nStrPos = 1;
if (nStrPos == 0) // ok
{
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 = TRUE; // break for
}
}
}
else if (eSymbolType == SYMBOLTYPE_ERROR) // error
{
nCheckPos = nPosOld;
bCancel = TRUE;
}
else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
nCheckPos = nPosOld+1; // error, prefix in string
bCancel = 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 == 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 = 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 ) )
{
USHORT 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 ) )
{
USHORT 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 ) )
{
USHORT 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;
}
short SvNumberformat::ImpNextSymbol(String& rString,
xub_StrLen& nPos,
String& sSymbol)
{
short eType = SYMBOLTYPE_FORMAT;
sal_Unicode cToken;
sal_Unicode cLetter = ' '; // Zwischenergebnis
xub_StrLen nLen = rString.Len();
ScanState eState = SsStart;
sSymbol.Erase();
const String* pKeywords = 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--;
eType = SYMBOLTYPE_FORMAT;
}
else if (cToken == ']')
{
eState = SsStop;
eType = SYMBOLTYPE_ERROR;
}
else if (cToken == ' ') // Skip Blanks
{
rString.Erase(nPos-1,1);
nPos--;
nLen--;
}
else
{
sSymbol += cToken;
eState = SsGetString;
eType = SYMBOLTYPE_FORMAT;
}
}
break;
case SsGetBracketed:
{
switch (cToken)
{
case '<':
case '>':
case '=':
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
cLetter = cToken;
eState = SsGetCon;
switch (cToken)
{
case '<': eType = NUMBERFORMAT_OP_LT; break;
case '>': eType = NUMBERFORMAT_OP_GT; break;
case '=': eType = 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('[');
eType = SYMBOLTYPE_LOCALE;
eState = SsGetPrefix;
}
else
{ // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
eType = SYMBOLTYPE_FORMAT;
eState = SsGetString;
}
sSymbol += cToken;
}
break;
case '~' :
{ // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
eType = 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
eType = (short) (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
eType = SYMBOLTYPE_DBNUM1 - (cDBNum - '1');
eState = SsGetPrefix;
}
else if (cUpper == pKeywords[NF_KEY_H].GetChar(0) || // H
cUpper == pKeywords[NF_KEY_MI].GetChar(0) || // M
cUpper == pKeywords[NF_KEY_S].GetChar(0) ) // S
{
sSymbol += cToken;
eState = SsGetTime;
cLetter = cToken;
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eType = SYMBOLTYPE_COLOR;
eState = SsGetPrefix;
}
}
break;
}
}
break;
case SsGetString:
{
if (cToken == ';')
eState = SsStop;
else
sSymbol += cToken;
}
break;
case SsGetTime:
{
if (cToken == ']')
{
sSymbol += cToken;
eState = SsGetString;
eType = SYMBOLTYPE_FORMAT;
}
else
{
sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0);
if (cUpper == pKeywords[NF_KEY_H].GetChar(0) || // H
cUpper == pKeywords[NF_KEY_MI].GetChar(0) || // M
cUpper == pKeywords[NF_KEY_S].GetChar(0) ) // S
{
if (cLetter == cToken)
{
sSymbol += cToken;
cLetter = ' ';
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eState = SsGetPrefix;
}
}
else
{
sSymbol.EraseAllChars('[');
sSymbol += cToken;
eType = SYMBOLTYPE_COLOR;
eState = SsGetPrefix;
}
}
}
break;
case SsGetCon:
{
switch (cToken)
{
case '<':
{
eState = SsStop;
eType = SYMBOLTYPE_ERROR;
}
break;
case '>':
{
if (cLetter == '<')
{
sSymbol += cToken;
cLetter = ' ';
eState = SsStop;
eType = NUMBERFORMAT_OP_NE;
}
else
{
eState = SsStop;
eType = SYMBOLTYPE_ERROR;
}
}
break;
case '=':
{
if (cLetter == '<')
{
sSymbol += cToken;
cLetter = ' ';
eType = NUMBERFORMAT_OP_LE;
}
else if (cLetter == '>')
{
sSymbol += cToken;
cLetter = ' ';
eType = NUMBERFORMAT_OP_GE;
}
else
{
eState = SsStop;
eType = 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 eType;
}
NfHackConversion SvNumberformat::Load( SvStream& rStream,
ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
ImpSvNumberInputScan& rISc )
{
rHdr.StartEntry();
USHORT nOp1, nOp2;
SvNumberformat::LoadString( rStream, sFormatstring );
rStream >> eType >> fLimit1 >> fLimit2
>> nOp1 >> nOp2 >> bStandard >> bIsUsed;
NfHackConversion eHackConversion = NF_CONVERT_NONE;
BOOL bOldConvert = 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 (USHORT 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;
BOOL bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic &&
(nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND );
BOOL bNewCurrencyLoaded = FALSE;
BOOL bNewCurrency = FALSE;
BOOL bGoOn = TRUE;
while ( rHdr.BytesLeft() && bGoOn )
{ // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
USHORT nId;
rStream >> nId;
switch ( nId )
{
case nNewCurrencyVersionId :
{
bNewCurrencyLoaded = TRUE;
rStream >> bNewCurrency;
if ( bNewCurrency )
{
for ( USHORT 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 = 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 );
USHORT nNewStandard = nNewStandardDefined;
// neu parsen etc.
String aStr( sFormatstring );
xub_StrLen nCheckPos;
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, TRUE );
break;
case NF_CONVERT_GERMAN_ENGLISH :
ConvertLanguage( *pHackConverter,
LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, TRUE );
break;
default:
DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
}
}
return eHackConversion;
}
void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
LanguageType eConvertFrom, LanguageType eConvertTo, BOOL bSystem )
{
xub_StrLen nCheckPos;
ULONG 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 ( USHORT 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
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)
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 = FALSE;
}
}
rHdr.StartEntry();
rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() );
rStream << eType << fLimit1 << fLimit2 << (USHORT) eOp1 << (USHORT) eOp2
<< bOldStandard << bIsUsed;
for (USHORT 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 ( USHORT 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();
}
BOOL SvNumberformat::HasNewCurrency() const
{
for ( USHORT j=0; j<4; j++ )
{
if ( NumFor[j].HasNewCurrency() )
return TRUE;
}
return FALSE;
}
BOOL SvNumberformat::GetNewCurrencySymbol( String& rSymbol,
String& rExtension ) const
{
for ( USHORT j=0; j<4; j++ )
{
if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
return TRUE;
}
rSymbol.Erase();
rExtension.Erase();
return FALSE;
}
// static
String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
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, TRUE );
}
void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
{
USHORT nStandardPrec = rScan.GetStandardPrec();
if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_E, nStandardPrec /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0));
else
{
#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
OutString = ::rtl::math::doubleToUString( fNumber,
rtl_math_StringFormat_F, nStandardPrec /*2*/,
GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
if (OutString.GetChar(0) == '-' &&
OutString.GetTokenCount('0') == OutString.Len())
OutString.EraseLeadingChars('-'); // nicht -0
}
return;
}
void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
{
BOOL bModified = 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 = 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;
}
}
BOOL SvNumberformat::GetOutputString(String& sString,
String& OutString,
Color** ppColor)
{
OutString.Erase();
USHORT nIx;
if (eType & NUMBERFORMAT_TEXT)
nIx = 0;
else if (NumFor[3].GetnAnz() > 0)
nIx = 3;
else
{
*ppColor = NULL; // no change of color
return FALSE;
}
*ppColor = NumFor[nIx].GetColor();
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
{
BOOL bRes = FALSE;
const USHORT nAnz = NumFor[nIx].GetnAnz();
for (USHORT i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
case SYMBOLTYPE_DEL :
OutString += sString;
break;
default:
OutString += rInfo.sStrArray[i];
}
}
return bRes;
}
return FALSE;
}
/*
void SvNumberformat::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
ULONG y0, ULONG y1,
ULONG& x2,ULONG& y2)
{
x2 = ((y0+nPrec)/y1)*x1 - x0;
y2 = ((y0+nPrec)/y1)*y1 - y0;
}
*/
ULONG SvNumberformat::ImpGGT(ULONG x, ULONG y)
{
if (y == 0)
return x;
else
{
ULONG z = x%y;
while (z)
{
x = y;
y = z;
z = x%y;
}
return y;
}
}
ULONG SvNumberformat::ImpGGTRound(ULONG x, ULONG y)
{
if (y == 0)
return x;
else
{
ULONG z = x%y;
while ((double)z/(double)y > D_EPS)
{
x = y;
y = z;
z = x%y;
}
return y;
}
}
BOOL SvNumberformat::GetOutputString(double fNumber,
String& OutString,
Color** ppColor)
{
BOOL bRes = FALSE;
OutString.Erase(); // alles loeschen
*ppColor = NULL; // keine Farbaenderung
if (eType & NUMBERFORMAT_LOGICAL)
{
if (fNumber)
OutString = rScan.GetTrueString();
else
OutString = rScan.GetFalseString();
return FALSE;
}
if (eType & NUMBERFORMAT_TEXT && bStandard)
{
ImpGetOutputStandard(fNumber, OutString);
return FALSE;
}
BOOL bHadStandard = FALSE;
if (bStandard) // einzelne Standardformate
{
if (rScan.GetStandardPrec() == 300) // alle Zahlformate InputLine
{
ImpGetOutputInputLine(fNumber, OutString);
return FALSE;
}
switch (eType)
{
case NUMBERFORMAT_NUMBER: // Standardzahlformat
ImpGetOutputStandard(fNumber, OutString);
bHadStandard = TRUE;
break;
case NUMBERFORMAT_DATE:
bRes |= ImpGetDateOutput(fNumber, 0, OutString);
bHadStandard = TRUE;
break;
case NUMBERFORMAT_TIME:
bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
bHadStandard = TRUE;
break;
case NUMBERFORMAT_DATETIME:
bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
bHadStandard = TRUE;
break;
}
}
if ( !bHadStandard )
{
USHORT 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 && fNumber < 0.0 && // negatives Format
IsNegativeRealNegative() ) // ohne Vorzeichen
fNumber = -fNumber; // Vorzeichen eliminieren
*ppColor = NumFor[nIx].GetColor();
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const USHORT nAnz = NumFor[nIx].GetnAnz();
if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
return FALSE; // leer => nichts
else if (nAnz == 0) // sonst Standard-Format
{
ImpGetOutputStandard(fNumber, OutString);
return FALSE;
}
switch (rInfo.eScannedType)
{
case NUMBERFORMAT_TEXT:
case NUMBERFORMAT_DEFINED:
{
for (USHORT i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
OutString += rInfo.sStrArray[i];
break;
case 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
ULONG nFrac, nDiv; // Vorkommaanteil
// Zaehler und Nenner
BOOL bSign = FALSE;
if (fNumber < 0)
{
if (nIx == 0) // nicht in hinteren
bSign = 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 FALSE;
}
if (rInfo.nCntExp == 0)
{
DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
return FALSE;
}
ULONG nBasis = ((ULONG)floor( // 9, 99, 999 ,...
pow(10.0,rInfo.nCntExp))) - 1;
ULONG x0, y0, x1, y1, x2, y2;
if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
{
BOOL bUpperHalf;
if (fNumber > 0.5)
{
bUpperHalf = TRUE;
fNumber -= (fNumber - 0.5) * 2.0;
}
else
bUpperHalf = FALSE;
// Einstieg in Farey-Serie
// finden:
x0 = (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;
ULONG nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
x0 /= nGgt;
y0 /= nGgt; // Einschachteln:
double fTest;
BOOL bStop = FALSE;
while (!bStop)
{
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 = TRUE;
}
else if (y1 == 1)
bStop = 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 = TRUE; // naechste Farey-Zahl
else
{
y1--;
bStop = 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)
{
x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
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
ULONG nGgt;
/*
nDiv = nBasis+1;
nFrac = ((ULONG)floor(0.5 + fNumber *
pow(10.0,rInfo.nCntExp)));
*/
nDiv = 10000000;
nFrac = ((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 = ((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 FALSE;
}
nFrac = (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 );
}
USHORT j = nAnz-1; // letztes Symbol->rueckw.
xub_StrLen k; // Nenner:
bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, SYMBOLTYPE_FRAC);
BOOL bCont = TRUE;
if (rInfo.nTypeArray[j] == 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 = FALSE;
}
// weiter Zaehler:
if ( !bCont )
sFrac.Erase();
else
{
bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, SYMBOLTYPE_FRACBLANK);
if (rInfo.nTypeArray[j] == SYMBOLTYPE_FRACBLANK)
{
sFrac.Insert(rInfo.sStrArray[j],0);
if ( j )
j--;
else
bCont = 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:
{
BOOL bSign = FALSE;
if (fNumber < 0)
{
if (nIx == 0) // nicht in hinteren
bSign = 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 );
}
}
USHORT j = nAnz-1; // last symbol
xub_StrLen k;
bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, SYMBOLTYPE_EXP);
while (k > 0) // erase leading zeros
{
k--;
if (ExpStr.GetChar(k) == '0')
ExpStr.Erase(0,1);
}
BOOL bCont = TRUE;
if (rInfo.nTypeArray[j] == 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 = 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;
}
BOOL SvNumberformat::ImpGetTimeOutput(double fNumber,
USHORT nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
BOOL bCalendarSet = FALSE;
double fNumberOrig = fNumber;
BOOL bRes = FALSE;
BOOL bSign = FALSE;
if (fNumber < 0.0)
{
fNumber = -fNumber;
if (nIx == 0)
bSign = TRUE;
}
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
if (rInfo.bThousand) // []-Format
{
if (fNumber > 1.0E10) // zu gross
{
OutString = rScan.GetErrorString();
return FALSE;
}
}
else
fNumber -= floor(fNumber); // sonst Datum abtrennen
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 = TRUE;
nCntPost = 7;
}
else
{
bInputLine = 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 = FALSE; // nicht -00:00:00
if( floor( fTime ) > _D_MAX_U_LONG_ )
{
OutString = rScan.GetErrorString();
return FALSE;
}
ULONG nSeconds = (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
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 USHORT nAnz = NumFor[nIx].GetnAnz();
for (USHORT i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
OutString += rInfo.sStrArray[i];
break;
case SYMBOLTYPE_DIGIT:
{
xub_StrLen nLen = ( bInputLine && i > 0 &&
rInfo.nTypeArray[i-1] == SYMBOLTYPE_STRING ?
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 = 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;
}
BOOL SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
{
if ( GetCal().getUniqueID() != Gregorian::get() )
return FALSE;
const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
const USHORT nAnz = rNumFor.GetnAnz();
USHORT i;
for ( i = 0; i < nAnz; i++ )
{
switch ( rInfo.nTypeArray[i] )
{
case SYMBOLTYPE_CALENDAR :
return FALSE;
break;
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 TRUE;
break;
}
}
return 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 );
}
}
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 TRUE;
}
}
return FALSE;
}
BOOL SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
{
const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
const USHORT nAnz = rNumFor.GetnAnz();
for ( USHORT i = 0; i < nAnz; i++ )
{
if ( rInfo.nTypeArray[i] == 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 TRUE;
}
}
return 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 );
}
BOOL SvNumberformat::ImpGetDateOutput(double fNumber,
USHORT nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
BOOL bRes = FALSE;
CalendarWrapper& rCal = GetCal();
double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
fNumber += fDiff;
rCal.setLocalDateTime( fNumber );
String aOrgCalendar; // empty => not changed yet
double fOrgDateTime;
BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
bOtherCalendar = FALSE;
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const USHORT nAnz = NumFor[nIx].GetnAnz();
sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
for (USHORT i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case 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 SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
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;
}
BOOL SvNumberformat::ImpGetDateTimeOutput(double fNumber,
USHORT nIx,
String& OutString)
{
using namespace ::com::sun::star::i18n;
BOOL bRes = FALSE;
CalendarWrapper& rCal = GetCal();
double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
fNumber += fDiff;
rCal.setLocalDateTime( fNumber );
String aOrgCalendar; // empty => not changed yet
double fOrgDateTime;
BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
if ( bOtherCalendar )
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
bOtherCalendar = FALSE;
sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
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 = TRUE;
nCntPost = 7;
}
else
{
bInputLine = FALSE;
nCntPost = xub_StrLen(rInfo.nCntPost);
}
double fTime = (fNumber - floor( fNumber )) * 86400.0;
fTime = ::rtl::math::round( fTime, int(nCntPost) );
ULONG nSeconds = (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
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 USHORT nAnz = NumFor[nIx].GetnAnz();
for (USHORT i = 0; i < nAnz; i++)
{
switch (rInfo.nTypeArray[i])
{
case 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 SYMBOLTYPE_STAR:
if( bStarFlag )
{
OutString += (sal_Unicode) 0x1B;
OutString += rInfo.sStrArray[i].GetChar(1);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
InsertBlanks( OutString, OutString.Len(),
rInfo.sStrArray[i].GetChar(1) );
break;
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
OutString += rInfo.sStrArray[i];
break;
case SYMBOLTYPE_DIGIT:
{
xub_StrLen nLen = ( bInputLine && i > 0 &&
rInfo.nTypeArray[i-1] == SYMBOLTYPE_STRING ?
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
{
if (nMin < 10)
OutString += '0';
OutString += ImpIntToString( nIx, nMin );
}
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;
}
BOOL SvNumberformat::ImpGetNumberOutput(double fNumber,
USHORT nIx,
String& OutString)
{
BOOL bRes = FALSE;
BOOL bSign;
if (fNumber < 0.0)
{
if (nIx == 0) // nicht in hinteren
bSign = TRUE; // Formaten
else
bSign = FALSE;
fNumber = -fNumber;
}
else
{
bSign = 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 FALSE;
}
}
USHORT i, j;
xub_StrLen k;
String sStr;
long nPrecExp;
BOOL bInteger = FALSE;
if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
{ // special formatting only if no GENERAL keyword in format code
const USHORT 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 = TRUE;
sStr.Erase( nPoint, 1 ); // . herausnehmen
}
if (bSign &&
(sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000
bSign = 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)
{
BOOL bTrailing = TRUE; // ob Endnullen?
BOOL bFilled = FALSE; // ob aufgefuellt wurde ?
short nType;
while (j > 0 && // rueckwaerts
(nType = rInfo.nTypeArray[j]) != SYMBOLTYPE_DECSEP)
{
switch ( nType )
{
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
/*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
sStr.Insert(rInfo.sStrArray[j],k);
break;
case SYMBOLTYPE_THSEP:
if (rInfo.nThousand == 0)
sStr.Insert(rInfo.sStrArray[j],k);
break;
case 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 = FALSE;
if (bTrailing)
{
if ( c == '0' )
bFilled = TRUE;
else if ( c == '-' )
{
if ( bInteger )
sStr.SetChar( k, '-' );
bFilled = TRUE;
}
else if ( c == '?' )
{
sStr.SetChar( k, ' ' );
bFilled = 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;
}
BOOL SvNumberformat::ImpNumberFillWithThousands(
String& sStr, // number string
double& rNumber, // number
xub_StrLen k, // position within string
USHORT j, // position of format code string
USHORT nIx, // subformat index
USHORT nDigCnt) // count of digits in format
{
BOOL bRes = FALSE;
BOOL bLeading = FALSE; // leading characters
xub_StrLen nAnzLeadingChars = 0; // count of leading zeros or blanks
USHORT nThousandCnt = 0; // count of digits before leftmost separator
xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
USHORT nDigitCount = 0; // count of integer digits
BOOL bStop = FALSE;
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
// no normal thousands separators if number divided by thousands
BOOL bDoThousands = (rInfo.nThousand == 0);
const String& rThousandSep = GetFormatter().GetNumThousandSep();
while (!bStop) // backwards
{
if (j == 0)
bStop = TRUE;
switch (rInfo.nTypeArray[j])
{
case SYMBOLTYPE_DECSEP:
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
sStr.Insert(rInfo.sStrArray[j],k);
if ( k == 0 )
nLeadingStringChars += rInfo.sStrArray[j].Len();
break;
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
/*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case 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.
if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
bDoThousands = ((j == 0) ||
(rInfo.nTypeArray[j-1] != SYMBOLTYPE_DIGIT) ||
(rInfo.nTypeArray[j+1] == SYMBOLTYPE_DIGIT));
if ( bDoThousands && k > 0 )
{
sStr.Insert(rInfo.sStrArray[j],k);
nThousandCnt = 0;
}
}
break;
case 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++;
const sal_Unicode c = *p;
//! TODO: what if rThousandSep is more than one charater? => change this damned backward loop
if ( c == rThousandSep.GetChar(0) && rThousandSep.Len() == 1 )
{
nDigitCount--;
if (k > 0)
{
sStr.Insert(c,k);
nThousandCnt = 0;
}
}
else if (k > 0)
{
k--;
nThousandCnt++;
}
else
bLeading = TRUE;
if (bLeading)
{
if (c == '?')
{
sStr.Insert(' ',0);
nAnzLeadingChars++;
}
else if (c == '0')
{
sStr.Insert('0',0);
nAnzLeadingChars++;
}
}
if (nDigitCount == nDigCnt && k > 0)
{ // more digits than specified
ImpDigitFill(sStr, 0, k, nIx, nThousandCnt);
}
}
}
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 += nLeadingStringChars + nAnzLeadingChars;
if (k > nLeadingStringChars)
ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nThousandCnt);
return bRes;
}
void SvNumberformat::ImpDigitFill(
String& sStr, // number string
xub_StrLen nStart, // start of digits
xub_StrLen& k, // position within string
USHORT nIx, // subformat index
USHORT nThousandCnt ) // count of digits before leftmost separator
{
if (NumFor[nIx].Info().bThousand) // noch Ziffern da
{ // Aufuellen mit .
const String& rThousandSep = GetFormatter().GetNumThousandSep();
while (k > nStart)
{
if (nThousandCnt == 3)
{ // hier muss . dazwischen
sStr.Insert( rThousandSep, k );
nThousandCnt = 1;
}
else
nThousandCnt++;
k--;
}
}
else // einfach ueberspringen
k = nStart;
}
BOOL SvNumberformat::ImpNumberFill(String& sStr, // Zahlstring
double& rNumber, // Zahl fuer Standard
xub_StrLen& k, // Zeigen darin
USHORT& j, // Symbolzeiger
USHORT nIx, // Teilformatstring
short eSymbolType ) // Abbruchtyp
{
BOOL bRes = FALSE;
k = sStr.Len(); // hinter letzter Ziffer
BOOL bLeading = FALSE; // fuehrende ? oder 0
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const String& rThousandSep = GetFormatter().GetNumThousandSep();
short nType;
while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
{ // rueckwaerts:
switch ( nType )
{
case SYMBOLTYPE_STAR:
if( bStarFlag )
{
sStr.Insert( sal_Unicode(0x1B), k++ );
sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
bRes = TRUE;
}
break;
case SYMBOLTYPE_BLANK:
k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
break;
case 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;
//! TODO: what if rThousandSep is more than one charater? => change this damned backward loop
if ( c == rThousandSep.GetChar(0) && rThousandSep.Len() == 1 )
{
if (k > 0)
sStr.Insert(c,k);
}
else if (k > 0)
k--;
else
bLeading = TRUE;
if (bLeading)
{
if (c == '?')
sStr.Insert(' ',0);
else if (c == '0')
sStr.Insert('0',0);
} // of if
} // 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(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(BOOL& bThousand,
BOOL& IsRed,
USHORT& nPrecision,
USHORT& 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 = TRUE;
else
IsRed = FALSE;
}
void SvNumberformat::GetNumForInfo( USHORT nNumFor, short& rScannedType,
BOOL& bThousand, USHORT& nPrecision, USHORT& 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;
BOOL bStop = FALSE;
USHORT i = 0;
const USHORT nAnz = NumFor[nNumFor].GetnAnz();
while (!bStop && i < nAnz)
{
short nType = rInfo.nTypeArray[i];
if ( nType == SYMBOLTYPE_DIGIT)
{
register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
while ( *p == '#' )
p++;
while ( *p++ == '0' )
nAnzLeading++;
}
else if (nType == SYMBOLTYPE_DECSEP)
bStop = TRUE;
i++;
}
}
}
const String* SvNumberformat::GetNumForString( USHORT nNumFor, USHORT nPos,
BOOL bString /* = FALSE */ ) const
{
if ( nNumFor > 3 )
return NULL;
USHORT 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 != SYMBOLTYPE_STRING) &&
(*pType != SYMBOLTYPE_CURRENCY) )
{
pType--;
nPos--;
}
if ( (*pType != SYMBOLTYPE_STRING) && (*pType != 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 != SYMBOLTYPE_STRING) &&
(*pType != SYMBOLTYPE_CURRENCY) )
{
pType++;
nPos++;
}
if ( nPos >= nAnz || ((*pType != SYMBOLTYPE_STRING) &&
(*pType != SYMBOLTYPE_CURRENCY)) )
return NULL;
}
return &NumFor[nNumFor].Info().sStrArray[nPos];
}
short SvNumberformat::GetNumForType( USHORT nNumFor, USHORT nPos,
BOOL bString /* = FALSE */ ) const
{
if ( nNumFor > 3 )
return 0;
USHORT 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 != SYMBOLTYPE_STRING) &&
(*pType != SYMBOLTYPE_CURRENCY) )
{
pType--;
nPos--;
}
if ( (*pType != SYMBOLTYPE_STRING) && (*pType != 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 != SYMBOLTYPE_STRING) &&
(*pType != SYMBOLTYPE_CURRENCY) )
{
pType++;
nPos++;
}
if ( (*pType != SYMBOLTYPE_STRING) && (*pType != SYMBOLTYPE_CURRENCY) )
return 0;
}
return NumFor[nNumFor].Info().nTypeArray[nPos];
}
BOOL SvNumberformat::IsNegativeWithoutSign() const
{
if ( IsNegativeRealNegative() )
{
const String* pStr = GetNumForString( 1, 0, TRUE );
if ( pStr )
return !HasStringNegativeSign( *pStr );
}
return FALSE;
}
DateFormat SvNumberformat::GetDateOrder() const
{
if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
{
short const * const pType = NumFor[0].Info().nTypeArray;
USHORT nAnz = NumFor[0].GetnAnz();
for ( USHORT j=0; j<nAnz; j++ )
{
switch ( pType[j] )
{
case NF_KEY_D :
case NF_KEY_DD :
return DMY;
break;
case NF_KEY_M :
case NF_KEY_MM :
case NF_KEY_MMM :
case NF_KEY_MMMM :
case NF_KEY_MMMMM :
return MDY;
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 :
return YMD;
break;
}
}
}
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;
USHORT nAnz = NumFor[0].GetnAnz();
sal_uInt32 nShift = 0;
for ( USHORT j=0; j<nAnz && nShift < 24; j++ )
{
switch ( pType[j] )
{
case NF_KEY_D :
case NF_KEY_DD :
nRet = (nRet << nShift) | 'D';
nShift += 8;
break;
case NF_KEY_M :
case NF_KEY_MM :
case NF_KEY_MMM :
case NF_KEY_MMMM :
case NF_KEY_MMMMM :
nRet = (nRet << nShift) | 'M';
nShift += 8;
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 << nShift) | 'Y';
nShift += 8;
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( USHORT 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;
}
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& rLoc,
BOOL bDontQuote ) const
{
String aStr;
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 );
BOOL bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
// from now on bDefault[] values are used to append empty subformats at the end
bDefault[3] = FALSE;
if ( !bDefaults )
{ // conditions specified
if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
bDefault[0] = bDefault[1] = TRUE; // [];x
else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
NumFor[2].GetnAnz() == 0 )
bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = TRUE; // [];[];;
// nothing to do if conditions specified for every subformat
}
else if ( bDefault[0] )
bDefault[0] = FALSE; // a single unconditional subformat is never delimited
else
{
if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
bDefault[3] = TRUE; // special cases x;x;; and ;x;;
for ( int i=0; i<3 && !bDefault[i]; ++i )
bDefault[i] = 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, rLoc.getNumDecimalSep() );
break;
case 1 :
lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
fLimit2, rLoc.getNumDecimalSep() );
break;
}
}
const String& rColorName = NumFor[n].GetColorName();
if ( rColorName.Len() )
{
const String* pKey = rScan.GetKeywords() + NF_KEY_FIRSTCOLOR;
for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++, pKey++ )
{
if ( *pKey == rColorName )
{
aPrefix += '[';
aPrefix += rKeywords[j];
aPrefix += ']';
break; // for
}
}
}
USHORT nAnz = NumFor[n].GetnAnz();
if ( nSem && (nAnz || aPrefix.Len()) )
{
for ( ; nSem; --nSem )
aStr += ';';
for ( ; nSub <= n; ++nSub )
bDefault[nSub] = FALSE;
}
if ( aPrefix.Len() )
aStr += aPrefix;
if ( nAnz )
{
const short* pType = NumFor[n].Info().nTypeArray;
const String* pStr = NumFor[n].Info().sStrArray;
for ( USHORT 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 += rLoc.getLongDateDayOfWeekSep();
}
else
{
switch ( pType[j] )
{
case SYMBOLTYPE_DECSEP :
aStr += rLoc.getNumDecimalSep();
break;
case SYMBOLTYPE_THSEP :
aStr += rLoc.getNumThousandSep();
break;
case SYMBOLTYPE_STRING :
if( bDontQuote )
aStr += pStr[j];
else if ( pStr[j].Len() == 1 )
{
sal_Unicode cx = pStr[j].GetChar(0);
switch ( cx )
{
case '+' :
case '-' :
case ' ' :
case '%' :
aStr += cx; // don't escape simple forms
break;
default:
// #i13399# Don't escape separators of
// target locale.
//! TODO: without binary filter all
// separators should become some
// SYMBOLTYPE_...SEP, which would also
// ease handling of
// PutandConvertEntry() and similar.
if ( !(((eType & NUMBERFORMAT_DATE) != 0)
&& cx == rLoc.getDateSep().GetChar(0))
&& !(((eType & NUMBERFORMAT_TIME) != 0)
&& (cx == rLoc.getTimeSep().GetChar(0))
|| cx == rLoc.getTime100SecSep().GetChar(0)))
aStr += '\\';
aStr += cx;
}
}
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, USHORT 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(
SvNumberFormatter::ConvertLanguageToLocale( rNum.GetLang() ) );
rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
aLocale, rNum.GetNatNum() );
}
void SvNumberformat::GetNatNumXml(
com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
USHORT nNumFor ) const
{
if ( nNumFor <= 3 )
{
const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
if ( rNum.IsSet() )
{
com::sun::star::lang::Locale aLocale(
SvNumberFormatter::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
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 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 TRUE;
} while ( *p == ' ' && ++p < pEnd );
p = pEnd - 1;
do
{ // Ende
if ( *p == '-' )
return TRUE;
} while ( *p == ' ' && pBeg < --p );
return 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();
BOOL bInString = FALSE;
BOOL bEscaped = FALSE;
BOOL bFound = 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 = TRUE;
nPos = p - rStr.GetBuffer();
}
break;
}
if ( bEscaped && *p != '\\' )
bEscaped = FALSE;
++p;
}
if ( bFound )
rStr.Erase( nPos );
}
// static
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 FALSE;
register const sal_Unicode* p0 = rStr.GetBuffer();
register const sal_Unicode* p = p0;
register const sal_Unicode* p1 = p0 + nPos;
BOOL bQuoted = FALSE;
while ( p <= p1 )
{
if ( *p == cQuote )
{
if ( p == p0 )
bQuoted = TRUE;
else if ( bQuoted )
{
if ( *(p-1) != cEscIn )
bQuoted = FALSE;
}
else
{
if ( *(p-1) != cEscOut )
bQuoted = 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 p - p0;
p++;
}
return nLen; // String Ende
}
USHORT SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor ) const
{
USHORT nCnt = 0;
USHORT nAnz = NumFor[nNumFor].GetnAnz();
short const * const pType = NumFor[nNumFor].Info().nTypeArray;
for ( USHORT j=0; j<nAnz; ++j )
{
switch ( pType[j] )
{
case SYMBOLTYPE_STRING:
case SYMBOLTYPE_CURRENCY:
++nCnt;
break;
}
}
return nCnt;
}