/**************************************************************
 * 
 * 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;	// every time > 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;
}