/* -*- 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_l10ntools.hxx"
#include <stdio.h>
#include <stdlib.h>
#include <tools/fsys.hxx>
#include "export.hxx"
#include "tokens.h"
#include "utf8conv.hxx"
#include <iostream>

extern "C" { int yyerror( char * ); }
extern "C" { int YYWarning( char * ); }

Export *pExport = 0L;

// defines to parse command line
#define STATE_NON  		0x0001
#define STATE_INPUT		0x0002
#define STATE_OUTPUT	0x0003
#define STATE_PRJ		0x0004
#define STATE_ROOT		0x0005
#define STATE_MERGESRC	0x0006
#define STATE_ERRORLOG	0x0007
#define STATE_BREAKHELP	0x0008
#define STATE_UNMERGE	0x0009
#define STATE_UTF8		0x000A
#define STATE_LANGUAGES	0X000B

// set of global variables
DECLARE_LIST( FileList, ByteString * )
FileList aInputFileList;
BOOL bEnableExport;
BOOL bMergeMode;
BOOL bErrorLog;
BOOL bBreakWhenHelpText;
BOOL bUnmerge;
BOOL bUTF8;
ByteString sPrj;
ByteString sPrjRoot;
ByteString sActFileName;
ByteString sOutputFile;
ByteString sMergeSrc;
ByteString sTempFile;
ByteString sFile;
MergeDataFile *pMergeDataFile;
FILE *pTempFile;


ByteString sStrBuffer;
bool bMarcro = false;

extern "C" {
// the whole interface to lexer is in this extern "C" section


/*****************************************************************************/
extern char *GetOutputFile( int argc, char* argv[])
/*****************************************************************************/
{
    bEnableExport = FALSE;
    bMergeMode = FALSE;
    bErrorLog = TRUE;
    bBreakWhenHelpText = FALSE;
    bUnmerge = FALSE;
    bUTF8 = TRUE;
    sPrj = "";
    sPrjRoot = "";
    sActFileName = "";
    Export::sLanguages = "";
    Export::sForcedLanguages = "";
    sTempFile = "";
    pTempFile = NULL;
    USHORT nState = STATE_NON;
    BOOL bInput = FALSE;

    // parse command line
    for( int i = 1; i < argc; i++ ) {
        ByteString sSwitch( argv[ i ] );
        
        if (sSwitch == "-i"  || sSwitch == "-I" ) {
            nState = STATE_INPUT; // next tokens specifies source files
        }
        else if (sSwitch == "-o"  || sSwitch == "-O" ) {
            nState = STATE_OUTPUT; // next token specifies the dest file
        }
        else if (sSwitch == "-p"  || sSwitch == "-P" ) {
            nState = STATE_PRJ; // next token specifies the cur. project
        }

        else if (sSwitch == "-r"  || sSwitch == "-R" ) {
            nState = STATE_ROOT; // next token specifies path to project root
        }
        else if (sSwitch == "-m"  || sSwitch == "-M" ) {
            nState = STATE_MERGESRC; // next token specifies the merge database
        }
        else if (sSwitch == "-e"  || sSwitch == "-E" ) {
            nState = STATE_ERRORLOG;
            bErrorLog = FALSE;
        }
        else if (sSwitch == "-b"  || sSwitch == "-B" ) {
            nState = STATE_BREAKHELP;
            bBreakWhenHelpText = TRUE;
        }
        else if (sSwitch == "-u"  || sSwitch == "-U" ) {
            nState = STATE_UNMERGE;
            bUnmerge = TRUE;
            bMergeMode = TRUE;
        }
        else if ( sSwitch.ToUpperAscii() == "-UTF8" ) {
            nState = STATE_UTF8;
            bUTF8 = TRUE;
        }
        else if ( sSwitch.ToUpperAscii() == "-NOUTF8" ) {
            nState = STATE_UTF8;
            bUTF8 = FALSE;
        }
        else if ( sSwitch == "-l"  || sSwitch == "-L" ) {
            nState = STATE_LANGUAGES;
        }
        else {
            switch ( nState ) {
                case STATE_NON: {
                    return NULL;	// no valid command line
                }
                case STATE_INPUT: {
                    aInputFileList.Insert( new ByteString( argv[ i ]), LIST_APPEND );
                    bInput = TRUE; // min. one source file found
                }
                break;
                case STATE_OUTPUT: {
                    sOutputFile = ByteString( argv[ i ]); // the dest. file
                }
                break;
                case STATE_PRJ: {
                    sPrj = ByteString( argv[ i ]);
                }
                break;
                case STATE_ROOT: {
                    sPrjRoot = ByteString( argv[ i ]); // path to project root
                }
                break;
                case STATE_MERGESRC: {
                    sMergeSrc = ByteString( argv[ i ]);
                    bMergeMode = TRUE; // activate merge mode, cause merge database found
                }
                break;
                case STATE_LANGUAGES: {
                    Export::sLanguages = ByteString( argv[ i ]);
                }
                break;
            }
        }
    }
    if( bUnmerge ) sMergeSrc = ByteString();
    if ( bInput ) {
        // command line is valid
        bEnableExport = TRUE;
        char *pReturn = new char[ sOutputFile.Len() + 1 ];
        strcpy( pReturn, sOutputFile.GetBuffer());  // #100211# - checked
        return pReturn;
    }

    // command line is not valid
    return NULL;
}
/*****************************************************************************/
int InitExport( char *pOutput , char* pFilename )
/*****************************************************************************/
{
    // instanciate Export
    ByteString sOutput( pOutput );
    ByteString sFilename( pFilename );

    if ( bMergeMode && !bUnmerge ) {
        // merge mode enabled, so read database
        pExport = new Export(sOutput, bEnableExport, sPrj, sPrjRoot, sMergeSrc , sFilename );
    }
    else
        // no merge mode, only export
        pExport = new Export( sOutput, bEnableExport, sPrj, sPrjRoot , sFilename );
    return 1;
}

/*****************************************************************************/
int EndExport()
/*****************************************************************************/
{
    delete pExport;
    return 1;
}

extern const char* getFilename()
{
    return (*(aInputFileList.GetObject( 0 ))).GetBuffer();
}
/*****************************************************************************/
extern FILE *GetNextFile()
/*****************************************************************************/
{
    // look for next valid filename in input file list
    if ( sTempFile.Len()) {
        fclose( pTempFile );
        String sTemp( sTempFile, RTL_TEXTENCODING_ASCII_US );
        DirEntry aTemp( sTemp );
        aTemp.Kill();
    }

    while ( aInputFileList.Count()) {
        ByteString sFileName( *(aInputFileList.GetObject( 0 )));

        ByteString sOrigFile( sFileName );

        sFileName = Export::GetNativeFile( sFileName );
        delete aInputFileList.GetObject(( ULONG ) 0 );
        aInputFileList.Remove(( ULONG ) 0 );

        if ( sFileName == "" ) {
            fprintf( stderr, "ERROR: Could not precompile File %s\n",
                sOrigFile.GetBuffer());
            return GetNextFile();
        }

        sTempFile = sFileName;
        Export::RemoveUTF8ByteOrderMarkerFromFile( sFileName );
        
        // able to open file?
        FILE *pFile = fopen( sFileName.GetBuffer(), "r" );
        if ( !pFile )
            fprintf( stderr, "Error: Could not open File %s\n",
                sFileName.GetBuffer());
        else {
            pTempFile = pFile;

            // this is a valid file which can be opened, so
            // create path to project root
            DirEntry aEntry( String( sOrigFile, RTL_TEXTENCODING_ASCII_US ));
            aEntry.ToAbs();
            ByteString sFullEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US );
            aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US ));
            aEntry += DirEntry( sPrjRoot );
            ByteString sPrjEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US );

            // create file name, beginnig with project root
            // (e.g.: source\ui\src\menue.src)
            sActFileName = sFullEntry.Copy( sPrjEntry.Len() + 1 );


            sActFileName.SearchAndReplaceAll( "/", "\\" );
            sFile = sActFileName;
            
            if ( pExport ) {
                // create instance of class export
                pExport->Init();
            }
            // return the valid file handle
            return pFile;
        }
    }
    // this means the file could not be opened
    return NULL;
}

int Parse( int nTyp, const char *pTokenText ){
    pExport->Execute( nTyp , pTokenText );    
    return 1;
}
void Close(){
    pExport->pParseQueue->Close();
}
/*****************************************************************************/
int WorkOnTokenSet( int nTyp, char *pTokenText )
/*****************************************************************************/
{

    pExport->pParseQueue->Push( QueueEntry( nTyp , ByteString( pTokenText ) ) );
    return 1;
}

} // extern

extern "C" {
/*****************************************************************************/
int SetError()
/*****************************************************************************/
{
    // set error at global instance of class Export
    pExport->SetError();
    return 1;
}
}

extern "C" {
/*****************************************************************************/
int GetError()
/*****************************************************************************/
{
    // get error at global instance of class Export
    if ( pExport->GetError())
        return 1;
    return FALSE;
}
}

//
// class ResData
//

void ResData::Dump(){
    printf("**************\nResData\n");
    printf("sPForm = %s , sResTyp = %s , sId = %s , sGId = %s , sHelpId = %s\n",sPForm.GetBuffer()
        ,sResTyp.GetBuffer(),sId.GetBuffer(),sGId.GetBuffer(),sHelpId.GetBuffer());

    ByteString a("*pStringList");
    ByteString b("*pUIEntries");
    ByteString c("*pFilterList");
    ByteString d("*pItemList");
    ByteString e("*pPairedList");
    ByteString f("sText");

    Export::DumpMap( f , sText );
    
    if( pStringList )	Export::DumpExportList( a , *pStringList );
    if( pUIEntries )	Export::DumpExportList( b , *pUIEntries );
    if( pFilterList )	Export::DumpExportList( c , *pFilterList );
    if( pItemList )		Export::DumpExportList( d , *pItemList );
    if( pPairedList )	Export::DumpExportList( e , *pPairedList );
    printf("\n");
}

void ResData::addFallbackData( ByteString& sId_in , const ByteString& sText_in ){
    //printf(" ResData::addFallbackData ( sId = %s , sText = %s )\n", sId_in.GetBuffer() , sText_in.GetBuffer() );
    aFallbackData[ sId_in ] = sText_in;
}
bool ResData::getFallbackData( ByteString& sId_in , ByteString& sText_inout ){
    sText_inout = aFallbackData[ sId_in ];
    //printf("ResData::getFallbackData( sId = %s , return sText = %s \n" , sId_in.GetBuffer(), sText_inout.GetBuffer());
    return sText_inout.Len() > 0;
}

void ResData::addMergedLanguage( ByteString& sLang ){
    aMergedLanguages[ sLang ]=ByteString("1");
}
bool ResData::isMerged( ByteString& sLang ){
    return aMergedLanguages[ sLang ].Equals("1");
}

/*****************************************************************************/
BOOL ResData::SetId( const ByteString &rId, USHORT nLevel )
/*****************************************************************************/
{
    if ( nLevel > nIdLevel )
    {
        nIdLevel = nLevel;
        sId = rId;

        if ( bChild && bChildWithText ) {
            ByteString sError( "ResId after child definition" );
            yyerror( sError.GetBufferAccess());
            sError.ReleaseBufferAccess();
            SetError();
        }

        if ( sId.Len() > 255 ) {
            ByteString sWarning( "LocalId > 255 chars, truncating..." );
            YYWarning( sWarning.GetBufferAccess());
            sWarning.ReleaseBufferAccess();
            sId.Erase( 255 );
            sId.EraseTrailingChars( ' ' );
            sId.EraseTrailingChars( '\t' );
        }

        return TRUE;
    }

    return FALSE;
}

//
// class Export
//

/*****************************************************************************/
Export::Export( const ByteString &rOutput, BOOL bWrite,
                const ByteString &rPrj, const ByteString &rPrjRoot , const ByteString& rFile )
