blob: afbeca6cdb86d64728b1fe284812ffc44786ded6 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svl.hxx"
#ifndef GCC
#endif
#include <stdlib.h>
#include <tools/debug.hxx>
#include <i18npool/mslangid.hxx>
#include <unotools/charclass.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/numberformatcodewrapper.hxx>
#include <rtl/instance.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <unotools/digitgroupingiterator.hxx>
#define _ZFORSCAN_CXX
#include "zforscan.hxx"
#undef _ZFORSCAN_CXX
#include <svl/nfsymbol.hxx>
using namespace svt;
const sal_Unicode cNonBreakingSpace = 0xA0;
namespace
{
struct ImplEnglishColors
{
const String* operator()()
{
static const String aEnglishColors[NF_MAX_DEFAULT_COLORS] =
{
String( RTL_CONSTASCII_USTRINGPARAM( "BLACK" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "BLUE" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "GREEN" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "CYAN" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "RED" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "MAGENTA" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "BROWN" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "GREY" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "YELLOW" ) ),
String( RTL_CONSTASCII_USTRINGPARAM( "WHITE" ) )
};
return &aEnglishColors[0];
}
};
struct theEnglishColors
: public rtl::StaticAggregate< const String, ImplEnglishColors> {};
}
ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP )
{
pFormatter = pFormatterP;
bConvertMode = sal_False;
//! All keywords MUST be UPPERCASE!
sKeyword[NF_KEY_E].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) ); // Exponent
sKeyword[NF_KEY_AMPM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AM/PM" ) ); // AM/PM
sKeyword[NF_KEY_AP].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "A/P" ) ); // AM/PM short
sKeyword[NF_KEY_MI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // Minute
sKeyword[NF_KEY_MMI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // Minute 02
sKeyword[NF_KEY_S].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "S" ) ); // Second
sKeyword[NF_KEY_SS].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SS" ) ); // Second 02
sKeyword[NF_KEY_Q].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Q" ) ); // Quarter short 'Q'
sKeyword[NF_KEY_QQ].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "QQ" ) ); // Quarter long
sKeyword[NF_KEY_NN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NN" ) ); // Day of week short
sKeyword[NF_KEY_NNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNN" ) ); // Day of week long
sKeyword[NF_KEY_NNNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNNN" ) ); // Day of week long incl. separator
sKeyword[NF_KEY_WW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WW" ) ); // Week of year
sKeyword[NF_KEY_CCC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CCC" ) ); // Currency abbreviation
bKeywordsNeedInit = sal_True; // locale dependent keywords
bCompatCurNeedInit = sal_True; // locale dependent compatibility currency strings
StandardColor[0] = Color(COL_BLACK);
StandardColor[1] = Color(COL_LIGHTBLUE);
StandardColor[2] = Color(COL_LIGHTGREEN);
StandardColor[3] = Color(COL_LIGHTCYAN);
StandardColor[4] = Color(COL_LIGHTRED);
StandardColor[5] = Color(COL_LIGHTMAGENTA);
StandardColor[6] = Color(COL_BROWN);
StandardColor[7] = Color(COL_GRAY);
StandardColor[8] = Color(COL_YELLOW);
StandardColor[9] = Color(COL_WHITE);
pNullDate = new Date(30,12,1899);
nStandardPrec = 2;
sErrStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###" ) );
Reset();
}
ImpSvNumberformatScan::~ImpSvNumberformatScan()
{
delete pNullDate;
Reset();
}
void ImpSvNumberformatScan::ChangeIntl()
{
bKeywordsNeedInit = sal_True;
bCompatCurNeedInit = sal_True;
// may be initialized by InitSpecialKeyword()
sKeyword[NF_KEY_TRUE].Erase();
sKeyword[NF_KEY_FALSE].Erase();
}
void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const
{
switch ( eIdx )
{
case NF_KEY_TRUE :
((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] =
pFormatter->GetCharClass()->upper(
pFormatter->GetLocaleData()->getTrueWord() );
if ( !sKeyword[NF_KEY_TRUE].Len() )
{
DBG_ERRORFILE( "InitSpecialKeyword: TRUE_WORD?" );
((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "sal_True" ) );
}
break;
case NF_KEY_FALSE :
((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] =
pFormatter->GetCharClass()->upper(
pFormatter->GetLocaleData()->getFalseWord() );
if ( !sKeyword[NF_KEY_FALSE].Len() )
{
DBG_ERRORFILE( "InitSpecialKeyword: FALSE_WORD?" );
((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "sal_False" ) );
}
break;
default:
DBG_ERRORFILE( "InitSpecialKeyword: unknown request" );
}
}
void ImpSvNumberformatScan::InitCompatCur() const
{
ImpSvNumberformatScan* pThis = (ImpSvNumberformatScan*)this;
// currency symbol for old style ("automatic") compatibility format codes
pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev );
// currency symbol upper case
pThis->sCurString = pFormatter->GetCharClass()->upper( sCurSymbol );
bCompatCurNeedInit = sal_False;
}
void ImpSvNumberformatScan::InitKeywords() const
{
if ( !bKeywordsNeedInit )
return ;
((ImpSvNumberformatScan*)this)->SetDependentKeywords();
bKeywordsNeedInit = sal_False;
}
/** Extract the name of General, Standard, Whatever, ignoring leading modifiers
such as [NatNum1]. */
static String lcl_extractStandardGeneralName( const ::rtl::OUString & rCode )
{
String aStr;
const sal_Unicode* p = rCode.getStr();
const sal_Unicode* const pStop = p + rCode.getLength();
const sal_Unicode* pBeg = p; // name begins here
bool bMod = false;
bool bDone = false;
while (p < pStop && !bDone)
{
switch (*p)
{
case '[':
bMod = true;
break;
case ']':
if (bMod)
{
bMod = false;
pBeg = p+1;
}
// else: would be a locale data error, easily to be spotted in
// UI dialog
break;
case ';':
if (!bMod)
{
bDone = true;
--p; // put back, increment by one follows
}
break;
}
++p;
if (bMod)
pBeg = p;
}
if (pBeg < p)
aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg);
return aStr;
}
void ImpSvNumberformatScan::SetDependentKeywords()
{
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
const CharClass* pCharClass = pFormatter->GetCharClass();
const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData();
// #80023# be sure to generate keywords for the loaded Locale, not for the
// requested Locale, otherwise number format codes might not match
lang::Locale aLoadedLocale = pLocaleData->getLoadedLocale();
LanguageType eLang = MsLangId::convertLocaleToLanguage( aLoadedLocale );
NumberFormatCodeWrapper aNumberFormatCode( pFormatter->GetServiceManager(), aLoadedLocale );
i18n::NumberFormatCode aFormat = aNumberFormatCode.getFormatCode( NF_NUMBER_STANDARD );
sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code);
sKeyword[NF_KEY_GENERAL] = pCharClass->upper( sNameStandardFormat );
// preset new calendar keywords
sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAA" ) );
sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
sKeyword[NF_KEY_EC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) );
sKeyword[NF_KEY_EEC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EE" ) );
sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
sKeyword[NF_KEY_R].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "R" ) );
sKeyword[NF_KEY_RR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RR" ) );
// Thai T NatNum special. Other locale's small letter 't' results in upper
// case comparison not matching but length does in conversion mode. Ugly.
if (eLang == LANGUAGE_THAI)
sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T"));
else
sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "t"));
switch ( eLang )
{
case LANGUAGE_GERMAN:
case LANGUAGE_GERMAN_SWISS:
case LANGUAGE_GERMAN_AUSTRIAN:
case LANGUAGE_GERMAN_LUXEMBOURG:
case LANGUAGE_GERMAN_LIECHTENSTEIN:
{
//! all capital letters
sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // month 1
sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // month 01
sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) ); // month Jan
sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) ); // month Januar
sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );// month J
sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) ); // hour 2
sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) ); // hour 02
sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTT" ) );
sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTTT" ) );
sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "LOGISCH" ) );
sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "FARBE" ) );
sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SCHWARZ" ) );
sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLAU" ) );
sKeyword[NF_KEY_GREEN] = UniString( "GR" "\xDC" "N", RTL_TEXTENCODING_ISO_8859_1 );
sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "ROT" ) );
sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BRAUN" ) );
sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GRAU" ) );
sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GELB" ) );
sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WEISS" ) );
}
break;
default:
{
// day
switch ( eLang )
{
case LANGUAGE_ITALIAN :
case LANGUAGE_ITALIAN_SWISS :
sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGGG" ) );
// must exchange the era code, same as Xcl
sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "X" ) );
sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XX" ) );
sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XXX" ) );
break;
case LANGUAGE_FRENCH :
case LANGUAGE_FRENCH_BELGIAN :
case LANGUAGE_FRENCH_CANADIAN :
case LANGUAGE_FRENCH_SWISS :
case LANGUAGE_FRENCH_LUXEMBOURG :
case LANGUAGE_FRENCH_MONACO :
sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "J" ) );
sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJ" ) );
sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
break;
case LANGUAGE_FINNISH :
sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "P" ) );
sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PP" ) );
sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPP" ) );
sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPPP" ) );
break;
default:
sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D" ) );
sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DD" ) );
sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDD" ) );
sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDDD" ) );
}
// month
switch ( eLang )
{
case LANGUAGE_FINNISH :
sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "K" ) );
sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KK" ) );
sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKK" ) );
sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKK" ) );
sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKKK" ) );
break;
default:
sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) );
sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) );
sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) );
sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) );
sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );
}
// year
switch ( eLang )
{
case LANGUAGE_ITALIAN :
case LANGUAGE_ITALIAN_SWISS :
case LANGUAGE_FRENCH :
case LANGUAGE_FRENCH_BELGIAN :
case LANGUAGE_FRENCH_CANADIAN :
case LANGUAGE_FRENCH_SWISS :
case LANGUAGE_FRENCH_LUXEMBOURG :
case LANGUAGE_FRENCH_MONACO :
case LANGUAGE_PORTUGUESE :
case LANGUAGE_PORTUGUESE_BRAZILIAN :
case LANGUAGE_SPANISH_MODERN :
case LANGUAGE_SPANISH_DATED :
case LANGUAGE_SPANISH_MEXICAN :
case LANGUAGE_SPANISH_GUATEMALA :
case LANGUAGE_SPANISH_COSTARICA :
case LANGUAGE_SPANISH_PANAMA :
case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC :
case LANGUAGE_SPANISH_VENEZUELA :
case LANGUAGE_SPANISH_COLOMBIA :
case LANGUAGE_SPANISH_PERU :
case LANGUAGE_SPANISH_ARGENTINA :
case LANGUAGE_SPANISH_ECUADOR :
case LANGUAGE_SPANISH_CHILE :
case LANGUAGE_SPANISH_URUGUAY :
case LANGUAGE_SPANISH_PARAGUAY :
case LANGUAGE_SPANISH_BOLIVIA :
case LANGUAGE_SPANISH_EL_SALVADOR :
case LANGUAGE_SPANISH_HONDURAS :
case LANGUAGE_SPANISH_NICARAGUA :
case LANGUAGE_SPANISH_PUERTO_RICO :
sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AA" ) );
sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
// must exchange the day of week name code, same as Xcl
sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOO" ) );
sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOOO" ) );
break;
case LANGUAGE_DUTCH :
case LANGUAGE_DUTCH_BELGIAN :
sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
break;
case LANGUAGE_FINNISH :
sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VV" ) );
sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VVVV" ) );
break;
default:
sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YY" ) );
sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YYYY" ) );
}
// hour
switch ( eLang )
{
case LANGUAGE_DUTCH :
case LANGUAGE_DUTCH_BELGIAN :
sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "U" ) );
sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "UU" ) );
break;
case LANGUAGE_FINNISH :
case LANGUAGE_SWEDISH :
case LANGUAGE_SWEDISH_FINLAND :
case LANGUAGE_DANISH :
case LANGUAGE_NORWEGIAN :
case LANGUAGE_NORWEGIAN_BOKMAL :
case LANGUAGE_NORWEGIAN_NYNORSK :
sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
break;
default:
sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) );
sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) );
}
// boolean
sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BOOLEAN" ) );
// colours
sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "COLOR" ) );
sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLACK" ) );
sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLUE" ) );
sKeyword[NF_KEY_GREEN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREEN" ) );
sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RED" ) );
sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BROWN" ) );
sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREY" ) );
sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YELLOW" ) );
sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WHITE" ) );
}
break;
}
// boolean keyords
InitSpecialKeyword( NF_KEY_TRUE );
InitSpecialKeyword( NF_KEY_FALSE );
// compatibility currency strings
InitCompatCur();
}
void ImpSvNumberformatScan::ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear)
{
if ( pNullDate )
*pNullDate = Date(nDay, nMonth, nYear);
else
pNullDate = new Date(nDay, nMonth, nYear);
}
void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec)
{
nStandardPrec = nPrec;
}
Color* ImpSvNumberformatScan::GetColor(String& sStr)
{
String sString = pFormatter->GetCharClass()->upper(sStr);
const NfKeywordTable & rKeyword = GetKeywords();
size_t i = 0;
while (i < NF_MAX_DEFAULT_COLORS &&
sString != rKeyword[NF_KEY_FIRSTCOLOR+i] )
i++;
if ( i >= NF_MAX_DEFAULT_COLORS )
{
const String* pEnglishColors = theEnglishColors::get();
size_t j = 0;
while ( j < NF_MAX_DEFAULT_COLORS &&
sString != pEnglishColors[j] )
++j;
if ( j < NF_MAX_DEFAULT_COLORS )
i = j;
}
Color* pResult = NULL;
if (i >= NF_MAX_DEFAULT_COLORS)
{
const String& rColorWord = rKeyword[NF_KEY_COLOR];
xub_StrLen nPos = sString.Match(rColorWord);
if (nPos > 0)
{
sStr.Erase(0, nPos);
sStr.EraseLeadingChars();
sStr.EraseTrailingChars();
if (bConvertMode)
{
pFormatter->ChangeIntl(eNewLnge);
sStr.Insert( GetKeywords()[NF_KEY_COLOR], 0 ); // Color -> FARBE
pFormatter->ChangeIntl(eTmpLnge);
}
else
sStr.Insert(rColorWord,0);
sString.Erase(0, nPos);
sString.EraseLeadingChars();
sString.EraseTrailingChars();
if ( CharClass::isAsciiNumeric( sString ) )
{
long nIndex = sString.ToInt32();
if (nIndex > 0 && nIndex <= 64)
pResult = pFormatter->GetUserDefColor((sal_uInt16)nIndex-1);
}
}
}
else
{
sStr.Erase();
if (bConvertMode)
{
pFormatter->ChangeIntl(eNewLnge);
sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot
pFormatter->ChangeIntl(eTmpLnge);
}
else
sStr = rKeyword[NF_KEY_FIRSTCOLOR+i];
pResult = &(StandardColor[i]);
}
return pResult;
}
short ImpSvNumberformatScan::GetKeyWord( const String& sSymbol, xub_StrLen nPos )
{
String sString = pFormatter->GetCharClass()->toUpper( sSymbol, nPos, sSymbol.Len() - nPos );
const NfKeywordTable & rKeyword = GetKeywords();
// #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
if ( sString.Search( rKeyword[NF_KEY_GENERAL] ) == 0 )
return NF_KEY_GENERAL;
//! MUST be a reverse search to find longer strings first
short i = NF_KEYWORD_ENTRIES_COUNT-1;
sal_Bool bFound = sal_False;
for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
{
bFound = sString.Search(rKeyword[i]) == 0;
if ( bFound )
{
break;
}
}
// new keywords take precedence over old keywords
if ( !bFound )
{ // skip the gap of colors et al between new and old keywords and search on
i = NF_KEY_LASTKEYWORD;
while ( i > 0 && sString.Search(rKeyword[i]) != 0 )
i--;
if ( i > NF_KEY_LASTOLDKEYWORD && sString != rKeyword[i] )
{ // found something, but maybe it's something else?
// e.g. new NNN is found in NNNN, for NNNN we must search on
short j = i - 1;
while ( j > 0 && sString.Search(rKeyword[j]) != 0 )
j--;
if ( j && rKeyword[j].Len() > rKeyword[i].Len() )
return j;
}
}
// The Thai T NatNum modifier during Xcl import.
if (i == 0 && bConvertMode && sString.GetChar(0) == 'T' && eTmpLnge ==
LANGUAGE_ENGLISH_US && MsLangId::getRealLanguage( eNewLnge) ==
LANGUAGE_THAI)
i = NF_KEY_THAI_T;
return i; // 0 => not found
}
//---------------------------------------------------------------------------
// Next_Symbol
//---------------------------------------------------------------------------
// Zerlegt die Eingabe in Symbole fuer die weitere
// Verarbeitung (Turing-Maschine).
//---------------------------------------------------------------------------
// Ausgangs Zustand = SsStart
//---------------+-------------------+-----------------------+---------------
// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
//---------------+-------------------+-----------------------+---------------
// SsStart | Buchstabe | Symbol=Zeichen | SsGetWord
// | " | Typ = String | SsGetString
// | \ | Typ = String | SsGetChar
// | * | Typ = Star | SsGetStar
// | _ | Typ = Blank | SsGetBlank
// | @ # 0 ? / . , % [ | Symbol = Zeichen; |
// | ] ' Blank | Typ = Steuerzeichen | SsStop
// | $ - + ( ) : | Typ = String; |
// | | | Typ = Comment | SsStop
// | Sonst | Symbol = Zeichen | SsStop
//---------------|-------------------+-----------------------+---------------
// SsGetChar | Sonst | Symbol=Zeichen | SsStop
//---------------+-------------------+-----------------------+---------------
// GetString | " | | SsStop
// | Sonst | Symbol+=Zeichen | GetString
//---------------+-------------------+-----------------------+---------------
// SsGetWord | Buchstabe | Symbol += Zeichen |
// | + - (E+ E-)| Symbol += Zeichen | SsStop
// | / (AM/PM)| Symbol += Zeichen |
// | Sonst | Pos--, if Key Typ=Word| SsStop
//---------------+-------------------+-----------------------+---------------
// SsGetStar | Sonst | Symbol+=Zeichen | SsStop
// | | markiere Sonderfall * |
//---------------+-------------------+-----------------------+---------------
// SsGetBlank | Sonst | Symbol+=Zeichen | SsStop
// | | markiere Sonderfall _ |
//---------------+-------------------+-----------------------+---------------
// Wurde im State SsGetWord ein Schluesselwort erkannt (auch als
// Anfangsteilwort des Symbols)
// so werden die restlichen Buchstaben zurueckgeschrieben !!
enum ScanState
{
SsStop = 0,
SsStart = 1,
SsGetChar = 2,
SsGetString = 3,
SsGetWord = 4,
SsGetStar = 5,
SsGetBlank = 6
};
short ImpSvNumberformatScan::Next_Symbol( const String& rStr,
xub_StrLen& nPos, String& sSymbol )
{
if ( bKeywordsNeedInit )
InitKeywords();
const CharClass* pChrCls = pFormatter->GetCharClass();
const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
const xub_StrLen nStart = nPos;
short eType = 0;
ScanState eState = SsStart;
sSymbol.Erase();
while ( nPos < rStr.Len() && eState != SsStop )
{
sal_Unicode cToken = rStr.GetChar( nPos++ );
switch (eState)
{
case SsStart:
{
// Fetch any currency longer than one character and don't get
// confused later on by "E/" or other combinations of letters
// and meaningful symbols. Necessary for old automatic currency.
// #96158# But don't do it if we're starting a "[...]" section,
// for example a "[$...]" new currency symbol to not parse away
// "$U" (symbol) of "[$UYU]" (abbreviation).
if ( nCurrPos != STRING_NOTFOUND && sCurString.Len() > 1 &&
nPos-1 + sCurString.Len() <= rStr.Len() &&
!(nPos > 1 && rStr.GetChar( nPos-2 ) == '[') )
{
String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
pChrCls->toUpper( aTest );
if ( aTest == sCurString )
{
sSymbol = rStr.Copy( --nPos, sCurString.Len() );
nPos = nPos + sSymbol.Len();
eState = SsStop;
eType = NF_SYMBOLTYPE_STRING;
return eType;
}
}
switch (cToken)
{
case '#':
case '0':
case '?':
case '%':
case '@':
case '[':
case ']':
case ',':
case '.':
case '/':
case '\'':
case ' ':
case ':':
case '-':
{
eType = NF_SYMBOLTYPE_DEL;
sSymbol += cToken;
eState = SsStop;
}
break;
case '*':
{
eType = NF_SYMBOLTYPE_STAR;
sSymbol += cToken;
eState = SsGetStar;
}
break;
case '_':
{
eType = NF_SYMBOLTYPE_BLANK;
sSymbol += cToken;
eState = SsGetBlank;
}
break;
#if NF_COMMENT_IN_FORMATSTRING
case '{':
eType = NF_SYMBOLTYPE_COMMENT;
eState = SsStop;
sSymbol.Append( rStr.GetBuffer() + (nPos-1), rStr.Len() - (nPos-1) );
nPos = rStr.Len();
break;
#endif
case '"':
eType = NF_SYMBOLTYPE_STRING;
eState = SsGetString;
sSymbol += cToken;
break;
case '\\':
eType = NF_SYMBOLTYPE_STRING;
eState = SsGetChar;
sSymbol += cToken;
break;
case '$':
case '+':
case '(':
case ')':
eType = NF_SYMBOLTYPE_STRING;
eState = SsStop;
sSymbol += cToken;
break;
default :
{
if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
StringEqualsChar( pLoc->getTimeSep(), cToken) ||
StringEqualsChar( pLoc->getTime100SecSep(), cToken))
{
// Another separator than pre-known ASCII
eType = NF_SYMBOLTYPE_DEL;
sSymbol += cToken;
eState = SsStop;
}
else if ( pChrCls->isLetter( rStr, nPos-1 ) )
{
short nTmpType = GetKeyWord( rStr, nPos-1 );
if ( nTmpType )
{
sal_Bool bCurrency = sal_False;
// "Automatic" currency may start with keyword,
// like "R" (Rand) and 'R' (era)
if ( nCurrPos != STRING_NOTFOUND &&
nPos-1 + sCurString.Len() <= rStr.Len() &&
sCurString.Search( sKeyword[nTmpType] ) == 0 )
{
String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
pChrCls->toUpper( aTest );
if ( aTest == sCurString )
bCurrency = sal_True;
}
if ( bCurrency )
{
eState = SsGetWord;
sSymbol += cToken;
}
else
{
eType = nTmpType;
xub_StrLen nLen = sKeyword[eType].Len();
sSymbol = rStr.Copy( nPos-1, nLen );
if ( eType == NF_KEY_E || IsAmbiguousE( eType ) )
{
sal_Unicode cNext = rStr.GetChar(nPos);
switch ( cNext )
{
case '+' :
case '-' : // E+ E- combine to one symbol
sSymbol += cNext;
eType = NF_KEY_E;
nPos++;
break;
case '0' :
case '#' : // scientific E without sign
eType = NF_KEY_E;
break;
}
}
nPos--;
nPos = nPos + nLen;
eState = SsStop;
}
}
else
{
eState = SsGetWord;
sSymbol += cToken;
}
}
else
{
eType = NF_SYMBOLTYPE_STRING;
eState = SsStop;
sSymbol += cToken;
}
}
break;
}
}
break;
case SsGetChar:
{
sSymbol += cToken;
eState = SsStop;
}
break;
case SsGetString:
{
if (cToken == '"')
eState = SsStop;
sSymbol += cToken;
}
break;
case SsGetWord:
{
if ( pChrCls->isLetter( rStr, nPos-1 ) )
{
short nTmpType = GetKeyWord( rStr, nPos-1 );
if ( nTmpType )
{ // beginning of keyword, stop scan and put back
eType = NF_SYMBOLTYPE_STRING;
eState = SsStop;
nPos--;
}
else
sSymbol += cToken;
}
else
{
sal_Bool bDontStop = sal_False;
switch (cToken)
{
case '/': // AM/PM, A/P
{
sal_Unicode cNext = rStr.GetChar(nPos);
if ( cNext == 'P' || cNext == 'p' )
{
xub_StrLen nLen = sSymbol.Len();
if ( 1 <= nLen
&& (sSymbol.GetChar(0) == 'A' || sSymbol.GetChar(0) == 'a')
&& (nLen == 1 || (nLen == 2
&& (sSymbol.GetChar(1) == 'M' || sSymbol.GetChar(1) == 'm')
&& (rStr.GetChar(nPos+1) == 'M' || rStr.GetChar(nPos+1) == 'm'))) )
{
sSymbol += cToken;
bDontStop = sal_True;
}
}
}
break;
}
// anything not recognized will stop the scan
if ( eState != SsStop && !bDontStop )
{
eState = SsStop;
nPos--;
eType = NF_SYMBOLTYPE_STRING;
}
}
}
break;
case SsGetStar:
{
eState = SsStop;
sSymbol += cToken;
nRepPos = (nPos - nStart) - 1; // everytime > 0!!
}
break;
case SsGetBlank:
{
eState = SsStop;
sSymbol += cToken;
}
break;
default:
break;
} // of switch
} // of while
if (eState == SsGetWord)
eType = NF_SYMBOLTYPE_STRING;
return eType;
}
xub_StrLen ImpSvNumberformatScan::Symbol_Division(const String& rString)
{
nCurrPos = STRING_NOTFOUND;
// Ist Waehrung im Spiel?
String sString = pFormatter->GetCharClass()->upper(rString);
xub_StrLen nCPos = 0;
while (nCPos != STRING_NOTFOUND)
{
nCPos = sString.Search(GetCurString(),nCPos);
if (nCPos != STRING_NOTFOUND)
{
// in Quotes?
xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
if ( nQ == STRING_NOTFOUND )
{
sal_Unicode c;
if ( nCPos == 0 ||
((c = sString.GetChar(xub_StrLen(nCPos-1))) != '"'
&& c != '\\') ) // dm kann durch "dm
{ // \d geschuetzt werden
nCurrPos = nCPos;
nCPos = STRING_NOTFOUND; // Abbruch
}
else
nCPos++; // weitersuchen
}
else
nCPos = nQ + 1; // weitersuchen
}
}
nAnzStrings = 0;
sal_Bool bStar = sal_False; // wird bei '*'Detektion gesetzt
Reset();
xub_StrLen nPos = 0;
const xub_StrLen nLen = rString.Len();
while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
{
nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
{ // Ueberwachung des '*'
if (bStar)
return nPos; // Fehler: doppelter '*'
else
bStar = sal_True;
}
nAnzStrings++;
}
return 0; // 0 => ok
}
void ImpSvNumberformatScan::SkipStrings(sal_uInt16& i, xub_StrLen& nPos)
{
while (i < nAnzStrings && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING
|| nTypeArray[i] == NF_SYMBOLTYPE_BLANK
|| nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
{
nPos = nPos + sStrArray[i].Len();
i++;
}
}
sal_uInt16 ImpSvNumberformatScan::PreviousKeyword(sal_uInt16 i)
{
short res = 0;
if (i > 0 && i < nAnzStrings)
{
i--;
while (i > 0 && nTypeArray[i] <= 0)
i--;
if (nTypeArray[i] > 0)
res = nTypeArray[i];
}
return res;
}
sal_uInt16 ImpSvNumberformatScan::NextKeyword(sal_uInt16 i)
{
short res = 0;
if (i < nAnzStrings-1)
{
i++;
while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
i++;
if (nTypeArray[i] > 0)
res = nTypeArray[i];
}
return res;
}
short ImpSvNumberformatScan::PreviousType( sal_uInt16 i )
{
if ( i > 0 && i < nAnzStrings )
{
do
{
i--;
} while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
return nTypeArray[i];
}
return 0;
}
sal_Unicode ImpSvNumberformatScan::PreviousChar(sal_uInt16 i)
{
sal_Unicode res = ' ';
if (i > 0 && i < nAnzStrings)
{
i--;
while (i > 0 && ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
|| nTypeArray[i] == NF_SYMBOLTYPE_STRING
|| nTypeArray[i] == NF_SYMBOLTYPE_STAR
|| nTypeArray[i] == NF_SYMBOLTYPE_BLANK ) )
i--;
if (sStrArray[i].Len() > 0)
res = sStrArray[i].GetChar(xub_StrLen(sStrArray[i].Len()-1));
}
return res;
}
sal_Unicode ImpSvNumberformatScan::NextChar(sal_uInt16 i)
{
sal_Unicode res = ' ';
if (i < nAnzStrings-1)
{
i++;
while (i < nAnzStrings-1 &&
( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
|| nTypeArray[i] == NF_SYMBOLTYPE_STRING
|| nTypeArray[i] == NF_SYMBOLTYPE_STAR
|| nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
i++;
if (sStrArray[i].Len() > 0)
res = sStrArray[i].GetChar(0);
}
return res;
}
sal_Bool ImpSvNumberformatScan::IsLastBlankBeforeFrac(sal_uInt16 i)
{
sal_Bool res = sal_True;
if (i < nAnzStrings-1)
{
sal_Bool bStop = sal_False;
i++;
while (i < nAnzStrings-1 && !bStop)
{
i++;
if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
sStrArray[i].GetChar(0) == '/')
bStop = sal_True;
else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
sStrArray[i].GetChar(0) == ' ')
res = sal_False;
}
if (!bStop) // kein '/'
res = sal_False;
}
else
res = sal_False; // kein '/' mehr
return res;
}
void ImpSvNumberformatScan::Reset()
{
nAnzStrings = 0;
nAnzResStrings = 0;
#if 0
// ER 20.06.97 14:05 nicht noetig, wenn nAnzStrings beachtet wird
for (size_t i = 0; i < NF_MAX_FORMAT_SYMBOLS; i++)
{
sStrArray[i].Erase();
nTypeArray[i] = 0;
}
#endif
eScannedType = NUMBERFORMAT_UNDEFINED;
nRepPos = 0;
bExp = sal_False;
bThousand = sal_False;
nThousand = 0;
bDecSep = sal_False;
nDecPos = -1;
nExpPos = (sal_uInt16) -1;
nBlankPos = (sal_uInt16) -1;
nCntPre = 0;
nCntPost = 0;
nCntExp = 0;
bFrac = sal_False;
bBlank = sal_False;
nNatNumModifier = 0;
}
sal_Bool ImpSvNumberformatScan::Is100SecZero( sal_uInt16 i, sal_Bool bHadDecSep )
{
sal_uInt16 nIndexPre = PreviousKeyword( i );
return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS)
&& (bHadDecSep // S, SS ','
|| (i>0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
// SS"any"00 take "any" as a valid decimal separator
}
xub_StrLen ImpSvNumberformatScan::ScanType(const String&)
{
const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
xub_StrLen nPos = 0;
sal_uInt16 i = 0;
short eNewType;
sal_Bool bMatchBracket = sal_False;
bool bHaveGeneral = false; // if General/Standard encountered
SkipStrings(i, nPos);
while (i < nAnzStrings)
{
if (nTypeArray[i] > 0)
{ // keyword
switch (nTypeArray[i])
{
case NF_KEY_E: // E
eNewType = NUMBERFORMAT_SCIENTIFIC;
break;
case NF_KEY_AMPM: // AM,A,PM,P
case NF_KEY_AP:
case NF_KEY_H: // H
case NF_KEY_HH: // HH
case NF_KEY_S: // S
case NF_KEY_SS: // SS
eNewType = NUMBERFORMAT_TIME;
break;
case NF_KEY_M: // M
case NF_KEY_MM: // MM
{ // minute or month
sal_uInt16 nIndexPre = PreviousKeyword(i);
sal_uInt16 nIndexNex = NextKeyword(i);
sal_Unicode cChar = PreviousChar(i);
if (nIndexPre == NF_KEY_H || // H
nIndexPre == NF_KEY_HH || // HH
nIndexNex == NF_KEY_S || // S
nIndexNex == NF_KEY_SS || // SS
cChar == '[' ) // [M
{
eNewType = NUMBERFORMAT_TIME;
nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5
}
else
eNewType = NUMBERFORMAT_DATE;
}
break;
case NF_KEY_MMM: // MMM
case NF_KEY_MMMM: // MMMM
case NF_KEY_MMMMM: // MMMMM
case NF_KEY_Q: // Q
case NF_KEY_QQ: // QQ
case NF_KEY_D: // D
case NF_KEY_DD: // DD
case NF_KEY_DDD: // DDD
case NF_KEY_DDDD: // DDDD
case NF_KEY_YY: // YY
case NF_KEY_YYYY: // YYYY
case NF_KEY_NN: // NN
case NF_KEY_NNN: // NNN
case NF_KEY_NNNN: // NNNN
case NF_KEY_WW : // WW
case NF_KEY_AAA : // AAA
case NF_KEY_AAAA : // AAAA
case NF_KEY_EC : // E
case NF_KEY_EEC : // EE
case NF_KEY_G : // G
case NF_KEY_GG : // GG
case NF_KEY_GGG : // GGG
case NF_KEY_R : // R
case NF_KEY_RR : // RR
eNewType = NUMBERFORMAT_DATE;
break;
case NF_KEY_CCC: // CCC
eNewType = NUMBERFORMAT_CURRENCY;
break;
case NF_KEY_GENERAL: // Standard
eNewType = NUMBERFORMAT_NUMBER;
bHaveGeneral = true;
break;
default:
eNewType = NUMBERFORMAT_UNDEFINED;
break;
}
}
else
{ // control character
switch ( sStrArray[i].GetChar(0) )
{
case '#':
case '?':
eNewType = NUMBERFORMAT_NUMBER;
break;
case '0':
{
if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
{
if ( Is100SecZero( i, bDecSep ) )
{
bDecSep = sal_True; // subsequent 0's
eNewType = NUMBERFORMAT_TIME;
}
else
return nPos; // Error
}
else
eNewType = NUMBERFORMAT_NUMBER;
}
break;
case '%':
eNewType = NUMBERFORMAT_PERCENT;
break;
case '/':
eNewType = NUMBERFORMAT_FRACTION;
break;
case '[':
{
if ( i < nAnzStrings-1 &&
nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
sStrArray[i+1].GetChar(0) == '$' )
{ // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
eNewType = NUMBERFORMAT_CURRENCY;
bMatchBracket = sal_True;
}
else if ( i < nAnzStrings-1 &&
nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
sStrArray[i+1].GetChar(0) == '~' )
{ // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
eNewType = NUMBERFORMAT_DATE;
bMatchBracket = sal_True;
}
else
{
sal_uInt16 nIndexNex = NextKeyword(i);
if (nIndexNex == NF_KEY_H || // H
nIndexNex == NF_KEY_HH || // HH
nIndexNex == NF_KEY_M || // M
nIndexNex == NF_KEY_MM || // MM
nIndexNex == NF_KEY_S || // S
nIndexNex == NF_KEY_SS ) // SS
eNewType = NUMBERFORMAT_TIME;
else
return nPos; // Error
}
}
break;
case '@':
eNewType = NUMBERFORMAT_TEXT;
break;
default:
if ( sStrArray[i] == pLoc->getTime100SecSep() )
bDecSep = sal_True; // for SS,0
eNewType = NUMBERFORMAT_UNDEFINED;
break;
}
}
if (eScannedType == NUMBERFORMAT_UNDEFINED)
eScannedType = eNewType;
else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
eScannedType = NUMBERFORMAT_TEXT; // Text bleibt immer Text
else if (eNewType == NUMBERFORMAT_UNDEFINED)
{ // bleibt wie bisher
}
else if (eScannedType != eNewType)
{
switch (eScannedType)
{
case NUMBERFORMAT_DATE:
{
switch (eNewType)
{
case NUMBERFORMAT_TIME:
eScannedType = NUMBERFORMAT_DATETIME;
break;
case NUMBERFORMAT_FRACTION: // DD/MM
break;
default:
{
if (nCurrPos != STRING_NOTFOUND)
eScannedType = NUMBERFORMAT_UNDEFINED;
else if ( sStrArray[i] != pFormatter->GetDateSep() )
return nPos;
}
}
}
break;
case NUMBERFORMAT_TIME:
{
switch (eNewType)
{
case NUMBERFORMAT_DATE:
eScannedType = NUMBERFORMAT_DATETIME;
break;
case NUMBERFORMAT_FRACTION: // MM/SS
break;
default:
{
if (nCurrPos != STRING_NOTFOUND)
eScannedType = NUMBERFORMAT_UNDEFINED;
else if ( sStrArray[i] != pLoc->getTimeSep() )
return nPos;
}
}
}
break;
case NUMBERFORMAT_DATETIME:
{
switch (eNewType)
{
case NUMBERFORMAT_TIME:
case NUMBERFORMAT_DATE:
break;
case NUMBERFORMAT_FRACTION: // DD/MM
break;
default:
{
if (nCurrPos != STRING_NOTFOUND)
eScannedType = NUMBERFORMAT_UNDEFINED;
else if ( sStrArray[i] != pFormatter->GetDateSep()
&& sStrArray[i] != pLoc->getTimeSep() )
return nPos;
}
}
}
break;
case NUMBERFORMAT_PERCENT:
{
switch (eNewType)
{
case NUMBERFORMAT_NUMBER: // nur Zahl nach Prozent
break;
default:
return nPos;
}
}
break;
case NUMBERFORMAT_SCIENTIFIC:
{
switch (eNewType)
{
case NUMBERFORMAT_NUMBER: // nur Zahl nach E
break;
default:
return nPos;
}
}
break;
case NUMBERFORMAT_NUMBER:
{
switch (eNewType)
{
case NUMBERFORMAT_SCIENTIFIC:
case NUMBERFORMAT_PERCENT:
case NUMBERFORMAT_FRACTION:
case NUMBERFORMAT_CURRENCY:
eScannedType = eNewType;
break;
default:
if (nCurrPos != STRING_NOTFOUND)
eScannedType = NUMBERFORMAT_UNDEFINED;
else
return nPos;
}
}
break;
case NUMBERFORMAT_FRACTION:
{
switch (eNewType)
{
case NUMBERFORMAT_NUMBER: // nur Zahl nach Bruch
break;
default:
return nPos;
}
}
break;
default:
break;
}
}
nPos = nPos + sStrArray[i].Len(); // Korrekturposition
i++;
if ( bMatchBracket )
{ // no type detection inside of matching brackets if [$...], [~...]
while ( bMatchBracket && i < nAnzStrings )
{
if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
&& sStrArray[i].GetChar(0) == ']' )
bMatchBracket = sal_False;
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
if ( bMatchBracket )
return nPos; // missing closing bracket at end of code
}
SkipStrings(i, nPos);
}
if ((eScannedType == NUMBERFORMAT_NUMBER || eScannedType == NUMBERFORMAT_UNDEFINED)
&& nCurrPos != STRING_NOTFOUND && !bHaveGeneral)
eScannedType = NUMBERFORMAT_CURRENCY; // old "automatic" currency
if (eScannedType == NUMBERFORMAT_UNDEFINED)
eScannedType = NUMBERFORMAT_DEFINED;
return 0; // Alles ok
}
bool ImpSvNumberformatScan::InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const String& rStr )
{
if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
return false;
++nAnzResStrings;
if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
--nPos; // reuse position
else
{
++nAnzStrings;
for (size_t i = nAnzStrings; i > nPos; --i)
{
nTypeArray[i] = nTypeArray[i-1];
sStrArray[i] = sStrArray[i-1];
}
}
nTypeArray[nPos] = static_cast<short>(eType);
sStrArray[nPos] = rStr;
return true;
}
int ImpSvNumberformatScan::FinalScanGetCalendar( xub_StrLen& nPos, sal_uInt16& i,
sal_uInt16& rAnzResStrings )
{
if ( sStrArray[i].GetChar(0) == '[' &&
i < nAnzStrings-1 &&
nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
sStrArray[i+1].GetChar(0) == '~' )
{ // [~calendarID]
// as of SV_NUMBERFORMATTER_VERSION_CALENDAR
nPos = nPos + sStrArray[i].Len(); // [
nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
nPos = nPos + sStrArray[++i].Len(); // ~
sStrArray[i-1] += sStrArray[i]; // [~
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
rAnzResStrings--;
if ( ++i >= nAnzStrings )
return -1; // error
nPos = nPos + sStrArray[i].Len(); // calendarID
String& rStr = sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert
i++;
while ( i < nAnzStrings &&
sStrArray[i].GetChar(0) != ']' )
{
nPos = nPos + sStrArray[i].Len();
rStr += sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
rAnzResStrings--;
i++;
}
if ( rStr.Len() && i < nAnzStrings &&
sStrArray[i].GetChar(0) == ']' )
{
nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
nPos = nPos + sStrArray[i].Len();
i++;
}
else
return -1; // error
return 1;
}
return 0;
}
xub_StrLen ImpSvNumberformatScan::FinalScan( String& rString, String& rComment )
{
const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
// save values for convert mode
String sOldDecSep = pFormatter->GetNumDecimalSep();
String sOldThousandSep = pFormatter->GetNumThousandSep();
String sOldDateSep = pFormatter->GetDateSep();
String sOldTimeSep = pLoc->getTimeSep();
String sOldTime100SecSep= pLoc->getTime100SecSep();
String sOldCurSymbol = GetCurSymbol();
String sOldCurString = GetCurString();
sal_Unicode cOldKeyH = sKeyword[NF_KEY_H].GetChar(0);
sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI].GetChar(0);
sal_Unicode cOldKeyS = sKeyword[NF_KEY_S].GetChar(0);
// If the group separator is a Non-Breaking Space (French) continue with a
// normal space instead so queries on space work correctly.
// The format string is adjusted to allow both.
// For output of the format code string the LocaleData characters are used.
if ( sOldThousandSep.GetChar(0) == cNonBreakingSpace && sOldThousandSep.Len() == 1 )
sOldThousandSep = ' ';
// change locale data et al
if (bConvertMode)
{
pFormatter->ChangeIntl(eNewLnge);
//! pointer may have changed
pLoc = pFormatter->GetLocaleData();
//! init new keywords
InitKeywords();
}
const CharClass* pChrCls = pFormatter->GetCharClass();
xub_StrLen nPos = 0; // error correction position
sal_uInt16 i = 0; // symbol loop counter
sal_uInt16 nCounter = 0; // counts digits
nAnzResStrings = nAnzStrings; // counts remaining symbols
bDecSep = sal_False; // reset in case already used in TypeCheck
bool bThaiT = false; // Thai T NatNum modifier present
switch (eScannedType)
{
case NUMBERFORMAT_TEXT:
case NUMBERFORMAT_DEFINED:
{
while (i < nAnzStrings)
{
switch (nTypeArray[i])
{
case NF_SYMBOLTYPE_BLANK:
case NF_SYMBOLTYPE_STAR:
break;
case NF_SYMBOLTYPE_COMMENT:
{
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
SvNumberformat::EraseCommentBraces( rStr );
rComment += rStr;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
break;
case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
break;
default:
{
if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
sStrArray[i].GetChar(0) != '@' )
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
}
break;
}
nPos = nPos + sStrArray[i].Len();
i++;
} // of while
}
break;
case NUMBERFORMAT_NUMBER:
case NUMBERFORMAT_PERCENT:
case NUMBERFORMAT_CURRENCY:
case NUMBERFORMAT_SCIENTIFIC:
case NUMBERFORMAT_FRACTION:
{
sal_Unicode cThousandFill = ' ';
while (i < nAnzStrings)
{
if (eScannedType == NUMBERFORMAT_FRACTION && // special case
nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/#
StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
StringEqualsChar( sStrArray[i], ' ' ) &&
!bFrac &&
IsLastBlankBeforeFrac(i) )
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string
} // kein Taus.p.
if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK ||
nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
nTypeArray[i] == NF_KEY_CCC || // CCC
nTypeArray[i] == NF_KEY_GENERAL ) // Standard
{
if (nTypeArray[i] == NF_KEY_GENERAL)
{
nThousand = FLAG_STANDARD_IN_FORMAT;
if ( bConvertMode )
sStrArray[i] = sNameStandardFormat;
}
nPos = nPos + sStrArray[i].Len();
i++;
}
else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // Strings oder
nTypeArray[i] > 0) // Keywords
{
if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
nTypeArray[i] == NF_KEY_E) // E+
{
if (bExp) // doppelt
return nPos;
bExp = sal_True;
nExpPos = i;
if (bDecSep)
nCntPost = nCounter;
else
nCntPre = nCounter;
nCounter = 0;
nTypeArray[i] = NF_SYMBOLTYPE_EXP;
}
else if (eScannedType == NUMBERFORMAT_FRACTION &&
sStrArray[i].GetChar(0) == ' ')
{
if (!bBlank && !bFrac) // nicht doppelt oder hinter /
{
if (bDecSep && nCounter > 0) // Nachkommastellen
return nPos; // Fehler
bBlank = sal_True;
nBlankPos = i;
nCntPre = nCounter;
nCounter = 0;
}
nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
}
else if (nTypeArray[i] == NF_KEY_THAI_T)
{
bThaiT = true;
sStrArray[i] = sKeyword[nTypeArray[i]];
}
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
{
sal_Unicode cHere = sStrArray[i].GetChar(0);
// Handle not pre-known separators in switch.
sal_Unicode cSimplified;
if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
cSimplified = ',';
else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
cSimplified = '.';
else
cSimplified = cHere;
switch ( cSimplified )
{
case '#':
case '0':
case '?':
{
if (nThousand > 0) // #... #
return nPos; // Fehler
else if (bFrac && cHere == '0')
return nPos; // 0 im Nenner
nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
i++;
nCounter++;
while (i < nAnzStrings &&
(sStrArray[i].GetChar(0) == '#' ||
sStrArray[i].GetChar(0) == '0' ||
sStrArray[i].GetChar(0) == '?')
)
{
nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
nPos = nPos + sStrArray[i].Len();
nCounter++;
i++;
}
}
break;
case '-':
{
if ( bDecSep && nDecPos+1 == i &&
nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
{ // "0.--"
nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
i++;
nCounter++;
while (i < nAnzStrings &&
(sStrArray[i].GetChar(0) == '-') )
{
// If more than two dashes are present in
// currency formats the last dash will be
// interpreted literally as a minus sign.
// Has to be this ugly. Period.
if ( eScannedType == NUMBERFORMAT_CURRENCY
&& rStr.Len() >= 2 &&
(i == nAnzStrings-1 ||
sStrArray[i+1].GetChar(0) != '-') )
break;
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
nCounter++;
i++;
}
}
else
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
}
break;
case '.':
case ',':
case '\'':
case ' ':
{
sal_Unicode cSep = cHere; // remember
if ( StringEqualsChar( sOldThousandSep, cSep ) )
{
// previous char with skip empty
sal_Unicode cPre = PreviousChar(i);
sal_Unicode cNext;
if (bExp || bBlank || bFrac)
{ // after E, / or ' '
if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
{
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++; // eat it
}
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
}
else if (i > 0 && i < nAnzStrings-1 &&
(cPre == '#' || cPre == '0') &&
((cNext = NextChar(i)) == '#' || cNext == '0')
) // #,#
{
nPos = nPos + sStrArray[i].Len();
if (!bThousand) // only once
{
bThousand = sal_True;
cThousandFill = sStrArray[i+1].GetChar(0);
}
// Eat it, will be reinserted at proper
// grouping positions further down.
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
else if (i > 0 && (cPre == '#' || cPre == '0')
&& PreviousType(i) == NF_SYMBOLTYPE_DIGIT
&& nThousand < FLAG_STANDARD_IN_FORMAT )
{ // #,,,,
if ( StringEqualsChar( sOldThousandSep, ' ' ) )
{ // strange, those French..
sal_Bool bFirst = sal_True;
String& rStr = sStrArray[i];
// set a hard Non-Breaking Space or ConvertMode
const String& rSepF = pFormatter->GetNumThousandSep();
while ( i < nAnzStrings
&& sStrArray[i] == sOldThousandSep
&& StringEqualsChar( sOldThousandSep, NextChar(i) ) )
{ // last was a space or another space
// is following => separator
nPos = nPos + sStrArray[i].Len();
if ( bFirst )
{
bFirst = sal_False;
rStr = rSepF;
nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
}
else
{
rStr += rSepF;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
nThousand++;
i++;
}
if ( i < nAnzStrings-1
&& sStrArray[i] == sOldThousandSep )
{ // something following last space
// => space if currency contained,
// else separator
nPos = nPos + sStrArray[i].Len();
if ( (nPos <= nCurrPos &&
nCurrPos < nPos + sStrArray[i+1].Len())
|| nTypeArray[i+1] == NF_KEY_CCC
|| (i < nAnzStrings-2 &&
sStrArray[i+1].GetChar(0) == '[' &&
sStrArray[i+2].GetChar(0) == '$') )
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
}
else
{
if ( bFirst )
{
bFirst = sal_False;
rStr = rSepF;
nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
}
else
{
rStr += rSepF;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
nThousand++;
}
i++;
}
}
else
{
do
{
nThousand++;
nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
nPos = nPos + sStrArray[i].Len();
sStrArray[i] = pFormatter->GetNumThousandSep();
i++;
} while (i < nAnzStrings &&
sStrArray[i] == sOldThousandSep);
}
}
else // any grsep
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
i++;
while ( i < nAnzStrings &&
sStrArray[i] == sOldThousandSep )
{
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
}
}
else if ( StringEqualsChar( sOldDecSep, cSep ) )
{
if (bBlank || bFrac) // . behind / or ' '
return nPos; // error
else if (bExp) // behind E
{
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++; // eat it
}
else if (bDecSep) // any .
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
i++;
while ( i < nAnzStrings &&
sStrArray[i] == sOldDecSep )
{
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
}
else
{
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
sStrArray[i] = pFormatter->GetNumDecimalSep();
bDecSep = sal_True;
nDecPos = i;
nCntPre = nCounter;
nCounter = 0;
i++;
}
} // of else = DecSep
else // . without meaning
{
if (cSep == ' ' &&
eScannedType == NUMBERFORMAT_FRACTION &&
StringEqualsChar( sStrArray[i], ' ' ) )
{
if (!bBlank && !bFrac) // no dups
{ // or behind /
if (bDecSep && nCounter > 0)// dec.
return nPos; // error
bBlank = sal_True;
nBlankPos = i;
nCntPre = nCounter;
nCounter = 0;
}
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
}
else
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
i++;
while (i < nAnzStrings &&
StringEqualsChar( sStrArray[i], cSep ) )
{
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
}
}
}
break;
case '/':
{
if (eScannedType == NUMBERFORMAT_FRACTION)
{
if ( i == 0 ||
(nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
return nPos ? nPos : 1; // /? not allowed
else if (!bFrac || (bDecSep && nCounter > 0))
{
bFrac = sal_True;
nCntPost = nCounter;
nCounter = 0;
nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
nPos = nPos + sStrArray[i].Len();
i++;
}
else // / doppelt od. , imZaehl
return nPos; // Fehler
}
else
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
}
break;
case '[' :
{
if ( eScannedType == NUMBERFORMAT_CURRENCY &&
i < nAnzStrings-1 &&
nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
sStrArray[i+1].GetChar(0) == '$' )
{ // [$DM-xxx]
// ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
nPos = nPos + sStrArray[i].Len(); // [
nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
nPos = nPos + sStrArray[++i].Len(); // $
sStrArray[i-1] += sStrArray[i]; // [$
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
if ( ++i >= nAnzStrings )
return nPos; // Fehler
nPos = nPos + sStrArray[i].Len(); // DM
String& rStr = sStrArray[i];
String* pStr = &sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // wandeln
sal_Bool bHadDash = sal_False;
i++;
while ( i < nAnzStrings &&
sStrArray[i].GetChar(0) != ']' )
{
nPos = nPos + sStrArray[i].Len();
if ( bHadDash )
{
*pStr += sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
else
{
if ( sStrArray[i].GetChar(0) == '-' )
{
bHadDash = sal_True;
pStr = &sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
}
else
{
*pStr += sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
}
i++;
}
if ( rStr.Len() && i < nAnzStrings &&
sStrArray[i].GetChar(0) == ']' )
{
nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
nPos = nPos + sStrArray[i].Len();
i++;
}
else
return nPos; // Fehler
}
else
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
}
break;
default: // andere Dels
{
if (eScannedType == NUMBERFORMAT_PERCENT &&
cHere == '%')
nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
} // of switch (Del)
} // of else Del
else if ( nTypeArray[i] == NF_SYMBOLTYPE_COMMENT )
{
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
SvNumberformat::EraseCommentBraces( rStr );
rComment += rStr;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
else
{
DBG_ERRORFILE( "unknown NF_SYMBOLTYPE_..." );
nPos = nPos + sStrArray[i].Len();
i++;
}
} // of while
if (eScannedType == NUMBERFORMAT_FRACTION)
{
if (bFrac)
nCntExp = nCounter;
else if (bBlank)
nCntPost = nCounter;
else
nCntPre = nCounter;
}
else
{
if (bExp)
nCntExp = nCounter;
else if (bDecSep)
nCntPost = nCounter;
else
nCntPre = nCounter;
}
if (bThousand) // Expansion of grouping separators
{
sal_uInt16 nMaxPos;
if (bFrac)
{
if (bBlank)
nMaxPos = nBlankPos;
else
nMaxPos = 0; // no grouping
}
else if (bDecSep) // decimal separator present
nMaxPos = nDecPos;
else if (bExp) // 'E' exponent present
nMaxPos = nExpPos;
else // up to end
nMaxPos = i;
// Insert separators at proper positions.
xub_StrLen nCount = 0;
utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
size_t nFirstDigitSymbol = nMaxPos;
size_t nFirstGroupingSymbol = nMaxPos;
i = nMaxPos;
while (i-- > 0)
{
if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
{
nFirstDigitSymbol = i;
nCount = nCount + sStrArray[i].Len(); // MSC converts += to int and then warns, so ...
// Insert separator only if not leftmost symbol.
if (i > 0 && nCount >= aGrouping.getPos())
{
DBG_ASSERT( sStrArray[i].Len() == 1,
"ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP,
pFormatter->GetNumThousandSep()))
// nPos isn't correct here, but signals error
return nPos;
// i may have been decremented by 1
nFirstDigitSymbol = i + 1;
nFirstGroupingSymbol = i;
aGrouping.advance();
}
}
}
// Generated something like "string",000; remove separator again.
if (nFirstGroupingSymbol < nFirstDigitSymbol)
{
nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
}
// Combine digits into groups to save memory (Info will be copied
// later, taking only non-empty symbols).
for (i = 0; i < nAnzStrings; ++i)
{
if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
{
String& rStr = sStrArray[i];
while (++i < nAnzStrings &&
nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
{
rStr += sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
}
}
}
break; // of NUMBERFORMAT_NUMBER
case NUMBERFORMAT_DATE:
{
while (i < nAnzStrings)
{
switch (nTypeArray[i])
{
case NF_SYMBOLTYPE_BLANK:
case NF_SYMBOLTYPE_STAR:
case NF_SYMBOLTYPE_STRING:
nPos = nPos + sStrArray[i].Len();
i++;
break;
case NF_SYMBOLTYPE_COMMENT:
{
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
SvNumberformat::EraseCommentBraces( rStr );
rComment += rStr;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
break;
case NF_SYMBOLTYPE_DEL:
{
int nCalRet;
if (sStrArray[i] == sOldDateSep)
{
nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
nPos = nPos + sStrArray[i].Len();
if (bConvertMode)
sStrArray[i] = pFormatter->GetDateSep();
i++;
}
else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
{
if ( nCalRet < 0 )
return nPos; // error
}
else
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
}
break;
case NF_KEY_THAI_T :
bThaiT = true;
// fall thru
case NF_KEY_M: // M
case NF_KEY_MM: // MM
case NF_KEY_MMM: // MMM
case NF_KEY_MMMM: // MMMM
case NF_KEY_MMMMM: // MMMMM
case NF_KEY_Q: // Q
case NF_KEY_QQ: // QQ
case NF_KEY_D: // D
case NF_KEY_DD: // DD
case NF_KEY_DDD: // DDD
case NF_KEY_DDDD: // DDDD
case NF_KEY_YY: // YY
case NF_KEY_YYYY: // YYYY
case NF_KEY_NN: // NN
case NF_KEY_NNN: // NNN
case NF_KEY_NNNN: // NNNN
case NF_KEY_WW : // WW
case NF_KEY_AAA : // AAA
case NF_KEY_AAAA : // AAAA
case NF_KEY_EC : // E
case NF_KEY_EEC : // EE
case NF_KEY_G : // G
case NF_KEY_GG : // GG
case NF_KEY_GGG : // GGG
case NF_KEY_R : // R
case NF_KEY_RR : // RR
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
break;
default: // andere Keywords
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
break;
}
} // of while
}
break; // of NUMBERFORMAT_DATE
case NUMBERFORMAT_TIME:
{
while (i < nAnzStrings)
{
switch (nTypeArray[i])
{
case NF_SYMBOLTYPE_BLANK:
case NF_SYMBOLTYPE_STAR:
{
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
case NF_SYMBOLTYPE_DEL:
{
switch( sStrArray[i].GetChar(0) )
{
case '0':
{
if ( Is100SecZero( i, bDecSep ) )
{
bDecSep = sal_True;
nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
String& rStr = sStrArray[i];
i++;
nPos = nPos + sStrArray[i].Len();
nCounter++;
while (i < nAnzStrings &&
sStrArray[i].GetChar(0) == '0')
{
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
nCounter++;
i++;
}
}
else
return nPos;
}
break;
case '#':
case '?':
return nPos;
case '[':
{
if (bThousand) // doppelt
return nPos;
bThousand = sal_True; // bei Time frei
sal_Unicode cChar = pChrCls->upper( NextChar(i) ).GetChar(0);
if ( cChar == cOldKeyH )
nThousand = 1; // H
else if ( cChar == cOldKeyMI )
nThousand = 2; // M
else if ( cChar == cOldKeyS )
nThousand = 3; // S
else
return nPos;
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
case ']':
{
if (!bThousand) // kein [ vorher
return nPos;
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
default:
{
nPos = nPos + sStrArray[i].Len();
if ( sStrArray[i] == sOldTimeSep )
{
nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
if ( bConvertMode )
sStrArray[i] = pLoc->getTimeSep();
}
else if ( sStrArray[i] == sOldTime100SecSep )
{
bDecSep = sal_True;
nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
if ( bConvertMode )
sStrArray[i] = pLoc->getTime100SecSep();
}
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
i++;
}
break;
}
}
break;
case NF_SYMBOLTYPE_STRING:
{
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
case NF_SYMBOLTYPE_COMMENT:
{
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
SvNumberformat::EraseCommentBraces( rStr );
rComment += rStr;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
break;
case NF_KEY_AMPM: // AM/PM
case NF_KEY_AP: // A/P
{
bExp = sal_True; // missbraucht fuer A/P
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
case NF_KEY_THAI_T :
bThaiT = true;
// fall thru
case NF_KEY_MI: // M
case NF_KEY_MMI: // MM
case NF_KEY_H: // H
case NF_KEY_HH: // HH
case NF_KEY_S: // S
case NF_KEY_SS: // SS
{
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
default: // andere Keywords
{
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
}
} // of while
nCntPost = nCounter; // Zaehler der Nullen
if (bExp)
nCntExp = 1; // merkt AM/PM
}
break; // of NUMBERFORMAT_TIME
case NUMBERFORMAT_DATETIME:
{
sal_Bool bTimePart = sal_False;
while (i < nAnzStrings)
{
switch (nTypeArray[i])
{
case NF_SYMBOLTYPE_BLANK:
case NF_SYMBOLTYPE_STAR:
case NF_SYMBOLTYPE_STRING:
nPos = nPos + sStrArray[i].Len();
i++;
break;
case NF_SYMBOLTYPE_COMMENT:
{
String& rStr = sStrArray[i];
nPos = nPos + rStr.Len();
SvNumberformat::EraseCommentBraces( rStr );
rComment += rStr;
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
i++;
}
break;
case NF_SYMBOLTYPE_DEL:
{
int nCalRet;
if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
{
if ( nCalRet < 0 )
return nPos; // error
}
else
{
switch( sStrArray[i].GetChar(0) )
{
case '0':
{
if ( bTimePart && Is100SecZero( i, bDecSep ) )
{
bDecSep = sal_True;
nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
String& rStr = sStrArray[i];
i++;
nPos = nPos + sStrArray[i].Len();
nCounter++;
while (i < nAnzStrings &&
sStrArray[i].GetChar(0) == '0')
{
rStr += sStrArray[i];
nPos = nPos + sStrArray[i].Len();
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
nCounter++;
i++;
}
}
else
return nPos;
}
break;
case '#':
case '?':
return nPos;
default:
{
nPos = nPos + sStrArray[i].Len();
if (bTimePart)
{
if ( sStrArray[i] == sOldTimeSep )
{
nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
if ( bConvertMode )
sStrArray[i] = pLoc->getTimeSep();
}
else if ( sStrArray[i] == sOldTime100SecSep )
{
bDecSep = sal_True;
nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
if ( bConvertMode )
sStrArray[i] = pLoc->getTime100SecSep();
}
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
}
else
{
if ( sStrArray[i] == sOldDateSep )
{
nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
if (bConvertMode)
sStrArray[i] = pFormatter->GetDateSep();
}
else
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
}
i++;
}
}
}
}
break;
case NF_KEY_AMPM: // AM/PM
case NF_KEY_AP: // A/P
{
bTimePart = sal_True;
bExp = sal_True; // missbraucht fuer A/P
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
}
break;
case NF_KEY_MI: // M
case NF_KEY_MMI: // MM
case NF_KEY_H: // H
case NF_KEY_HH: // HH
case NF_KEY_S: // S
case NF_KEY_SS: // SS
bTimePart = sal_True;
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
break;
case NF_KEY_M: // M
case NF_KEY_MM: // MM
case NF_KEY_MMM: // MMM
case NF_KEY_MMMM: // MMMM
case NF_KEY_MMMMM: // MMMMM
case NF_KEY_Q: // Q
case NF_KEY_QQ: // QQ
case NF_KEY_D: // D
case NF_KEY_DD: // DD
case NF_KEY_DDD: // DDD
case NF_KEY_DDDD: // DDDD
case NF_KEY_YY: // YY
case NF_KEY_YYYY: // YYYY
case NF_KEY_NN: // NN
case NF_KEY_NNN: // NNN
case NF_KEY_NNNN: // NNNN
case NF_KEY_WW : // WW
case NF_KEY_AAA : // AAA
case NF_KEY_AAAA : // AAAA
case NF_KEY_EC : // E
case NF_KEY_EEC : // EE
case NF_KEY_G : // G
case NF_KEY_GG : // GG
case NF_KEY_GGG : // GGG
case NF_KEY_R : // R
case NF_KEY_RR : // RR
bTimePart = sal_False;
sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
nPos = nPos + sStrArray[i].Len();
i++;
break;
case NF_KEY_THAI_T :
bThaiT = true;
sStrArray[i] = sKeyword[nTypeArray[i]];
nPos = nPos + sStrArray[i].Len();
i++;
break;
default: // andere Keywords
nTypeArray[i] = NF_SYMBOLTYPE_STRING;
nPos = nPos + sStrArray[i].Len();
i++;
break;
}
} // of while
nCntPost = nCounter; // decimals (100th seconds)
if (bExp)
nCntExp = 1; // merkt AM/PM
}
break; // of NUMBERFORMAT_DATETIME
default:
break;
}
if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
(nCntPre + nCntPost == 0 || nCntExp == 0))
return nPos;
else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
return nPos;
if (bThaiT && !GetNatNumModifier())
SetNatNumModifier(1);
if ( bConvertMode )
{ // strings containing keywords of the target locale must be quoted, so
// the user sees the difference and is able to edit the format string
for ( i=0; i < nAnzStrings; i++ )
{
if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
sStrArray[i].GetChar(0) != '\"' )
{
if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
{ // don't stringize automatic currency, will be converted
if ( sStrArray[i] == sOldCurSymbol )
continue; // for
// DM might be splitted into D and M
if ( sStrArray[i].Len() < sOldCurSymbol.Len() &&
pChrCls->toUpper( sStrArray[i], 0, 1 ).GetChar(0) ==
sOldCurString.GetChar(0) )
{
String aTmp( sStrArray[i] );
sal_uInt16 j = i + 1;
while ( aTmp.Len() < sOldCurSymbol.Len() &&
j < nAnzStrings &&
nTypeArray[j] == NF_SYMBOLTYPE_STRING )
{
aTmp += sStrArray[j++];
}
if ( pChrCls->upper( aTmp ) == sOldCurString )
{
sStrArray[i++] = aTmp;
for ( ; i<j; i++ )
{
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
i = j - 1;
continue; // for
}
}
}
String& rStr = sStrArray[i];
xub_StrLen nLen = rStr.Len();
for ( xub_StrLen j=0; j<nLen; j++ )
{
if ( (j == 0 || rStr.GetChar(j-1) != '\\') && GetKeyWord( rStr, j ) )
{
rStr.Insert( '\"', 0 );
rStr += '\"';
break; // for
}
}
}
}
}
// concatenate strings, remove quotes for output, and rebuild the format string
rString.Erase();
i = 0;
while (i < nAnzStrings)
{
switch ( nTypeArray[i] )
{
case NF_SYMBOLTYPE_STRING :
{
xub_StrLen nStringPos = rString.Len();
xub_StrLen nArrPos = 0;
sal_uInt16 iPos = i;
do
{
if (sStrArray[i].Len() == 2 &&
sStrArray[i].GetChar(0) == '\\')
{
// Unescape some simple forms of symbols even in the UI
// visible string to prevent duplicates that differ
// only in notation, originating from import.
// e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
// but 0\ 000 0 and 0 000 0 in a French locale are not.
sal_Unicode c = sStrArray[i].GetChar(1);
switch (c)
{
case '+':
case '-':
rString += c;
break;
case ' ':
case '.':
case '/':
if (((eScannedType & NUMBERFORMAT_DATE) == 0)
&& (StringEqualsChar(
pFormatter->GetNumThousandSep(),
c) || StringEqualsChar(
pFormatter->GetNumDecimalSep(),
c) || (c == ' ' &&
StringEqualsChar(
pFormatter->GetNumThousandSep(),
cNonBreakingSpace))))
rString += sStrArray[i];
else if ((eScannedType & NUMBERFORMAT_DATE) &&
StringEqualsChar(
pFormatter->GetDateSep(), c))
rString += sStrArray[i];
else if ((eScannedType & NUMBERFORMAT_TIME) &&
(StringEqualsChar( pLoc->getTimeSep(),
c) ||
StringEqualsChar(
pLoc->getTime100SecSep(), c)))
rString += sStrArray[i];
else if (eScannedType & NUMBERFORMAT_FRACTION)
rString += sStrArray[i];
else
rString += c;
break;
default:
rString += sStrArray[i];
}
}
else
rString += sStrArray[i];
if ( RemoveQuotes( sStrArray[i] ) > 0 )
{ // update currency up to quoted string
if ( eScannedType == NUMBERFORMAT_CURRENCY )
{ // dM -> DM or DM -> $ in old automatic
// currency formats, oh my ..., why did we ever
// introduce them?
String aTmp( pChrCls->toUpper(
sStrArray[iPos], nArrPos,
sStrArray[iPos].Len()-nArrPos ) );
xub_StrLen nCPos = aTmp.Search( sOldCurString );
if ( nCPos != STRING_NOTFOUND )
{
const String& rCur =
bConvertMode && bConvertSystemToSystem ?
GetCurSymbol() : sOldCurSymbol;
sStrArray[iPos].Replace( nArrPos+nCPos,
sOldCurString.Len(), rCur );
rString.Replace( nStringPos+nCPos,
sOldCurString.Len(), rCur );
}
nStringPos = rString.Len();
if ( iPos == i )
nArrPos = sStrArray[iPos].Len();
else
nArrPos = sStrArray[iPos].Len() + sStrArray[i].Len();
}
}
if ( iPos != i )
{
sStrArray[iPos] += sStrArray[i];
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
i++;
} while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
if ( i < nAnzStrings )
i--; // enter switch on next symbol again
if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.Len() )
{ // same as above, since last RemoveQuotes
String aTmp( pChrCls->toUpper(
sStrArray[iPos], nArrPos,
sStrArray[iPos].Len()-nArrPos ) );
xub_StrLen nCPos = aTmp.Search( sOldCurString );
if ( nCPos != STRING_NOTFOUND )
{
const String& rCur =
bConvertMode && bConvertSystemToSystem ?
GetCurSymbol() : sOldCurSymbol;
sStrArray[iPos].Replace( nArrPos+nCPos,
sOldCurString.Len(), rCur );
rString.Replace( nStringPos+nCPos,
sOldCurString.Len(), rCur );
}
}
}
break;
case NF_SYMBOLTYPE_CURRENCY :
{
rString += sStrArray[i];
RemoveQuotes( sStrArray[i] );
}
break;
case NF_KEY_THAI_T:
if (bThaiT && GetNatNumModifier() == 1)
{ // Remove T from format code, will be replaced with a [NatNum1] prefix.
nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
nAnzResStrings--;
}
else
rString += sStrArray[i];
break;
case NF_SYMBOLTYPE_EMPTY :
// nothing
break;
default:
rString += sStrArray[i];
}
i++;
}
return 0;
}
xub_StrLen ImpSvNumberformatScan::RemoveQuotes( String& rStr )
{
if ( rStr.Len() > 1 )
{
sal_Unicode c = rStr.GetChar(0);
xub_StrLen n;
if ( c == '"' && rStr.GetChar( (n = xub_StrLen(rStr.Len()-1)) ) == '"' )
{
rStr.Erase(n,1);
rStr.Erase(0,1);
return 2;
}
else if ( c == '\\' )
{
rStr.Erase(0,1);
return 1;
}
}
return 0;
}
xub_StrLen ImpSvNumberformatScan::ScanFormat( String& rString, String& rComment )
{
xub_StrLen res = Symbol_Division(rString); //lexikalische Analyse
if (!res)
res = ScanType(rString); // Erkennung des Formattyps
if (!res)
res = FinalScan( rString, rComment ); // Typabhaengige Endanalyse
return res; // res = Kontrollposition
// res = 0 => Format ok
}
void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, sal_uInt16 nAnz)
{
size_t i,j;
j = 0;
i = 0;
while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
{
if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
{
pInfo->sStrArray[i] = sStrArray[j];
pInfo->nTypeArray[i] = nTypeArray[j];
i++;
}
j++;
}
pInfo->eScannedType = eScannedType;
pInfo->bThousand = bThousand;
pInfo->nThousand = nThousand;
pInfo->nCntPre = nCntPre;
pInfo->nCntPost = nCntPost;
pInfo->nCntExp = nCntExp;
}