/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svl.hxx"

#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( "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( "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 String* pKeyword = GetKeywords();
    size_t i = 0;
    while (i < NF_MAX_DEFAULT_COLORS &&
           sString != pKeyword[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 = pKeyword[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 = pKeyword[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 String* pKeyword = GetKeywords();
    // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
    if ( sString.Search( pKeyword[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(pKeyword[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(pKeyword[i]) != 0 )
            i--;
        if ( i > NF_KEY_LASTOLDKEYWORD && sString != pKeyword[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(pKeyword[j]) != 0 )
                j--;
            if ( j && pKeyword[j].Len() > pKeyword[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:
        {
            while (i < nAnzStrings)
            {
                // TODO: rechecking eScannedType is unnecessary.
                // This switch-case is for eScannedType == NUMBERFORMAT_FRACTION anyway
                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 if (sStrArray[i].GetChar(0) >= '0' &&
                             sStrArray[i].GetChar(0) <= '9')
                    {
                        rtl::OUString sDiv;
                        sal_uInt16 j = i;
                        while(j < nAnzStrings)
                            sDiv += sStrArray[j++];
                        if (rtl::OUString::valueOf(sDiv.toInt32()) == sDiv)
                        {
                            /* Found a Divisor */
                            while (i < j)
                                nTypeArray[i++] = NF_SYMBOLTYPE_FRAC_FDIV;
                            i = j - 1;                            // Stop the loop
                            if (nCntPost)
                                nCounter = nCntPost;
                            else if (nCntPre)
                                nCounter = nCntPre;
                            if (!nCntPre)
                                nCntPre++;
                        }
                    }
                    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;
                                    // 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;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