/*****************************************************************************/
                :
                pWordTransformer( NULL ),
                aCharSet( RTL_TEXTENCODING_MS_1252 ),
                bDefine( FALSE ),
                bNextMustBeDefineEOL( FALSE ),
                nLevel( 0 ),
                nList( LIST_NON ),
                nListIndex( 0 ),
                nListLevel( 0 ),
                bSkipFile( false ),
                sProject( sPrj ),
                sRoot( sPrjRoot ),
                bEnableExport( bWrite ),
                bMergeMode( bUnmerge ),
                bError( FALSE ),
                bReadOver( FALSE ),
                bDontWriteOutput( FALSE ),
                sFilename( rFile )
{
    pParseQueue = new ParserQueue( *this );
    (void) rPrj;
    (void) rPrjRoot;
    (void) rFile;
    
    if( !isInitialized ) InitLanguages();
    // used when export is enabled

    // open output stream
    if ( bEnableExport ) {
        aOutput.Open( String( rOutput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC );
        if( !aOutput.IsOpen() ) {
            printf("ERROR : Can't open file %s\n",rOutput.GetBuffer());
            exit ( -1 );
        }
        aOutput.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );

        aOutput.SetLineDelimiter( LINEEND_CRLF );
    }
}

/*****************************************************************************/
Export::Export( const ByteString &rOutput, BOOL bWrite,
                const ByteString &rPrj, const ByteString &rPrjRoot,
                const ByteString &rMergeSource , const ByteString& rFile )
/*****************************************************************************/
                :
                pWordTransformer( NULL ),
                aCharSet( RTL_TEXTENCODING_MS_1252 ),
                bDefine( FALSE ),
                bNextMustBeDefineEOL( FALSE ),
                nLevel( 0 ),
                nList( LIST_NON ),
                nListIndex( 0 ),
                nListLevel( 0 ),
                bSkipFile( false ),
                sProject( sPrj ),
                sRoot( sPrjRoot ),
                bEnableExport( bWrite ),
                bMergeMode( TRUE ),
                sMergeSrc( rMergeSource ),
                bError( FALSE ),
                bReadOver( FALSE ),
                bDontWriteOutput( FALSE ),
                sFilename( rFile )
{
    (void) rPrj;
    (void) rPrjRoot;
    (void) rFile;
    pParseQueue = new ParserQueue( *this );
    if( !isInitialized ) InitLanguages( bMergeMode );
    // used when merge is enabled

    // open output stream
    if ( bEnableExport ) {
        aOutput.Open( String( rOutput, RTL_TEXTENCODING_ASCII_US ), STREAM_STD_WRITE | STREAM_TRUNC );
        aOutput.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
        aOutput.SetLineDelimiter( LINEEND_CRLF );
    }

}

/*****************************************************************************/
void Export::Init()
/*****************************************************************************/
{
    // resets the internal status, used before parseing another file
    sActPForm = "";
    bDefine = FALSE;
    bNextMustBeDefineEOL = FALSE;
    nLevel = 0;
    nList = LIST_NON;
    nListLang = ByteString( String::CreateFromAscii(""),RTL_TEXTENCODING_ASCII_US );
    nListIndex = 0;
    while ( aResStack.Count()) {
        delete aResStack.GetObject(( ULONG ) 0 );
        aResStack.Remove(( ULONG ) 0 );
    }
}

/*****************************************************************************/
Export::~Export()
/*****************************************************************************/
{
    if( pParseQueue ) 
        delete pParseQueue;
    // close output stream
    if ( bEnableExport )
        aOutput.Close();
    while ( aResStack.Count()) {
        delete aResStack.GetObject(( ULONG ) 0 );
        aResStack.Remove(( ULONG ) 0 );
    }

    if ( bMergeMode && !bUnmerge ) {
        if ( !pMergeDataFile )
            pMergeDataFile = new MergeDataFile( sMergeSrc,sFile , bErrorLog, aCharSet);//, bUTF8 );

        //pMergeDataFile->WriteErrorLog( sActFileName );
        delete pMergeDataFile;
    }
}

/*****************************************************************************/
int Export::Execute( int nToken, const char * pToken )
/*****************************************************************************/
{
    
    ByteString sToken( pToken );
    ByteString sOrig( sToken );
/*	printf("+---------------\n");
    printf("sToken = %s\n",sToken.GetBuffer());
    printf("nToken = %d\n",nToken);
    printf("+---------------\n"); */
    BOOL bWriteToMerged = bMergeMode;

    if ( nToken == CONDITION ) {
        ByteString sTestToken( pToken );
        sTestToken.EraseAllChars( '\t' );
        sTestToken.EraseAllChars( ' ' );
        if (( !bReadOver ) && ( sTestToken.Search( "#ifndef__RSC_PARSER" ) == 0 ))
            bReadOver = TRUE;
        else if (( bReadOver ) && ( sTestToken.Search( "#endif" ) == 0 ))
            bReadOver = FALSE;
    }
    if ((( nToken < FILTER_LEVEL ) || ( bReadOver )) &&
        (!(( bNextMustBeDefineEOL ) && ( sOrig == "\n" )))) {
        // this tokens are not mandatory for parsing, so ignore them ...
        if ( bMergeMode )
            WriteToMerged( sOrig , false ); // ... ore whrite them directly to dest.
        return 0;
    }

    ResData *pResData = NULL;
    if ( nLevel ) {
        // res. exists at cur. level
        pResData = aResStack.GetObject( nLevel-1 );
    }
    else if (( nToken != RESSOURCE ) &&
            ( nToken != RESSOURCEEXPR ) &&
            ( nToken != SMALRESSOURCE ) &&
            ( nToken != LEVELUP ) &&
            ( nToken != NORMDEFINE ) &&
            ( nToken != RSCDEFINE ) &&
            ( nToken != CONDITION ) &&
            ( nToken != PRAGMA ))
    {
        // no res. exists at cur. level so return
        if ( bMergeMode )
            WriteToMerged( sOrig , false );		
        return 0;
    }
    // #define NO_LOCALIZE_EXPORT
    if( bSkipFile ){  
        if ( bMergeMode ) {
            WriteToMerged( sOrig , false );
        }
        return 1;
    }


    if ( bDefine ) {
        if (( nToken != EMPTYLINE ) && ( nToken != LEVELDOWN ) && ( nToken != LEVELUP )) {
            // cur. res. defined in macro
            if ( bNextMustBeDefineEOL ) {
                if ( nToken != RSCDEFINELEND ) {
                    // end of macro found, so destroy res.
                    bDefine = FALSE;
                    if ( bMergeMode ) {
                        /*if ( bDontWriteOutput && bUnmerge ) {
                            bDontWriteOutput = FALSE;
                            bNextMustBeDefineEOL = FALSE;
                            bDefine = TRUE;
                        }*/
                        MergeRest( pResData );
                    }
                    bNextMustBeDefineEOL = FALSE;
                    Execute( LEVELDOWN, "" );
                }
                else {
                    // next line also in macro definition
                    bNextMustBeDefineEOL = FALSE;
                    if ( bMergeMode )
                        WriteToMerged( sOrig , false );
                    return 1;
                }
            }
            else if (( nToken != LISTASSIGNMENT ) && ( nToken != UIENTRIES )){
                // cur. line has macro line end
                ByteString sTmpLine( sToken );
                sTmpLine.EraseAllChars( '\t' ); sTmpLine.EraseAllChars( ' ' );
            }
        }
    }

    BOOL bExecuteDown = FALSE;
    if ( nToken != LEVELDOWN ) {
        USHORT nOpen = 0;
        USHORT nClose = 0;
        BOOL bReadOver1 = FALSE;
        USHORT i = 0; 
        for ( i = 0; i < sToken.Len(); i++ ) {
            if ( sToken.GetChar( i ) == '\"' )
                bReadOver1 = !bReadOver1;
            if ( !bReadOver1 && ( sToken.GetChar( i ) == '{' ))
                nOpen++;
        }

        bReadOver1 = FALSE;
        for ( i = 0; i < sToken.Len(); i++ ) {
            if ( sToken.GetChar( i ) == '\"' )
                bReadOver1 = !bReadOver1;
            if ( !bReadOver1 && ( sToken.GetChar( i ) == '}' ))
                nClose++;
        }

        if ( nOpen < nClose )
            bExecuteDown = TRUE;
    }
    switch ( nToken ) {
        
        case NORMDEFINE:
                        //printf("sToken = '%s'",sToken.GetBuffer());
                        while( sToken.SearchAndReplace( "\r", " " ) != STRING_NOTFOUND ) {};
                        while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
                        while( sToken.SearchAndReplace( "  ", " " ) != STRING_NOTFOUND ) {};
                        if( sToken.EqualsIgnoreCaseAscii( "#define NO_LOCALIZE_EXPORT" ) ){
                            bSkipFile = true;
                            return 0;
                        }
                        if ( bMergeMode )
                          WriteToMerged( sOrig , false );     
                            
                        return 0;
                        
 
        case RSCDEFINE:
            bDefine = TRUE; // res. defined in macro

        case RESSOURCE:
        case RESSOURCEEXPR: {
            bDontWriteOutput = FALSE;
            if ( nToken != RSCDEFINE )
                bNextMustBeDefineEOL = FALSE;
            // this is the beginning of a new res.
            nLevel++;
            if ( nLevel > 1 ) {
                aResStack.GetObject( nLevel - 2 )->bChild = TRUE;
            }

            // create new instance for this res. and fill mandatory fields

            pResData = new ResData( sActPForm, FullId() , sFilename );
            aResStack.Insert( pResData, LIST_APPEND );
            ByteString sBackup( sToken );
            sToken.EraseAllChars( '\n' );
            sToken.EraseAllChars( '\r' );
            sToken.EraseAllChars( '{' );
            while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
            sToken.EraseTrailingChars( ' ' );
            ByteString sT =  sToken.GetToken( 0, ' ' );
            pResData->sResTyp = sT.ToLowerAscii();
            ByteString sId( sToken.Copy( pResData->sResTyp.Len() + 1 ));
            ByteString sCondition;
            if ( sId.Search( "#" ) != STRING_NOTFOUND ) {
                // between ResTyp, Id and paranthes is a precomp. condition
                sCondition = "#";
                sCondition += sId.GetToken( 1, '#' );
                sId = sId.GetToken( 0, '#' );
            }
            sId = sId.GetToken( 0, '/' );
            CleanValue( sId );
            sId = sId.EraseAllChars( '\t' );
            pResData->SetId( sId, ID_LEVEL_IDENTIFIER );
            if ( sCondition.Len()) {
                ByteString sEmpty( "" );
                Execute( CONDITION, sEmpty.GetBufferAccess()); 	// execute the
                                                                  // precomp.
                                                                // condition
                sEmpty.ReleaseBufferAccess();
            }
        }
        break;
        case SMALRESSOURCE: {
            bDontWriteOutput = FALSE;
            // this is the beginning of a new res.
            bNextMustBeDefineEOL = FALSE;
            nLevel++;
            if ( nLevel > 1 ) {
                aResStack.GetObject( nLevel - 2 )->bChild = TRUE;
            }

            // create new instance for this res. and fill mandatory fields

            pResData = new ResData( sActPForm, FullId() , sFilename );
            aResStack.Insert( pResData, LIST_APPEND );
            sToken.EraseAllChars( '\n' );
            sToken.EraseAllChars( '\r' );
            sToken.EraseAllChars( '{' );
            sToken.EraseAllChars( '\t' );
            sToken.EraseAllChars( ' ' );
            sToken.EraseAllChars( '\\' );
            pResData->sResTyp = sToken.ToLowerAscii();
        }
        break;
        case LEVELUP: {
            // push
            if ( nList )
                nListLevel++;
            if ( nList )
                break;

            bDontWriteOutput = FALSE;
            ByteString sLowerTyp;
            if ( pResData )
                sLowerTyp = "unknown";
            nLevel++;
            if ( nLevel > 1 ) {
                aResStack.GetObject( nLevel - 2 )->bChild = TRUE;
            }

            ResData *pNewData = new ResData( sActPForm, FullId() , sFilename );
            pNewData->sResTyp = sLowerTyp;
            aResStack.Insert( pNewData, LIST_APPEND );
        }
        break;
        case LEVELDOWN: {
            // pop
            if ( !nList  ) {
                bDontWriteOutput = FALSE;
                if ( nLevel ) {
                    if ( bDefine && (nLevel == 1 )) {
                        bDefine = FALSE;
                        bNextMustBeDefineEOL = FALSE;
                    }
                    WriteData( pResData );
                    delete aResStack.GetObject( nLevel - 1 );
                    aResStack.Remove( nLevel - 1 );
                    nLevel--;
                }
            }
            else {
                if ( bDefine )
                    bNextMustBeDefineEOL = TRUE;
                if ( !nListLevel ) {
                    if ( bMergeMode )
                        MergeRest( pResData, MERGE_MODE_LIST );
                    nList = LIST_NON;
                }
                else
                    nListLevel--;
            }
        } 
        break;
        case ASSIGNMENT: {
            bDontWriteOutput = FALSE;
            // interpret different types of assignement
             ByteString sKey = sToken.GetToken( 0, '=' );
            sKey.EraseAllChars( ' ' );
            sKey.EraseAllChars( '\t' );
            ByteString sValue = sToken.GetToken( 1, '=' );
            CleanValue( sValue );
            if ( sKey.ToUpperAscii() == "IDENTIFIER" ) {
                ByteString sId( sValue.EraseAllChars( '\t' ));
                pResData->SetId( sId.EraseAllChars( ' ' ), ID_LEVEL_IDENTIFIER );
            }
            else if ( sKey == "HELPID" ) {
                pResData->sHelpId = sValue;
            }
            else if ( sKey == "STRINGLIST" ) {
                //if ( bUnmerge ){
                //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                //}

                pResData->bList = TRUE;
                nList = LIST_STRING;
                //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                nListLang = SOURCE_LANGUAGE;
                nListIndex = 0;
                nListLevel = 0;
            }
            else if ( sKey == "FILTERLIST" ) {
                //if ( bUnmerge ){
                //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                //}
                pResData->bList = TRUE;
                nList = LIST_FILTER;
                //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                nListLang = SOURCE_LANGUAGE;
                nListIndex = 0;
                nListLevel = 0;
            }
            else if ( sKey == "UIENTRIES" ) {
                //if ( bUnmerge ){
                //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));}
                pResData->bList = TRUE;
                nList = LIST_UIENTRIES;
                //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                nListLang = SOURCE_LANGUAGE;
                nListIndex = 0;
                nListLevel = 0;
            }
            if (( sToken.Search( "{" ) != STRING_NOTFOUND ) &&
                ( sToken.GetTokenCount( '{' ) > sToken.GetTokenCount( '}' )))
            {
                //WorkOnTokenSet( LEVELUP, pTkn );
                Parse( LEVELUP, "" );
            }
            //if ( bUnmerge && ( nListLang.EqualsIgnoreCaseAscii("de") || nListLang.EqualsIgnoreCaseAscii("en-US") ) && ListExists( pResData, nList ))
            //	bDontWriteOutput = TRUE;
         }
        break;
        case UIENTRIES:
        case LISTASSIGNMENT: {
            bDontWriteOutput = FALSE;
            ByteString sTmpToken( sToken);
            sTmpToken.EraseAllChars(' ');
            USHORT nPos = 0;
            //nPos = sTmpToken.ToLowerAscii().Search("[de]=");
            nPos = sTmpToken.ToLowerAscii().Search("[en-us]=");
            if( nPos != STRING_NOTFOUND ) {
                //if ( bUnmerge ){
                //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                //}
                ByteString sKey = sTmpToken.Copy( 0 , nPos );
                sKey.EraseAllChars( ' ' );
                sKey.EraseAllChars( '\t' );
                ByteString sValue = sToken.GetToken( 1, '=' );
                CleanValue( sValue );
                if ( sKey.ToUpperAscii() ==  "STRINGLIST" ) {
                    pResData->bList = TRUE;
                    nList = LIST_STRING;
                    //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                    nListLang = SOURCE_LANGUAGE;
                    nListIndex = 0;
                    nListLevel = 0;
                }
                else if ( sKey == "FILTERLIST" ) {
                    pResData->bList = TRUE;
                    nList = LIST_FILTER;
                    //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                    nListLang = SOURCE_LANGUAGE;
                    nListIndex = 0;
                    nListLevel = 0;
                }
                // PairedList
                else if ( sKey ==  "PAIREDLIST" ) {
                    pResData->bList = TRUE;
                    nList = LIST_PAIRED;
                    //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                    nListLang = SOURCE_LANGUAGE;
                    nListIndex = 0;
                    nListLevel = 0;
                }

                else if ( sKey ==  "ITEMLIST" ) {
                    pResData->bList = TRUE;
                    nList = LIST_ITEM;
                    //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                    nListLang = SOURCE_LANGUAGE;
                    nListIndex = 0;
                    nListLevel = 0;
                }
                else if ( sKey ==  "UIENTRIES" ) {
                    pResData->bList = TRUE;
                    nList = LIST_UIENTRIES;
                    //ByteString sLang("en-US" , RTL_TEXTENCODING_ASCII_US );
                    nListLang = SOURCE_LANGUAGE;
                    nListIndex = 0;
                    nListLevel = 0;
                }
                /*if ( bUnmerge && ( nListLang.EqualsIgnoreCaseAscii( "de" )  
                    || nListLang.EqualsIgnoreCaseAscii("en-US" ) )
                    && ListExists( pResData, nList ))
                    bDontWriteOutput = TRUE;*/
            }
            else {
                // new res. is a String- or FilterList
                ByteString sKey = sToken.GetToken( 0, '[' );
                sKey.EraseAllChars( ' ' );
                sKey.EraseAllChars( '\t' );
                if ( sKey.ToUpperAscii() == "STRINGLIST" )
                    nList = LIST_STRING;
                else if ( sKey == "FILTERLIST" )
                    nList = LIST_FILTER;
                else if ( sKey == "PAIREDLIST" )
                    nList = LIST_PAIRED;				// abcd
                else if ( sKey == "ITEMLIST" )
                    nList = LIST_ITEM;
                else if ( sKey == "UIENTRIES" )
                    nList = LIST_UIENTRIES;
                if ( nList ) {
                    ByteString sLang=sToken.GetToken( 1, '[' ).GetToken( 0, ']' );
                    CleanValue( sLang );
                    nListLang = sLang;
                    /*if (( bUnmerge ) && ( !nListLang.EqualsIgnoreCaseAscii("de")) && ( !nListLang.EqualsIgnoreCaseAscii("en-US")))
                        bDontWriteOutput = TRUE;*/
                    nListIndex = 0;
                    nListLevel = 0;
                    /*if ( bUnmerge && nListLang.EqualsIgnoreCaseAscii("de")  && ListExists( pResData, nList ) )
                        bDontWriteOutput = TRUE;*/
                }
            }
        }
        break;
        case TEXT:
        case _LISTTEXT:
        case LISTTEXT: {
            // this is an entry for a String- or FilterList
            if ( nList ) {
                SetChildWithText();
                ByteString sEntry( sToken.GetToken( 1, '\"' ));
                if ( sToken.GetTokenCount( '\"' ) > 3 )
                    sEntry += "\"";
                if ( sEntry == "\\\"" )
                    sEntry = "\"";
                //sEntry = sEntry.Convert( aCharSet, RTL_TEXTENCODING_MS_1252 );
                //sEntry = sEntry.Convert( RTL_TEXTENCODING_MS_1252, RTL_TEXTENCODING_UTF8 );
                InsertListEntry( sEntry, sOrig );
                if ( bMergeMode && ( sEntry != "\"" )) {
                    PrepareTextToMerge( sOrig, nList, nListLang, pResData );
                }
            }
        }
        break;
        case LONGTEXTLINE:
        case TEXTLINE:
            bDontWriteOutput = FALSE;
            if ( nLevel ) {
                CutComment( sToken );

                // this is a text line!!!
                ByteString sKey = sToken.GetToken( 0, '=' ).GetToken( 0, '[' );
                sKey.EraseAllChars( ' ' );
                sKey.EraseAllChars( '\t' );
                ByteString sText( GetText( sToken, nToken ));
                if ( !bMergeMode )
                    sText = sText.Convert( aCharSet, RTL_TEXTENCODING_MS_1252 );
                ByteString sLang;
                if ( sToken.GetToken( 0, '=' ).Search( "[" ) != STRING_NOTFOUND ) {
                     sLang = sToken.GetToken( 0, '=' ).GetToken( 1, '[' ).GetToken( 0, ']' );
                    CleanValue( sLang );
                }
                ByteString nLangIndex = sLang;
                ByteString sOrigKey = sKey;
                if ( sText.Len() && sLang.Len() ) {
                    if (( sKey.ToUpperAscii() == "TEXT" ) ||
                        ( sKey == "MESSAGE" ) ||
                        ( sKey == "CUSTOMUNITTEXT" ) ||
                        ( sKey == "SLOTNAME" ) ||
                        ( sKey == "UINAME" ))
                    {
                        //if ( bUnmerge && sToken.GetToken( 0, '=' ).Search( "[" ) == STRING_NOTFOUND )
                        //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                        
                        SetChildWithText();
                        //if ( nLangIndex.EqualsIgnoreCaseAscii("en-US") )
                        if ( Export::isSourceLanguage( nLangIndex ) )						
                            pResData->SetId( sText, ID_LEVEL_TEXT );

                        pResData->bText = TRUE;
                        pResData->sTextTyp = sOrigKey;
                        if ( bMergeMode ) {
                            PrepareTextToMerge( sOrig, STRING_TYP_TEXT, nLangIndex, pResData );
                            //if ( bUnmerge )
                            //	pResData->sText[ nLangIndex ] = sText;
                        }
                        else {
                            if ( pResData->sText[ nLangIndex ].Len()) {
                                ByteString sError( "Language " );
                                sError += nLangIndex;
                                sError += " defined twice";
                            }
                            pResData->sText[ nLangIndex ] = sText;
                        }
                    }
                    else if ( sKey == "HELPTEXT" ) {
                        //if ( bUnmerge && sToken.GetToken( 0, '=' ).Search( "[" ) == STRING_NOTFOUND ){
                        //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                        //	}
                        SetChildWithText();
                        pResData->bHelpText = TRUE;
                        if ( bBreakWhenHelpText ) {
                            ByteString sError( "\"HelpText\" found in source\n" );
                            YYWarning( sError.GetBufferAccess());
                            sError.ReleaseBufferAccess();
                            SetError();
                        }
                        if ( bMergeMode )
                            PrepareTextToMerge( sOrig, STRING_TYP_HELPTEXT, nLangIndex, pResData );
                            //if ( bUnmerge )
                            //	pResData->sHelpText[ nLangIndex ] = sText;
                        else {
                            if ( pResData->sHelpText[ nLangIndex ].Len()) {
                                ByteString sError( "Language " );
                                sError += nLangIndex;
                                sError += " defined twice";
                            }
                            pResData->sHelpText[ nLangIndex ] = sText;
                        }
                    }
                    else if ( sKey == "QUICKHELPTEXT" ) {
                        //if ( bUnmerge && sToken.GetToken( 0, '=' ).Search( "[" ) == STRING_NOTFOUND ){
                        //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                        //	}
                        SetChildWithText();
                        pResData->bQuickHelpText = TRUE;
                        if ( bMergeMode )
                            PrepareTextToMerge( sOrig, STRING_TYP_QUICKHELPTEXT, nLangIndex, pResData );
                            //if ( bUnmerge )
                            //	pResData->sQuickHelpText[ nLangIndex ] = sText;
                        else {
                            if ( pResData->sQuickHelpText[ nLangIndex ].Len()) {
                                ByteString sError( "Language " );
                                sError += nLangIndex;
                                sError += " defined twice";
                            }
                            pResData->sQuickHelpText[ nLangIndex ] = sText;
                        }
                    }
                    else if ( sKey == "TITLE" ) {
                        //if ( bUnmerge && sToken.GetToken( 0, '=' ).Search( "[" ) == STRING_NOTFOUND ){
                        //	( sOrig.SearchAndReplace( "=", "[ de ] =" ));
                        //	}
                        SetChildWithText();
                        pResData->bTitle = TRUE;
                        if ( bMergeMode )
                            PrepareTextToMerge( sOrig, STRING_TYP_TITLE, nLangIndex, pResData );
                            //if ( bUnmerge )
                            //	pResData->sTitle[ nLangIndex ] = sText;
                        else {
                            if ( pResData->sTitle[ nLangIndex ].Len()) {
                                ByteString sError( "Language " );
                                sError += nLangIndex;
                                sError += " defined twice";
                            }
                            pResData->sTitle[ nLangIndex ] = sText;
                        }
                    }
                    else if ( sKey == "ACCESSPATH" ) {
                        pResData->SetId( sText, ID_LEVEL_ACCESSPATH );
                    }
                    else if ( sKey == "FIELDNAME" ) {
                        pResData->SetId( sText, ID_LEVEL_FIELDNAME );
                    }
                }
            }
        break;
        case NEWTEXTINRES: {
            bDontWriteOutput = TRUE;
            // this means something like // ### Achtung : Neuer Text ...
            /*ByteString sLang( "GERMAN" );
            ByteString sText = sToken.GetToken( 2, ':' ).GetToken( 0, '*' );
            CleanValue( sText );
            if ( sText.Len())
                pResData->sText[ sLang ] = sText;*/
        }
        break;
        case APPFONTMAPPING: {
            bDontWriteOutput = FALSE;
            // this is a AppfontMapping, so look if its a definition
            // of field size
            ByteString sKey = sToken.GetToken( 0, '=' );
            sKey.EraseAllChars( ' ' );
            sKey.EraseAllChars( '\t' );
            ByteString sMapping = sToken.GetToken( 1, '=' );
            sMapping = sMapping.GetToken( 1, '(' );
            sMapping = sMapping.GetToken( 0, ')' );
            sMapping.EraseAllChars( ' ' );
            sMapping.EraseAllChars( '\t' );
            if ( sKey.ToUpperAscii() == "SIZE" ) {
                pResData->nWidth = ( USHORT ) sMapping.GetToken( 0, ',' ).ToInt64();
            }
            else if ( sKey == "POSSIZE" ) {
                pResData->nWidth = ( USHORT ) sMapping.GetToken( 2, ',' ).ToInt64();
            }
        }
        break;
        case RSCDEFINELEND:
            bDontWriteOutput = FALSE;
        break;
        case CONDITION: {
            bDontWriteOutput = FALSE;
            while( sToken.SearchAndReplace( "\r", " " ) != STRING_NOTFOUND ) {};
            while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
            while( sToken.SearchAndReplace( "  ", " " ) != STRING_NOTFOUND ) {};
            ByteString sCondition = sToken.GetToken( 0, ' ' );
            if ( sCondition == "#ifndef" ) {
                sActPForm = "!defined ";
                sActPForm += sToken.GetToken( 1, ' ' );
            }
            else if ( sCondition == "#ifdef" ) {
                sActPForm = "defined ";
                sActPForm += sToken.GetToken( 1, ' ' );
            }
            else if ( sCondition == "#if" ) {
                sActPForm = sToken.Copy( 4 );
                while ( sActPForm.SearchAndReplace( "||", "\\or" ) != STRING_NOTFOUND ) {};
            }
            else if ( sCondition == "#elif" ) {
                sActPForm = sToken.Copy( 6 );
                while ( sActPForm.SearchAndReplace( "||", "\\or" ) != STRING_NOTFOUND ) {};
            }
            else if ( sCondition == "#else" ) {
                sActPForm = sCondition;
            }
            else if ( sCondition == "#endif" ) {
                sActPForm = "";
            }
            else break;
            if ( nLevel ) {
                WriteData( pResData, TRUE );
                pResData->sPForm = sActPForm;
            }
        }
        break;
        case EMPTYLINE : {
            bDontWriteOutput = FALSE;
            if ( bDefine ) {
                bNextMustBeDefineEOL = FALSE;
                bDefine = FALSE;
                while ( nLevel )
                    Parse( LEVELDOWN, "" );
                    //WorkOnTokenSet( LEVELDOWN, pTkn );
            }
        }
        break;
        case PRAGMA : {
            bDontWriteOutput = FALSE;
            while( sToken.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
            while( sToken.SearchAndReplace( "  ", " " ) != STRING_NOTFOUND ) {};
            sToken.EraseLeadingChars( ' ' );
            sToken.EraseTrailingChars( ' ' );

            ByteString sCharset = sToken.GetToken( 1, ' ' );
            ByteString sSet = sToken.GetToken( 2, ' ' );
            if (( sCharset.ToUpperAscii() == "CHARSET_IBMPC" ) ||
                ( sCharset == "RTL_TEXTENCODING_IBM_850" ) ||
                (( sCharset == "CHARSET" ) && ( sSet.ToUpperAscii() == "IBMPC" )))
            {
                aCharSet = RTL_TEXTENCODING_IBM_850;
            }
            else if (( sCharset == "CHARSET_ANSI" ) ||
                ( sCharset == "RTL_TEXTENCODING_MS_1252" ) ||
                (( sCharset == "CHARSET" ) && ( sSet.ToUpperAscii() == "ANSI" )))
            {
                aCharSet = RTL_TEXTENCODING_MS_1252;
            }
        }
        break;
        case TEXTREFID : {
            bDontWriteOutput = TRUE;
             /*ByteString sK = sToken.GetToken( 0, '=' );
            ByteString sKey = sK.EraseAllChars( '\t' ).EraseAllChars( ' ' );
            ByteString sT = sToken.GetToken( 1, '=' ).GetToken( 0, ';' );
            USHORT nRefId = ( USHORT ) sT.EraseAllChars( '\t' ).EraseAllChars( ' ' ).ToInt32();
            if (( sKey.ToUpperAscii() == "TEXT" ) ||
                ( sKey == "MESSAGE" ) ||
                ( sKey == "CUSTOMUNITTEXT" ) ||
                ( sKey == "SLOTNAME" ) ||
                ( sKey == "UINAME" ))
                    pResData->nTextRefId = nRefId;
            else if ( sKey == "HELPTEXT" )
                pResData->nHelpTextRefId = nRefId;
            else if ( sKey == "QUICKHELPTEXT" )
                pResData->nQuickHelpTextRefId = nRefId;
            else if ( sKey == "TITLE" )
                pResData->nTitleRefId = nRefId;*/
        }
        }
    if ( bWriteToMerged ) {
        // the current token must be written to dest. without merging
        
        if( bDefine && sOrig.Len() > 2 ){
            for( USHORT n = 0 ; n < sOrig.Len() ; n++ ){
                if( sOrig.GetChar( n ) == '\n' && sOrig.GetChar( n-1 ) != '\\'){    
                    sOrig.Insert('\\' , n++ );
                }
            }
        }
        WriteToMerged( sOrig , false);
    }

    if ( bExecuteDown ) {
        Parse( LEVELDOWN, "" );
        //WorkOnTokenSet( LEVELDOWN, pTkn );
    }

    return 1;
}

/*****************************************************************************/
void Export::CutComment( ByteString &rText )
/*****************************************************************************/
{
    if ( rText.Search( "//" ) != STRING_NOTFOUND ) {
        ByteString sWork( rText );
        sWork.SearchAndReplaceAll( "\\\"", "XX" );
        USHORT i = 0;
        BOOL bInner = FALSE;

        while ( i < sWork.Len() - 1 ) {
            if ( sWork.GetChar( i ) == '\"' )
                bInner = !bInner;
            else if
                (( sWork.GetChar( i ) == '/' ) &&
                ( !bInner ) &&
                ( sWork.GetChar( i + 1 ) == '/' ))
            {
                rText.Erase( i );
                return;
            }
            i++;
        }
    }
}

void Export::UnmergeUTF8( ByteString& sOrig ){
    USHORT nPos1 = sOrig.Search('\"');
    USHORT nPos2 = sOrig.SearchBackward('\"');
    if( nPos1 > 0 && nPos2 > 0 && nPos1 < nPos2){
        ByteString sPart = sOrig.Copy(nPos1+1 , nPos2-1);
        ByteString sPartUTF8 = sPart;
        sPartUTF8.Convert( RTL_TEXTENCODING_MS_1252 , RTL_TEXTENCODING_UTF8 );
        sOrig.SearchAndReplace( sPart , sPartUTF8 );
    }
}

/*****************************************************************************/
BOOL Export::ListExists( ResData *pResData, USHORT nLst )
/*****************************************************************************/
{
    switch ( nLst ) {
        case LIST_STRING: return pResData->pStringList != NULL; 
        case LIST_FILTER: return pResData->pFilterList != NULL;
        case LIST_ITEM: return pResData->pItemList != NULL; 
        case LIST_PAIRED: return pResData->pPairedList != NULL; 
        case LIST_UIENTRIES: return pResData->pUIEntries != NULL; 
    }
    return FALSE;
}

/*****************************************************************************/
BOOL Export::WriteData( ResData *pResData, BOOL bCreateNew )
/*****************************************************************************/
{
    if ( bMergeMode ) {
        MergeRest( pResData );
        return TRUE;
    }

    if ( bUnmerge )
        return TRUE;

/*    ByteStringHashMap::iterator pos3 = pResData->sText.begin();
    ByteStringHashMap::iterator end3 = pResData->sText.end();
    for(;pos3!=end3;++pos3){
        
        printf("[%s]=%s\n", pos3->first.GetBuffer(), pos3->second.GetBuffer() );
    }*/
       // mandatory to export: en-US 
    
     if (( //pResData->sText[ ByteString("de") ].Len() &&
        ( pResData->sText[ SOURCE_LANGUAGE ].Len()))
        ||
        ( //pResData->sHelpText[ ByteString("de") ].Len() &&
        (  pResData->sHelpText[ SOURCE_LANGUAGE ].Len()))                                                                                                             
        ||
        ( //pResData->sQuickHelpText[ ByteString("de") ].Len() &&
        (  pResData->sQuickHelpText[ SOURCE_LANGUAGE ].Len()))
         ||
        ( //pResData->sTitle[ ByteString("de") ].Len() &&
        (  pResData->sTitle[ SOURCE_LANGUAGE ].Len())))
           
       {
        FillInFallbacks( pResData );

        ByteString sGID = pResData->sGId;
        ByteString sLID;
        if ( !sGID.Len())
            sGID = pResData->sId;
        else
            sLID = pResData->sId;

        ByteString sXText;
        ByteString sXHText;
        ByteString sXQHText;
        ByteString sXTitle;

        ByteString sTimeStamp( Export::GetTimeStamp());
        ByteString sCur;

        for( unsigned int n = 0; n < aLanguages.size(); n++ ){
            sCur = aLanguages[ n ];
                if ( !sCur.EqualsIgnoreCaseAscii("x-comment") ){
                    if ( pResData->sText[ sCur ].Len())
                        sXText = pResData->sText[ sCur ];
                    else {
                        sXText = pResData->sText[ SOURCE_LANGUAGE ];
                        /*if ( !sXText.Len())
                            sXText = pResData->sText[ ByteString("en") ];
                        if ( !sXText.Len())
                            sXText = pResData->sText[ ByteString("de") ];*/
                    }

                    if ( pResData->sHelpText[ sCur ].Len())
                        sXHText = pResData->sHelpText[ sCur ];
                    else {
                        sXHText = pResData->sHelpText[ SOURCE_LANGUAGE ];
                        /*if ( !sXHText.Len())
                            sXHText = pResData->sHelpText[ ByteString("en") ];
                        if ( !sXText.Len())
                            sXHText = pResData->sHelpText[ ByteString("de") ];*/
                    }

                    if ( pResData->sQuickHelpText[ sCur ].Len())
                        sXQHText = pResData->sQuickHelpText[ sCur ];
                    else {
                        sXQHText = pResData->sQuickHelpText[ SOURCE_LANGUAGE ];
                        /*if ( !sXQHText.Len())
                            sXQHText = pResData->sQuickHelpText[ ByteString("en") ];
                        if ( !sXQHText.Len())
                            sXQHText = pResData->sQuickHelpText[ ByteString("de") ];*/
                    }

                    if ( pResData->sTitle[ sCur ].Len())
                        sXTitle = pResData->sTitle[ sCur ];
                    else {
                        sXTitle = pResData->sTitle[ SOURCE_LANGUAGE ];
                        /*if ( !sXTitle.Len())
                            sXTitle = pResData->sTitle[ ByteString("en") ];
                        if ( !sXTitle.Len())
                            sXTitle = pResData->sTitle[ ByteString("de") ];*/
                    }

                    if ( !sXText.Len())
                        sXText = "-";

                    if ( !sXHText.Len()) {
                        /*if ( pResData->sHelpText[ ByteString("de") ].Len())
                            sXHText = pResData->sHelpText[ ByteString("de") ];*/
                        if ( pResData->sHelpText[ SOURCE_LANGUAGE ].Len())
                            sXHText = pResData->sHelpText[ SOURCE_LANGUAGE ];
                        /*else if ( pResData->sHelpText[ ByteString("en") ].Len())
                            sXHText = pResData->sHelpText[ ByteString("en") ];*/
                    }
                }
                else
                    sXText = pResData->sText[ sCur ];

                if ( bEnableExport ) {
                    ByteString sOutput( sProject ); sOutput += "\t";
                    if ( sRoot.Len())
                        sOutput += sActFileName;
                    sOutput += "\t0\t";
                    sOutput += pResData->sResTyp; sOutput += "\t";
                    sOutput += sGID; sOutput += "\t";
                    sOutput += sLID; sOutput += "\t";
                    sOutput += pResData->sHelpId; sOutput	+= "\t";
                    sOutput += pResData->sPForm; sOutput	+= "\t";
                    sOutput += ByteString::CreateFromInt64( pResData->nWidth ); sOutput += "\t";
                    sOutput += sCur; sOutput += "\t";
                    

                    sOutput += sXText; sOutput	+= "\t";
                    sOutput += sXHText; sOutput += "\t";
                    sOutput += sXQHText; sOutput+= "\t";
                    sOutput += sXTitle; sOutput += "\t";
                    sOutput += sTimeStamp;
                      
                 // if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sProject ) ) ) 
                    aOutput.WriteLine( sOutput );
                }

                if ( bCreateNew ) {
                    pResData->sText[ sCur ]			= "";
                    pResData->sHelpText[ sCur ]		= "";
                    pResData->sQuickHelpText[ sCur ]= "";
                    pResData->sTitle[ sCur ]		= "";
                }
            }
    }
    FillInFallbacks( pResData );
    if ( pResData->pStringList ) {
        ByteString sList( "stringlist" );
        WriteExportList( pResData, pResData->pStringList, sList, bCreateNew );
        if ( bCreateNew )
            pResData->pStringList = 0;
    }
    if ( pResData->pFilterList ) {
        ByteString sList( "filterlist" );
        WriteExportList( pResData, pResData->pFilterList, sList, bCreateNew );
        if ( bCreateNew )
            pResData->pFilterList = 0;
    }
    if ( pResData->pItemList ) {
        ByteString sList( "itemlist" );
        WriteExportList( pResData, pResData->pItemList, sList, bCreateNew );
        if ( bCreateNew )
            pResData->pItemList = 0;
    }
    if ( pResData->pPairedList ) {
        ByteString sList( "pairedlist" );
        WriteExportList( pResData, pResData->pPairedList, sList, bCreateNew );
        if ( bCreateNew )
            pResData->pItemList = 0;
    }
    if ( pResData->pUIEntries ) {
        ByteString sList( "uientries" );
        WriteExportList( pResData, pResData->pUIEntries, sList, bCreateNew );
        if ( bCreateNew )
            pResData->pUIEntries = 0;
    }
    return TRUE;
}
ByteString Export::GetPairedListID( const ByteString& sText ){
// < "STRING" ; IDENTIFIER ; > ;
    ByteString sIdent = sText.GetToken( 1, ';' );
    sIdent.ToUpperAscii();
    while( sIdent.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
    sIdent.EraseTrailingChars( ' ' );
    sIdent.EraseLeadingChars( ' ' );
    return sIdent;
}
ByteString Export::GetPairedListString( const ByteString& sText ){
// < "STRING" ; IDENTIFIER ; > ;
    ByteString sString = sText.GetToken( 0, ';' );
    while( sString.SearchAndReplace( "\t", " " ) != STRING_NOTFOUND ) {};
    sString.EraseTrailingChars( ' ' );
    ByteString s1 = sString.Copy( sString.Search( '\"' )+1 );
    sString = s1.Copy( 0 , s1.SearchBackward( '\"' ) );
    sString.EraseTrailingChars( ' ' );
    sString.EraseLeadingChars( ' ' );
    return sString;
}
ByteString Export::StripList( const ByteString& sText ){
    ByteString s1 = sText.Copy( sText.Search( '\"' ) + 1 );
    return s1.Copy( 0 , s1.SearchBackward( '\"' ) );
}

/*****************************************************************************/
BOOL Export::WriteExportList( ResData *pResData, ExportList *pExportList,
                        const ByteString &rTyp, BOOL bCreateNew )
/*****************************************************************************/
{
    ByteString sGID = pResData->sGId;
    if ( !sGID.Len())
        sGID = pResData->sId;
    else {
        sGID += ".";
        sGID += pResData->sId;
        sGID.EraseTrailingChars( '.' );
    }

    ByteString sTimeStamp( Export::GetTimeStamp());
    ByteString sCur;
    for ( ULONG i = 0; pExportList != NULL && i < pExportList->Count(); i++ ) {
        ExportListEntry *pEntry = pExportList->GetObject( i );
                // mandatory for export: german and eng. and/or enus
        //ByteString a("Export::WriteExportList::pEntry");
        //Export::DumpMap( a,  *pEntry );

        ByteString sLID( ByteString::CreateFromInt64( i + 1 ));
        for( unsigned int n = 0; n < aLanguages.size(); n++ ){
            sCur = aLanguages[ n ];
            if ( //1 )
                  //(*pEntry)[ ByteString("de") ].Len() &&
                     (*pEntry)[ SOURCE_LANGUAGE ].Len() )
                    //||
                     // 	(*pEntry)[ ByteString("en") ].Len()))
                {
                    if ( bEnableExport )
                    {
                        ByteString sText((*pEntry)[ SOURCE_LANGUAGE ] );
                        
                        // Strip PairList Line String
                        if( rTyp.EqualsIgnoreCaseAscii("pairedlist") ){
                            sLID = GetPairedListID( sText );
                            if ((*pEntry)[ sCur ].Len())
                                sText = (*pEntry)[ sCur ];
                            sText = GetPairedListString( sText ); 
                        }
                        else{
                            //if ((*pEntry)[ sCur ].Len()){
                            //	if( sCur.EqualsIgnoreCaseAscii("de") ){
                            //		sText = StripList( (*pEntry)[ sCur ] );
                            //	}
                            //	else
                                    sText = StripList( (*pEntry)[ sCur ] );
                                    if( sText == "\\\"" )
                                        sText = "\"";
                            //}
                        }

                        ByteString sOutput( sProject ); sOutput += "\t";
                        if ( sRoot.Len())
                            sOutput += sActFileName;
                        sOutput += "\t0\t";
                        sOutput += rTyp; sOutput += "\t";
                        sOutput += sGID; sOutput += "\t";
                        sOutput += sLID; sOutput += "\t\t";
                        sOutput += pResData->sPForm; sOutput += "\t0\t";
                        sOutput += sCur; sOutput += "\t";

                        sOutput += sText; sOutput += "\t\t\t\t";
                        sOutput += sTimeStamp;
                        
                        //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sProject ) ) )
                        aOutput.WriteLine( sOutput );

                    }
                }
        }
        if ( bCreateNew )
            delete [] pEntry;
    }
    if ( bCreateNew )
        delete pExportList;

    return TRUE;
}

/*****************************************************************************/
ByteString Export::FullId()
/*****************************************************************************/
{
    ByteString sFull;
    if ( nLevel > 1 ) {
        sFull = aResStack.GetObject( 0 )->sId;
        for ( USHORT i = 1; i < nLevel - 1; i++ ) {
            ByteString sToAdd = aResStack.GetObject( i )->sId;
            if ( sToAdd.Len()) {
                sFull += ".";
                sFull += sToAdd;
            }
        }
    }
    if ( sFull.Len() > 255 ) {
        ByteString sError( "GroupId > 255 chars" );
        printf("GroupID = %s\n",sFull.GetBuffer());
        yyerror( sError.GetBufferAccess());
        sError.ReleaseBufferAccess();
    }

    return sFull;
}

/*****************************************************************************/
void Export::InsertListEntry( const ByteString &rText, const ByteString &rLine )
/*****************************************************************************/
{
    ResData *pResData = aResStack.GetObject( nLevel-1 );

    ExportList *pList = NULL;
    if ( nList == LIST_STRING ) {
        pList = pResData->pStringList;
        if ( !pList ) {
            pResData->pStringList = new ExportList();
            pList = pResData->pStringList;
            nListIndex = 0;
        }
    }
    else if ( nList == LIST_FILTER ) {
        pList = pResData->pFilterList;
        if ( !pList ) {
            pResData->pFilterList = new ExportList();
            pList = pResData->pFilterList;
            nListIndex = 0;
        }
    }
    else if ( nList == LIST_ITEM ) {
        pList = pResData->pItemList;
        if ( !pList ) {
            pResData->pItemList = new ExportList();
            pList = pResData->pItemList;
            nListIndex = 0;
        }
    }
    else if ( nList == LIST_PAIRED ) {
        pList = pResData->pPairedList;
        if ( !pList ) {
            pResData->pPairedList = new ExportList();
            pList = pResData->pPairedList;
            nListIndex = 0;
        }
    }
    else if ( nList == LIST_UIENTRIES ) {
        pList = pResData->pUIEntries;
        if ( !pList ) {
            pResData->pUIEntries = new ExportList();
            pList = pResData->pUIEntries; 
            nListIndex = 0;
        }
    }
    else
        return;

    if ( nListIndex + 1 > pList->Count()) {
        ExportListEntry *pNew = new ExportListEntry();
        (*pNew)[ LIST_REFID ] = ByteString::CreateFromInt32( REFID_NONE );
        pList->Insert( pNew, LIST_APPEND );
    }
    ExportListEntry *pCurEntry = pList->GetObject( nListIndex );
    
    // For paired list use the line to set proper lid
    if( nList == LIST_PAIRED ){
        (*pCurEntry)[ nListLang ] = rLine;
    }else
        (*pCurEntry)[ nListLang ] = rText;
    
    // Remember en-US fallback string, so each list has the same amount of elements
    //if ( nListLang.EqualsIgnoreCaseAscii("en-US")  ) {
    if ( Export::isSourceLanguage( nListLang ) ) {
        if( nList == LIST_PAIRED ){
            const ByteString sPlist("pairedlist");
            ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sId , GetPairedListID( rLine ) , sFilename );
            pResData->addFallbackData( sKey , rText );
        }
        // new fallback
        else{
            const ByteString sPlist("list");
            ByteString a( pResData->sGId );
            a.Append( "." );
            a.Append( pResData->sId );
            sal_Int64 x = nListIndex+1;
            ByteString b( ByteString::CreateFromInt64( x ) );
            ByteString sKey = MergeDataFile::CreateKey( sPlist , a , b  , sFilename );
            pResData->addFallbackData( sKey , rText );
        }
        // new fallback
    }
    
    //if ( nListLang.EqualsIgnoreCaseAscii("en-US")  ) {
    if ( Export::isSourceLanguage( nListLang ) ) {
        if( nList == LIST_PAIRED ){
            (*pCurEntry)[ SOURCE_LANGUAGE ] = rLine;
        }
        else
            (*pCurEntry)[ SOURCE_LANGUAGE ] = rLine;
        
        pList->NewSourceLanguageListEntry();
    }

    //printf("Export::InsertListEntry ResData.id = %s ResData.ListData = %s\n",pResData->sId.GetBuffer() ,(*pCurEntry)[ nListLang ].GetBuffer());
    nListIndex++;
}

/*****************************************************************************/
void Export::CleanValue( ByteString &rValue )
/*****************************************************************************/
{
    while ( rValue.Len()) {
        if (( rValue.GetChar( 0 ) == ' ' ) || ( rValue.GetChar( 0 ) == '\t' ))
            rValue = rValue.Copy( 1 );
        else
            break;
    }

    if ( rValue.Len()) {
        for ( USHORT i = rValue.Len() - 1; i > 0; i-- ) {
            if (( rValue.GetChar( i ) == ' ' ) || ( rValue.GetChar( i ) == '\t' ) ||
                ( rValue.GetChar( i ) == '\n' ) || ( rValue.GetChar( i ) == ';' ) ||
                ( rValue.GetChar( i ) == '{' ) || ( rValue.GetChar( i ) == '\\' ) ||
                ( rValue.GetChar( i ) == '\r' ))
                rValue.Erase( i );
            else
                break;
        }
    }
}


/*****************************************************************************/
ByteString Export::GetText( const ByteString &rSource, int nToken )
/*****************************************************************************/
#define TXT_STATE_NON  	0x000
#define TXT_STATE_TEXT	0x001
#define TXT_STATE_MACRO	0x002
{
    ByteString sReturn;
    switch ( nToken ) {
        case TEXTLINE:
        case LONGTEXTLINE: {
            ByteString sTmp( rSource.Copy( rSource.Search( "=" )));
            CleanValue( sTmp );
            sTmp.EraseAllChars( '\n' );
            sTmp.EraseAllChars( '\r' );

            while ( sTmp.SearchAndReplace( "\\\\\"", "-=<[BSlashBSlashHKom]>=-\"" )
                != STRING_NOTFOUND ) {};
            while ( sTmp.SearchAndReplace( "\\\"", "-=<[Hochkomma]>=-" )
                != STRING_NOTFOUND ) {};
            while ( sTmp.SearchAndReplace( "\\", "-=<[0x7F]>=-" )
                != STRING_NOTFOUND ) {};
            while ( sTmp.SearchAndReplace( "\\0x7F", "-=<[0x7F]>=-" )
                != STRING_NOTFOUND ) {};

            USHORT nStart = 0;
            USHORT nState = TXT_STATE_MACRO;

            nState = TXT_STATE_TEXT;
            nStart = 1;


            for ( USHORT i = nStart; i < sTmp.GetTokenCount( '\"' ); i++ ) {
                ByteString sToken = sTmp.GetToken( i, '\"' );
                if ( sToken.Len()) {
                    if ( nState == TXT_STATE_TEXT ) {
                        sReturn += sToken;
                        nState = TXT_STATE_MACRO;
                    }
                    else {
                        while( sToken.SearchAndReplace( "\t", " " ) !=
                            STRING_NOTFOUND ) {};
                        while( sToken.SearchAndReplace( "  ", " " ) !=
                            STRING_NOTFOUND ) {};
                        sToken.EraseLeadingChars( ' ' );
                        sToken.EraseTrailingChars( ' ' );
                        if ( sToken.Len()) {
                            sReturn += "\\\" ";
                            sReturn += sToken;
                            sReturn += " \\\"";
                        }
                        nState = TXT_STATE_TEXT;
                    }
                }
            }

            while ( sReturn.SearchAndReplace( "-=<[0x7F]>=-", "" )
                != STRING_NOTFOUND ) {};
            while ( sReturn.SearchAndReplace( "-=<[Hochkomma]>=-", "\"" )
                != STRING_NOTFOUND ) {};
            while ( sReturn.SearchAndReplace( "-=<[BSlashBSlashHKom]>=-", "\\\\" )
                != STRING_NOTFOUND ) {};


            while ( sReturn.SearchAndReplace( "\\\\", "-=<[BSlashBSlash]>=-" )
                != STRING_NOTFOUND ) {};
            while ( sReturn.SearchAndReplace( "-=<[BSlashBSlash]>=-", "\\" )
                != STRING_NOTFOUND ) {};

        }
        break;
    }
    return sReturn;
}

/*****************************************************************************/
void Export::WriteToMerged( const ByteString &rText , bool bSDFContent )
/*****************************************************************************/
{
    static ByteString SLASH  ('\\');
    static ByteString RETURN ('\n');
    //printf("%s\n",rText.GetBuffer() );

    if ( !bDontWriteOutput || !bUnmerge ) {
        ByteString sText( rText );
        while ( sText.SearchAndReplace( " \n", "\n" ) != STRING_NOTFOUND ) {};
        if( pParseQueue->bNextIsM && bSDFContent && sText.Len() > 2 ){
            for( USHORT n = 0 ; n < sText.Len() ; n++ ){
                if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){    
                    sText.Insert('\\' , n++ );
                    
                }
            }
        }
        else if( pParseQueue->bLastWasM && sText.Len() > 2 ){ 
            for( USHORT n = 0 ; n < sText.Len() ; n++ ){
                if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){    
                    sText.Insert('\\' , n++ );
                }
                if( sText.GetChar( n ) == '\n' )pParseQueue->bMflag=true;
            }
        }
        else if( pParseQueue->bCurrentIsM && bSDFContent && sText.Len() > 2 ){ 
            for( USHORT n = 0 ; n < sText.Len() ; n++ ){
                if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){    
                    sText.Insert('\\' , n++ );
                    pParseQueue->bMflag=true;
                }
            }
        }
        else if( pParseQueue->bMflag ){ 
            for( USHORT n = 1 ; n < sText.Len() ; n++ ){
                if( sText.GetChar( n ) == '\n' && sText.GetChar( n-1 ) != '\\'){    
                    sText.Insert('\\' , n++ );
                }
            }
        }
        for ( USHORT i = 0; i < sText.Len(); i++ ) {
            if ( sText.GetChar( i ) != '\n' ){
                aOutput.Write( ByteString( sText.GetChar( i )).GetBuffer(), 1 );
                
            }
            else{
                aOutput.WriteLine( ByteString());
            }
            
        }
    }
}

/*****************************************************************************/
void Export::ConvertMergeContent( ByteString &rText )
/*****************************************************************************/
{
    BOOL bNoOpen = ( rText.Search( "\\\"" ) != 0 );
    ByteString sClose( rText.Copy( rText.Len() - 2 ));
    BOOL bNoClose = ( sClose != "\\\"" );
    ByteString sNew;
    for ( USHORT i = 0; i < rText.Len(); i++ ) {
        ByteString sChar( rText.GetChar( i ));
        if ( sChar == "\\" ) {
            if (( i + 1 ) < rText.Len()) {
                ByteString sNext( rText.GetChar( i + 1 ));
                if ( sNext == "\"" ) {
                    sChar = "\"";
                    i++;
                }
                else if ( sNext == "n" ) {
                    sChar = "\\n";
                    i++;
                }
                else if ( sNext == "t" ) {
                    sChar = "\\t";
                    i++;
                }
                else if ( sNext == "\'" ) {
                    sChar = "\\\'";
                    i++;
                }
                else
                    sChar = "\\\\";
            }
            else {
                sChar = "\\\\";
            }
        }
        else if ( sChar == "\"" ) {
            sChar = "\\\"";
        }
        else if ( sChar == "" ) {
            sChar = "\\0x7F";
        }
        sNew += sChar;
    }

    rText = sNew;

    if ( bNoOpen ) {
        ByteString sTmp( rText );
        rText = "\"";
        rText += sTmp;
    }
    if ( bNoClose )
        rText += "\"";
}

/*****************************************************************************/
BOOL Export::PrepareTextToMerge( ByteString &rText, USHORT nTyp,
                                ByteString &nLangIndex, ResData *pResData )
/*****************************************************************************/
{
    // position to merge in:
    USHORT nStart = 0;
    USHORT nEnd = 0;
    ByteString sOldId = pResData->sId;
    ByteString sOldGId = pResData->sGId;
    ByteString sOldTyp = pResData->sResTyp;

    ByteString sOrigText( rText );

    switch ( nTyp ) {
        case LIST_STRING :
        case LIST_UIENTRIES :
        case LIST_FILTER :
        case LIST_PAIRED:
        case LIST_ITEM :
        {
            if ( bUnmerge )
                return TRUE;

            ExportList *pList = NULL;
            switch ( nTyp ) {
                case LIST_STRING : {
                    pResData->sResTyp = "stringlist";
                    pList = pResData->pStringList;
                }
                break;
                case LIST_UIENTRIES : {
                    pResData->sResTyp = "uientries";
                    pList = pResData->pUIEntries;
                }
                break;
                case LIST_FILTER : {
                    pResData->sResTyp = "filterlist";
                    pList = pResData->pFilterList;
                }
                break;
                case LIST_ITEM : {
                    pResData->sResTyp = "itemlist";
                    pList = pResData->pItemList;
                }
                break;
                case LIST_PAIRED : {
                    pResData->sResTyp = "pairedlist";
                    pList = pResData->pPairedList;
                }
                break;

            }
            if ( pList ) {
                ExportListEntry *pCurEntry = pList->GetObject( nListIndex - 1 );
                if ( pCurEntry ) {
                    //printf("%s\n",Export::DumpMap( "pCurEntry", *pCurEntry ).GetBuffer() );
                    //ByteString a("pCurEntry");
                    //Export::DumpMap( a , *pCurEntry );
                    rText = (*pCurEntry)[ SOURCE_LANGUAGE ];
                    if( nTyp == LIST_PAIRED ){ 
                        pResData->addMergedLanguage( nLangIndex );						
                    }
                }
            }

            nStart = rText.Search( "\"" );
            if ( nStart == STRING_NOTFOUND ) {
                rText = sOrigText;
                return FALSE;
            }

            BOOL bFound = FALSE;
            for ( nEnd = nStart + 1; nEnd < rText.Len() && !bFound; nEnd++ ) {
                if ( rText.GetChar( nEnd ) == '\"' )
                    bFound = TRUE;
            }
            if ( !bFound ) {
                rText = sOrigText;
                return FALSE;
            }

            nEnd --;
            sLastListLine = rText;
            if (( sLastListLine.Search( ">" ) != STRING_NOTFOUND ) &&
                ( sLastListLine.Search( "<" ) == STRING_NOTFOUND ))
            {
                ByteString sTmp = sLastListLine;
                sLastListLine = "<";
                sLastListLine += sTmp;
            }
            if ( pResData->sResTyp.EqualsIgnoreCaseAscii( "pairedlist" ) ){
               pResData->sId = GetPairedListID( sLastListLine ); 
            }
            else pResData->sId = ByteString::CreateFromInt32( nListIndex );
            
            if ( pResData->sGId.Len())
                pResData->sGId += ".";
            pResData->sGId += sOldId;
            nTyp = STRING_TYP_TEXT;
        }
        break;
        case STRING_TYP_TEXT :
        case STRING_TYP_HELPTEXT :
        case STRING_TYP_QUICKHELPTEXT :
        case STRING_TYP_TITLE :
        {
            /*if ( bUnmerge ) {
                if (( nLangIndex != ByteString("de") ) &&
                    ( nLangIndex != ByteString("en-US") ))
                {
                    bDontWriteOutput = TRUE;
                }
                return TRUE;
            }*/

            nStart = rText.Search( "=" );
            if ( nStart == STRING_NOTFOUND ) {
                rText = sOrigText;
                return FALSE;
            }

            nStart++;
            BOOL bFound = FALSE;
            while(( nStart < rText.Len()) && !bFound ) {
                if (( rText.GetChar( nStart ) != ' ' ) && ( rText.GetChar( nStart ) != '\t' ))
                    bFound = TRUE;
                else
                    nStart ++;
            }

            // no start position found
            if ( !bFound ) {
                rText = sOrigText;
                return FALSE;
            }

            // position to end mergeing in
            nEnd = rText.Len() - 1;
            bFound = FALSE;

            while (( nEnd > nStart ) && !bFound ) {
                if (( rText.GetChar( nEnd ) != ' ' ) && ( rText.GetChar( nEnd ) != '\t' ) &&
                    ( rText.GetChar( nEnd ) != '\n' ) && ( rText.GetChar( nEnd ) != ';' ) &&
                    ( rText.GetChar( nEnd ) != '{' ) && ( rText.GetChar( nEnd ) != '\\' ))
                {
                    bFound = TRUE;
                }
                else
                    nEnd --;
            }
        }
        break;
    }

    // search for merge data
    if ( !pMergeDataFile ){
        pMergeDataFile = new MergeDataFile( sMergeSrc, sFile , bErrorLog, aCharSet);//, bUTF8 );
        
        // Init Languages
        ByteString sTmp = Export::sLanguages;
        if( sTmp.ToUpperAscii().Equals("ALL") )
            SetLanguages( pMergeDataFile->GetLanguages() );
        else if( !isInitialized )InitLanguages();

    }
//	printf("*************DUMPING****************\n");
//	printf("%s\n",pMergeDataFile->Dump().GetBuffer());
//	printf("*************DUMPING****************\n");
    
//	printf("Dumping ResData\n");
//	pResData->Dump();
    PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
    //printf("Dumping pEntrys\n");
    //if( pEntrys ) pEntrys->Dump();
    pResData->sId = sOldId;
    pResData->sGId = sOldGId;
    pResData->sResTyp = sOldTyp;

    if ( !pEntrys ) {
        rText = sOrigText;
        return FALSE; // no data found
    }

    ByteString sContent;
    pEntrys->GetTransex3Text( sContent, nTyp, nLangIndex );
    //if ( !sContent.Len() && ( ! nLangIndex.EqualsIgnoreCaseAscii("en-US") )) {
    if ( !sContent.Len() && ( ! Export::isSourceLanguage( nLangIndex ) )) {
        rText = sOrigText;
        return FALSE; // no data found   
    }

    //if ( nLangIndex.EqualsIgnoreCaseAscii("en-US") ) {
    if ( Export::isSourceLanguage( nLangIndex ) ) {
        return FALSE;
    }

    ByteString sPostFix( rText.Copy( ++nEnd ));
    rText.Erase( nStart );

    //ConvertMergeContent( sContent, nTyp );
    ConvertMergeContent( sContent );



    //printf("Merged %s\n",nLangIndex.GetBuffer());
    // merge new res. in text line
    rText += sContent;
    rText += sPostFix;

    return TRUE;
}

/*****************************************************************************/
void Export::MergeRest( ResData *pResData, USHORT nMode )
/*****************************************************************************/
{
    //if ( bUnmerge ) { return;}

    //pResData->Dump();

    if ( !pMergeDataFile ){
        pMergeDataFile = new MergeDataFile( sMergeSrc, sFile ,bErrorLog, aCharSet);//, bUTF8 );
  
        // Init Languages
        ByteString sTmp = Export::sLanguages;
        if( sTmp.ToUpperAscii().Equals("ALL") )
            SetLanguages( pMergeDataFile->GetLanguages() );
        else if( !isInitialized )InitLanguages();

    }
    switch ( nMode ) {
        case MERGE_MODE_NORMAL : {
            PFormEntrys *pEntry = pMergeDataFile->GetPFormEntrys( pResData );
             
            bool bWriteNoSlash = false;
            if ( pEntry && pResData->bText ) {
                
                BOOL bAddSemikolon = FALSE;
                BOOL bFirst = TRUE;
                ByteString sCur;
                ByteString sTmp = Export::sLanguages;

                for( unsigned int n = 0; n < aLanguages.size(); n++ ){
                    sCur = aLanguages[ n ];

                    ByteString sText;
                    BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_TEXT, sCur , TRUE );
                    if ( bText && sText.Len() && sText != "-" ) {
                        ByteString sOutput;
                        if ( bNextMustBeDefineEOL)  {
                            if ( bFirst )
                                sOutput += "\t\\\n";
                            else
                                sOutput += ";\t\\\n";
                        }
                        bFirst=FALSE;
                        sOutput += "\t";
                        sOutput += pResData->sTextTyp;
                        //if ( !sCur.EqualsIgnoreCaseAscii("en-US")) {
                        if ( ! Export::isSourceLanguage( sCur ) ) {
                            sOutput += "[ ";
                            sOutput += sCur;
                            sOutput += " ] ";
                        }
                        sOutput += "= ";
                        ConvertMergeContent( sText );
                        sOutput += sText;

                        if ( bDefine && bWriteNoSlash )
                            sOutput += ";\n";

                        if ( bDefine )
                            sOutput += ";\\\n";
                        else if ( !bNextMustBeDefineEOL )
                            sOutput += ";\n";
                        else
                            bAddSemikolon = TRUE;
                        for ( USHORT j = 1; j < nLevel; j++ )
                            sOutput += "\t";
                        WriteToMerged( sOutput , true );
                    }
                }
      

                if ( bAddSemikolon ) {
                    ByteString sOutput( ";" );
                    WriteToMerged( sOutput , false );
                }
            }

            if ( pEntry && pResData->bQuickHelpText ) {
                BOOL bAddSemikolon = FALSE;
                BOOL bFirst = TRUE;
                ByteString sCur;

                for( unsigned int n = 0; n < aLanguages.size(); n++ ){
                    sCur = aLanguages[ n ];

                    ByteString sText;
                    BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_QUICKHELPTEXT, sCur, TRUE );
                    if ( bText && sText.Len() && sText != "-" ) {
                        ByteString sOutput;
                        if ( bNextMustBeDefineEOL)  {
                            if ( bFirst )
                                sOutput += "\t\\\n";
                            else
                                sOutput += ";\t\\\n";
                        }
                        bFirst=FALSE;
                        sOutput += "\t";
                        sOutput += "QuickHelpText";
                        //if ( !sCur.EqualsIgnoreCaseAscii("en-US") ) {
                        if ( ! Export::isSourceLanguage( sCur ) ) {
                            sOutput += "[ ";
                            sOutput += sCur;
                            sOutput += " ] ";
                        }
                        sOutput += "= ";
                        ConvertMergeContent( sText );
                        sOutput += sText;
                        if ( bDefine )
                            sOutput += ";\\\n";
                        else if ( !bNextMustBeDefineEOL )
                            sOutput += ";\n";
                        else
                            bAddSemikolon = TRUE;
                        for ( USHORT j = 1; j < nLevel; j++ )
                            sOutput += "\t";
                        WriteToMerged( sOutput ,true );
                    }
                }
                if ( bAddSemikolon ) {
                    ByteString sOutput( ";" );
                    WriteToMerged( sOutput , false );
                }
            }

            if ( pEntry && pResData->bTitle ) {
                BOOL bAddSemikolon = FALSE;
                BOOL bFirst = TRUE;
                ByteString sCur;

                for( unsigned int n = 0; n < aLanguages.size(); n++ ){
                    sCur = aLanguages[ n ];

                ByteString sText;
                    BOOL bText = pEntry->GetTransex3Text( sText, STRING_TYP_TITLE, sCur, TRUE );
                    if ( bText && sText.Len() && sText != "-" ) {
                        ByteString sOutput;
                        if ( bNextMustBeDefineEOL)  {
                            if ( bFirst )
                                sOutput += "\t\\\n";
                            else
                                sOutput += ";\t\\\n";
                        }
                        bFirst=FALSE;
                        sOutput += "\t";
                        sOutput += "Title";
                        //if ( !sCur.EqualsIgnoreCaseAscii("en-US") ) {
                        if ( ! Export::isSourceLanguage( sCur ) ) {
                            sOutput += "[ ";
                            sOutput += sCur;
                            sOutput += " ] ";
                        }
                        sOutput += "= ";
                        ConvertMergeContent( sText );
                        sOutput += sText;
                        if ( bDefine )
                            sOutput += ";\\\n";
                        else if ( !bNextMustBeDefineEOL )
                            sOutput += ";\n";
                        else
                            bAddSemikolon = TRUE;
                        for ( USHORT j = 1; j < nLevel; j++ )
                            sOutput += "\t";
                        WriteToMerged( sOutput ,true );
                    }
                }
                if ( bAddSemikolon ) {
                    ByteString sOutput( ";" );
                    WriteToMerged( sOutput ,false);
                }
            }
            // Merge Lists

            if ( pResData->bList ) {
                //printf("Dumping ResData\n");
                //pResData->Dump();
                
                bool bPairedList = false;
                ByteString sOldId = pResData->sId;
                ByteString sOldGId = pResData->sGId;
                ByteString sOldTyp = pResData->sResTyp;
                if ( pResData->sGId.Len())
                    pResData->sGId += ".";
                pResData->sGId += sOldId;
                ByteString sSpace;
                for ( USHORT i = 1; i < nLevel-1; i++ )
                    sSpace += "\t";
                for ( USHORT nT = LIST_STRING; nT <= LIST_UIENTRIES; nT++ ) {
                    ExportList *pList = NULL;
                    switch ( nT ) {
                        case LIST_STRING : pResData->sResTyp = "stringlist"; pList = pResData->pStringList; bPairedList = false; break;
                        case LIST_FILTER : pResData->sResTyp = "filterlist"; pList = pResData->pFilterList; bPairedList = false; break;
                        case LIST_UIENTRIES : pResData->sResTyp = "uientries"; pList = pResData->pUIEntries;bPairedList = false; break;
                        case LIST_ITEM : pResData->sResTyp = "itemlist"; pList = pResData->pItemList;       bPairedList = false; break;
                        case LIST_PAIRED : pResData->sResTyp = "pairedlist"; pList = pResData->pPairedList; bPairedList = true;  break;
                    }
                    ByteString sCur;
                    for( unsigned int n = 0; n < aLanguages.size(); n++ ){
                        sCur = aLanguages[ n ];				
                        USHORT nIdx = 1;
                        
                        // Set matching pairedlist identifier 
                        if( bPairedList && pResData->pPairedList && ( nIdx == 1 ) ){
                            ExportListEntry* pListE = ( ExportListEntry* ) pResData->pPairedList->GetObject( nIdx-1 );
                            pResData->sId = GetPairedListID ( (*pListE)[ SOURCE_LANGUAGE ] );
                        } 
                        else
                            pResData->sId = ByteString("1");
                        
                        PFormEntrys *pEntrys;
                        ULONG nLIndex = 0;
                        ULONG nMaxIndex = 0;
                        if ( pList )
                            nMaxIndex = pList->GetSourceLanguageListEntryCount();
                        pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
                        while( pEntrys  && ( nLIndex < nMaxIndex )) {
                            //printf("Lang %s, List Index %d\n",sCur.GetBuffer(),(int)nLIndex);
                            ByteString sText;
                            BOOL bText;
                            bText = pEntrys->GetTransex3Text( sText, STRING_TYP_TEXT, sCur, TRUE );
                            if( !bText )
                                bText = pEntrys->GetTransex3Text( sText , STRING_TYP_TEXT, SOURCE_LANGUAGE , FALSE );

                            // Use fallback, if data is missing in sdf file
                            //if( !bText && pResData->sResTyp.Equals( "pairedlist" ) ){ 
                            if( !bText && bPairedList ){ 
                                if( pResData->isMerged( sCur ) ) break; 
                                const ByteString sPlist("pairedlist");
                                ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sGId , pResData->sId , sFilename );
                                bText = pResData->getFallbackData( sKey , sText );
                            }else if ( !bText ){// new fallback
                                if( pResData->isMerged( sCur ) ) break; 
                                const ByteString sPlist("list");
                                ByteString sKey = MergeDataFile::CreateKey( sPlist , pResData->sGId , pResData->sId , sFilename );
                                bText = pResData->getFallbackData( sKey , sText );
                            } // new fallback

                            if ( bText && sText.Len()) {
                                //if( pEntrys ) pEntrys->Dump();							
                                if ( nIdx == 1 ) {
                                    ByteString sHead;
                                    if ( bNextMustBeDefineEOL ) 
                                        sHead = "\\\n\t";
                                    sHead += sSpace;
                                    switch ( nT ) {
                                        case LIST_STRING : sHead += "StringList "; break;
                                        case LIST_FILTER : sHead += "FilterList "; break;
                                        case LIST_ITEM : sHead += "ItemList "; break;
                                        case LIST_PAIRED : sHead += "PairedList "; break;
                                        case LIST_UIENTRIES : sHead += "UIEntries "; break;
                                    }
                                      sHead += "[ ";
                                    sHead += sCur;
                                    sHead += " ] ";
                                    //}
                                    if ( bDefine || bNextMustBeDefineEOL ) {
                                        sHead += "= \\\n";
                                        sHead += sSpace;
                                        sHead += "\t{\\\n\t";
                                    }
                                    else {
                                        sHead += "= \n";
                                        sHead += sSpace;
                                        sHead += "\t{\n\t";
                                    }
                                    WriteToMerged( sHead , true);
                                }
                                ByteString sLine;
                                if ( pList && pList->GetObject( nLIndex )) 
                                    sLine = ( *pList->GetObject( nLIndex ))[ SOURCE_LANGUAGE ];
                                if ( !sLine.Len())
                                    sLine = sLastListLine;

                                if ( sLastListLine.Search( "<" ) != STRING_NOTFOUND ) {
                                    if (( nT != LIST_UIENTRIES ) &&
                                        (( sLine.Search( "{" ) == STRING_NOTFOUND ) ||
                                        ( sLine.Search( "{" ) >= sLine.Search( "\"" ))) &&
                                        (( sLine.Search( "<" ) == STRING_NOTFOUND ) ||
                                        ( sLine.Search( "<" ) >= sLine.Search( "\"" ))))
                                    {
                                        sLine.SearchAndReplace( "\"", "< \"" );
                                    }
                                }

                                USHORT nStart, nEnd;
                                nStart = sLine.Search( "\"" );
                            
                                ByteString sPostFix;
                                if( !bPairedList ){
                                    nEnd = sLine.SearchBackward( '\"' );
                                    sPostFix = ByteString( sLine.Copy( ++nEnd ));
                                    sLine.Erase( nStart );
                                }


                                ConvertMergeContent( sText );

                                // merge new res. in text line
                                if( bPairedList ){
                                    sLine = MergePairedList( sLine , sText );
                                }
                                else{
                                    sLine += sText;
                                    sLine += sPostFix;
                                }

                                ByteString sText1( "\t" );
                                sText1 += sLine;
                                if ( bDefine || bNextMustBeDefineEOL )
                                    sText1 += " ;\\\n";
                                else
                                    sText1 += " ;\n";
                                sText1 += sSpace;
                                sText1 += "\t";
                                //printf("Writing '%s'\n",sText1.GetBuffer());
                                WriteToMerged( sText1 ,true );
                               
                                // Set matching pairedlist identifier 
                                if ( bPairedList ){
                                    nIdx++;
                                    ExportListEntry* pListE = ( ExportListEntry* ) pResData->pPairedList->GetObject( ( nIdx ) -1 );
                                    if( pListE ){
                                        pResData->sId = GetPairedListID ( (*pListE)[ SOURCE_LANGUAGE ] );
                                    }
                                }
                                else
                                    pResData->sId = ByteString::CreateFromInt32( ++nIdx );
                            }
                            else
                                break;
                            nLIndex ++;
                            PFormEntrys *oldEntry = pEntrys;
                            pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); // <--- game over
                            if( !pEntrys )
                                pEntrys = oldEntry;
                        }
                        if ( nIdx > 1 ) {
                            ByteString sFooter( sSpace.Copy( 1 ));
                            if ( bNextMustBeDefineEOL )
                                sFooter += "};";
                            else if ( !bDefine )
                                sFooter += "};\n\t";
                            else
                                sFooter += "\n\n";
                            WriteToMerged( sFooter ,true );
                        }
                    }
                }

                pResData->sId = sOldId;
                pResData->sGId = sOldGId;
                pResData->sResTyp = sOldTyp;
            }
        }
        break;
        case MERGE_MODE_LIST : {
            ExportList *pList = NULL;
            switch ( nList ) {
                // PairedList
                case LIST_STRING : pList = pResData->pStringList; break;
                case LIST_FILTER : pList = pResData->pFilterList; break;
                case LIST_UIENTRIES : pList = pResData->pUIEntries; break;
                case LIST_ITEM : pList = pResData->pItemList; break;
                case LIST_PAIRED : pList = pResData->pPairedList; break;

            }

            nListIndex++;
            ULONG nMaxIndex = 0;
            if ( pList )
                nMaxIndex = pList->GetSourceLanguageListEntryCount();
            ByteString sLine;
            if ( pList && pList->GetObject( nListIndex )) 
                sLine = ( *pList->GetObject( nListIndex ))[ SOURCE_LANGUAGE ];
            if ( !sLine.Len())
                sLine = sLastListLine;

            if ( sLastListLine.Search( "<" ) != STRING_NOTFOUND ) {
                if (( nList != LIST_UIENTRIES ) &&
                    (( sLine.Search( "{" ) == STRING_NOTFOUND ) ||
                    ( sLine.Search( "{" ) >= sLine.Search( "\"" ))) &&
                    (( sLine.Search( "<" ) == STRING_NOTFOUND ) ||
                    ( sLine.Search( "<" ) >= sLine.Search( "\"" ))))
                {
                    sLine.SearchAndReplace( "\"", "< \"" );
                }
            }

            while( PrepareTextToMerge( sLine, nList, nListLang, pResData ) && ( nListIndex <= nMaxIndex )) { 
                ByteString sText( "\t" );
                sText += sLine;
                sText += " ;";
                sText += "\n";
                for ( USHORT i = 0; i < nLevel; i++ )
                    sText += "\t";
                WriteToMerged( sText ,false );
                nListIndex++;
                if ( pList && pList->GetObject( nListIndex )) 
                    sLine = ( *pList->GetObject( nListIndex ))[ SOURCE_LANGUAGE ];
                if ( !sLine.Len())
                    sLine = sLastListLine;
                sLine += " ;";
            }
        }
        break;
    }
    pParseQueue->bMflag = false;
}

ByteString Export::MergePairedList( ByteString& sLine , ByteString& sText ){
// < "xy" ; IDENTIFIER ; >
    ByteString sPre  = sLine.Copy( 0 , sLine.Search('\"') );
    ByteString sPost = sLine.Copy( sLine.SearchBackward('\"') + 1 , sLine.Len() );
    sPre.Append( sText );
    sPre.Append( sPost );
    return sPre;
}

/*****************************************************************************/
void Export::SetChildWithText()
/*****************************************************************************/
{
    if ( aResStack.Count() > 1 ) {
        for ( ULONG i = 0; i < aResStack.Count() - 1; i++ ) {
            aResStack.GetObject( i )->bChildWithText = TRUE;
        }
    }
}

void ParserQueue::Push( const QueueEntry& aEntry ){
//    printf("nTyp = %d ",aEntry.nTyp);
    USHORT nLen = aEntry.sLine.Len();

    if( !bStart ){
        aQueueCur->push( aEntry );
        if( nLen > 1 && aEntry.sLine.GetChar( nLen-1 ) == '\n' )
            bStart = true;
        else if ( aEntry.nTyp != IGNOREDTOKENS ){
            if( nLen > 1 && ( aEntry.sLine.GetChar( nLen-1 ) == '\\') ){
                // Next is Macro
                bCurrentIsM = true;
             }else{
                // Next is no Macro
                bCurrentIsM = false;
             }
        }
    }
    else{
        aQueueNext->push( aEntry );
        if( nLen > 1 && aEntry.sLine.GetChar( nLen-1 ) != '\n' ){
            if( nLen > 1 && ( aEntry.sLine.GetChar( nLen-1  ) == '\\') ){
                // Next is Macro
                bNextIsM = true;
            }
            else{
                // Next is no Macro
                bNextIsM = false;
            }
        }else if( nLen > 2 && aEntry.sLine.GetChar( nLen-1 ) == '\n' ){
            if( aEntry.nTyp != IGNOREDTOKENS ){
                if( nLen > 2 && ( aEntry.sLine.GetChar( nLen-2  ) == '\\') ){
                    // Next is Macro
                    bNextIsM = true;
                }
                else{
                    // Next is no Macro
                    bNextIsM = false;
                }
            }
            // Pop current
            Pop( *aQueueCur );
            bLastWasM = bCurrentIsM;
            // next -> current
            bCurrentIsM = bNextIsM;
            aQref = aQueueCur;
            aQueueCur = aQueueNext;
            aQueueNext = aQref;

        }

        else{
            // Pop current
            Pop( *aQueueCur );
            bLastWasM = bCurrentIsM;
            // next -> current
            bCurrentIsM = bNextIsM;
            aQref = aQueueCur;
            aQueueCur = aQueueNext;
            aQueueNext = aQref;
        }       
    }
}

void ParserQueue::Close(){
    // Pop current
    Pop( *aQueueCur );
    // next -> current
    bLastWasM = bCurrentIsM;
    bCurrentIsM = bNextIsM;
    aQref = aQueueCur;
    aQueueCur = aQueueNext;
    aQueueNext = aQref;
    bNextIsM = false;
    Pop( *aQueueNext );
};
void ParserQueue::Pop( std::queue<QueueEntry>& aQueue ){
    while( !aQueue.empty() ){
        QueueEntry aEntry = aQueue.front(); 
        aQueue.pop();
        aExport.Execute( aEntry.nTyp , (char*) aEntry.sLine.GetBuffer() );
    }
}
ParserQueue::ParserQueue( Export& aExportObj )
        :  
          bCurrentIsM( false ), 
          bNextIsM( false ) , 
          bLastWasM( false ),
          bMflag( false ) ,
          aExport( aExportObj ) ,
          bStart( false ) , 
          bStartNext( false )
{
          aQueueNext = new std::queue<QueueEntry>;
          aQueueCur  = new std::queue<QueueEntry>;
}


ParserQueue::~ParserQueue(){
    if( aQueueNext )    delete aQueueNext;
    if( aQueueCur )     delete aQueueCur;
}

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