| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_l10ntools.hxx" |
| #include <stdio.h> |
| #include <tools/string.hxx> |
| #include <tools/fsys.hxx> |
| |
| // local includes |
| #include "export.hxx" |
| #include "xrmmerge.hxx" |
| #include "utf8conv.hxx" |
| #include "tokens.h" |
| #include <iostream> |
| #include <vector> |
| |
| using namespace std; |
| |
| extern "C" { int yyerror( char * ); } |
| extern "C" { int YYWarning( char * ); } |
| |
| // 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_UTF8 0x000B |
| #define STATE_LANGUAGES 0x000C |
| #define STATE_ISOCODE99 0x000D |
| |
| // set of global variables |
| sal_Bool bEnableExport; |
| sal_Bool bMergeMode; |
| sal_Bool bErrorLog; |
| sal_Bool bUTF8; |
| ByteString sPrj; |
| ByteString sPrjRoot; |
| ByteString sInputFileName; |
| ByteString sActFileName; |
| ByteString sOutputFile; |
| ByteString sMergeSrc; |
| String sUsedTempFile; |
| XRMResParser *pParser = NULL; |
| |
| extern "C" { |
| // the whole interface to lexer is in this extern "C" section |
| |
| /*****************************************************************************/ |
| extern char *GetOutputFile( int argc, char* argv[]) |
| /*****************************************************************************/ |
| { |
| bEnableExport = sal_False; |
| bMergeMode = sal_False; |
| bErrorLog = sal_True; |
| bUTF8 = sal_True; |
| sPrj = ""; |
| sPrjRoot = ""; |
| sInputFileName = ""; |
| sActFileName = ""; |
| Export::sLanguages = ""; |
| sal_uInt16 nState = STATE_NON; |
| sal_Bool bInput = sal_False; |
| |
| // parse command line |
| for( int i = 1; i < argc; i++ ) { |
| if ( ByteString( argv[ i ] ).ToUpperAscii() == "-I" ) { |
| nState = STATE_INPUT; // next token specifies source file |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-O" ) { |
| nState = STATE_OUTPUT; // next token specifies the dest file |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-P" ) { |
| nState = STATE_PRJ; // next token specifies the cur. project |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-R" ) { |
| nState = STATE_ROOT; // next token specifies path to project root |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-M" ) { |
| nState = STATE_MERGESRC; // next token specifies the merge database |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-E" ) { |
| nState = STATE_ERRORLOG; |
| bErrorLog = sal_False; |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-UTF8" ) { |
| nState = STATE_UTF8; |
| bUTF8 = sal_True; |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-NOUTF8" ) { |
| nState = STATE_UTF8; |
| bUTF8 = sal_False; |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-L" ) { |
| nState = STATE_LANGUAGES; |
| } |
| else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-ISO99" ) { |
| nState = STATE_ISOCODE99; |
| } |
| else { |
| switch ( nState ) { |
| case STATE_NON: { |
| return NULL; // no valid command line |
| } |
| case STATE_INPUT: { |
| sInputFileName = argv[ i ]; |
| bInput = sal_True; // source file found |
| } |
| break; |
| case STATE_OUTPUT: { |
| sOutputFile = 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 = sal_True; // activate merge mode, cause merge database found |
| } |
| break; |
| case STATE_LANGUAGES: { |
| Export::sLanguages = ByteString( argv[ i ]); |
| } |
| break; |
| } |
| } |
| } |
| |
| if ( bInput ) { |
| // command line is valid |
| bEnableExport = sal_True; |
| char *pReturn = new char[ sOutputFile.Len() + 1 ]; |
| strcpy( pReturn, sOutputFile.GetBuffer()); // #100211# - checked |
| return pReturn; |
| } |
| |
| // command line is not valid |
| return NULL; |
| } |
| void removeTempFile(){ |
| if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ |
| DirEntry aTempFile( sUsedTempFile ); |
| aTempFile.Kill(); |
| } |
| } |
| /*****************************************************************************/ |
| int InitXrmExport( char *pOutput , char* pFilename) |
| /*****************************************************************************/ |
| { |
| // instanciate Export |
| ByteString sOutput( pOutput ); |
| ByteString sFilename( pFilename ); |
| Export::InitLanguages( false ); |
| |
| if ( bMergeMode ) |
| pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename ); |
| else if ( sOutputFile.Len()) { |
| pParser = new XRMResExport( sOutputFile, sPrj, sActFileName ); |
| } |
| |
| return 1; |
| } |
| |
| /*****************************************************************************/ |
| int EndXrmExport() |
| /*****************************************************************************/ |
| { |
| delete pParser; |
| return 1; |
| } |
| extern const char* getFilename() |
| { |
| return sInputFileName.GetBuffer(); |
| } |
| /*****************************************************************************/ |
| extern FILE *GetXrmFile() |
| /*****************************************************************************/ |
| { |
| FILE *pFile = 0; |
| // look for valid filename |
| if ( sInputFileName.Len()) { |
| if( Export::fileHasUTF8ByteOrderMarker( sInputFileName ) ){ |
| DirEntry aTempFile = Export::GetTempFile(); |
| DirEntry aSourceFile( String( sInputFileName , RTL_TEXTENCODING_ASCII_US ) ); |
| aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); |
| String sTempFile = aTempFile.GetFull(); |
| Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); |
| pFile = fopen( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ).GetBuffer(), "r" ); |
| sUsedTempFile = sTempFile; |
| }else{ |
| // able to open file? |
| pFile = fopen( sInputFileName.GetBuffer(), "r" ); |
| sUsedTempFile = String::CreateFromAscii(""); |
| } |
| if ( !pFile ){ |
| fprintf( stderr, "Error: Could not open file %s\n", |
| sInputFileName.GetBuffer()); |
| } |
| else { |
| // this is a valid file which can be opened, so |
| // create path to project root |
| DirEntry aEntry( String( sInputFileName, 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( "/", "\\" ); |
| |
| return pFile; |
| } |
| } |
| // this means the file could not be opened |
| return NULL; |
| } |
| |
| /*****************************************************************************/ |
| int WorkOnTokenSet( int nTyp, char *pTokenText ) |
| /*****************************************************************************/ |
| { |
| //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText ); |
| pParser->Execute( nTyp, pTokenText ); |
| |
| return 1; |
| } |
| |
| /*****************************************************************************/ |
| int SetError() |
| /*****************************************************************************/ |
| { |
| pParser->SetError(); |
| return 1; |
| } |
| } |
| |
| extern "C" { |
| /*****************************************************************************/ |
| int GetError() |
| /*****************************************************************************/ |
| { |
| return pParser->GetError(); |
| } |
| } |
| |
| // |
| // class XRMResParser |
| // |
| |
| |
| /*****************************************************************************/ |
| XRMResParser::XRMResParser() |
| /*****************************************************************************/ |
| : bError( sal_False ), |
| bText( sal_False ) |
| { |
| aLanguages = Export::GetLanguages(); |
| } |
| |
| /*****************************************************************************/ |
| XRMResParser::~XRMResParser() |
| /*****************************************************************************/ |
| { |
| } |
| |
| /*****************************************************************************/ |
| int XRMResParser::Execute( int nToken, char * pToken ) |
| /*****************************************************************************/ |
| { |
| ByteString rToken( pToken ); |
| |
| switch ( nToken ) { |
| case XRM_README_START: |
| sLID = ""; |
| sGID = GetAttribute( rToken, "name" ); |
| break; |
| |
| case XRM_README_END: |
| sGID = ""; |
| break; |
| |
| case XRM_SECTION_START: |
| sLID = ""; |
| sGID += "."; |
| sGID += GetAttribute( rToken, "id" ); |
| //sLocalized = "1"; |
| |
| //sLocalized = "X:"; |
| sLocalized = true; |
| break; |
| |
| case XRM_SECTION_END: |
| sGID = sGID.GetToken( 0, '.' ); |
| break; |
| |
| case XRM_PARAGRAPH_START: |
| sLID = ""; |
| sGID += "."; |
| sGID += GetAttribute( rToken, "id" ); |
| // if ( GetAttribute( rToken, "localized" ) == "false" ) |
| // sLocalized += "0"; |
| // sLocalized = false; |
| // else |
| // sLocalized += "1"; |
| sLocalized = true; |
| break; |
| |
| case XRM_PARAGRAPH_END: { |
| if ( sLID.Len()) |
| EndOfText( sCurrentOpenTag, sCurrentCloseTag ); |
| ByteString sTmp = sGID; |
| sGID = ""; |
| for ( sal_uInt16 i = 0; i + 1 < sTmp.GetTokenCount( '.' ); i++ ) { |
| if ( sGID.Len()) |
| sGID += "."; |
| sGID += sTmp.GetToken( i, '.' ); |
| } |
| //sLocalized = sLocalized.Copy( 0, sLocalized.Len() - 1 ); |
| } |
| break; |
| |
| case XRM_TEXT_START:{ |
| //printf("->XRM_TEXT_START\n"); |
| ByteString sNewLID = GetAttribute( rToken, "id" ); |
| if ( sNewLID != sLID ) { |
| //EndOfText( sCurrentOpenTag, sCurrentCloseTag ); |
| sLID = sNewLID; |
| } |
| bText = sal_True; |
| sCurrentText = ""; |
| sCurrentOpenTag = rToken; |
| Output( rToken ); |
| //printf("<-XRM_TEXT_START\n"); |
| } |
| break; |
| |
| case XRM_TEXT_END: { |
| sCurrentCloseTag = rToken; |
| //printf("->XRM_TEXT_END\n"); |
| ByteString sLang = GetAttribute( sCurrentOpenTag, "xml:lang" ); |
| WorkOnText( sCurrentOpenTag, sCurrentText ); |
| Output( sCurrentText ); |
| EndOfText( sCurrentOpenTag, sCurrentCloseTag );// <--- |
| bText = sal_False; |
| rToken = ByteString(""); |
| sCurrentText = ByteString(""); |
| //printf("<-XRM_TEXT_END"); |
| } |
| break; |
| |
| case XRM_LIST_START: |
| sLID = ""; |
| break; |
| |
| case XRM_LIST_END: |
| if ( sLID.Len()) |
| EndOfText( sCurrentOpenTag, sCurrentCloseTag ); |
| break; |
| |
| default: |
| if ( bText ) { |
| sCurrentText += rToken; |
| } |
| break; |
| } |
| |
| if ( !bText ) |
| { |
| Output( rToken ); |
| } |
| return 0; |
| } |
| |
| /*****************************************************************************/ |
| ByteString XRMResParser::GetAttribute( const ByteString &rToken, const ByteString &rAttribute ) |
| /*****************************************************************************/ |
| { |
| ByteString sTmp( rToken ); |
| sTmp.SearchAndReplaceAll( "\t", " " ); |
| |
| ByteString sSearch( " " ); |
| sSearch += rAttribute; |
| sSearch += "="; |
| sal_uInt16 nPos = sTmp.Search( sSearch ); |
| |
| if ( nPos != STRING_NOTFOUND ) { |
| sTmp = sTmp.Copy( nPos ); |
| ByteString sId = sTmp.GetToken( 1, '\"' ); |
| return sId; |
| } |
| return ""; |
| } |
| |
| |
| /*****************************************************************************/ |
| void XRMResParser::Error( const ByteString &rError ) |
| /*****************************************************************************/ |
| { |
| yyerror(( char * ) rError.GetBuffer()); |
| } |
| |
| /*****************************************************************************/ |
| void XRMResParser::ConvertStringToDBFormat( ByteString &rString ) |
| /*****************************************************************************/ |
| { |
| ByteString sResult; |
| do { |
| sResult = rString; |
| rString.EraseLeadingChars( _LF ); |
| // rString.EraseLeadingChars( ' ' ); |
| rString.EraseLeadingChars( '\t' ); |
| // rString.EraseTrailingChars( ' ' ); |
| rString.EraseTrailingChars( '\t' ); |
| } while ( sResult != rString ); |
| |
| rString.SearchAndReplaceAll( "\t", "\\t" ); |
| } |
| |
| /*****************************************************************************/ |
| void XRMResParser::ConvertStringToXMLFormat( ByteString &rString ) |
| /*****************************************************************************/ |
| { |
| rString.SearchAndReplaceAll( "\\t", "\t" ); |
| } |
| |
| |
| |
| // |
| // class XRMResOutputParser |
| // |
| |
| /*****************************************************************************/ |
| XRMResOutputParser::XRMResOutputParser ( const ByteString &rOutputFile ) |
| /*****************************************************************************/ |
| { |
| aLanguages = Export::GetLanguages(); |
| pOutputStream = |
| new SvFileStream( |
| String( rOutputFile, RTL_TEXTENCODING_ASCII_US ), |
| STREAM_STD_WRITE | STREAM_TRUNC |
| ); |
| pOutputStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); |
| if ( !pOutputStream->IsOpen()) { |
| ByteString sError( "Unable to open output file: " ); |
| sError += rOutputFile; |
| Error( sError ); |
| delete pOutputStream; |
| pOutputStream = NULL; |
| } |
| } |
| |
| /*****************************************************************************/ |
| XRMResOutputParser::~XRMResOutputParser() |
| /*****************************************************************************/ |
| { |
| if ( pOutputStream ) { |
| pOutputStream->Close(); |
| delete pOutputStream; |
| } |
| } |
| |
| // |
| // class XMLResExport |
| // |
| |
| /*****************************************************************************/ |
| XRMResExport::XRMResExport( |
| const ByteString &rOutputFile, const ByteString &rProject, |
| const ByteString &rFilePath ) |
| /*****************************************************************************/ |
| : XRMResOutputParser( rOutputFile ), |
| pResData( NULL ), |
| sPrj( rProject ), |
| sPath( rFilePath ) |
| { |
| aLanguages = Export::GetLanguages(); |
| } |
| |
| /*****************************************************************************/ |
| XRMResExport::~XRMResExport() |
| /*****************************************************************************/ |
| { |
| delete pResData; |
| } |
| |
| void XRMResExport::Output( const ByteString& rOutput ) |
| { |
| // Dummy to suppress warnings caused by poor class design |
| (void) rOutput; |
| } |
| |
| /*****************************************************************************/ |
| void XRMResExport::WorkOnText( |
| const ByteString &rOpenTag, |
| ByteString &rText |
| ) |
| /*****************************************************************************/ |
| { |
| ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); |
| |
| if ( !pResData ) { |
| ByteString sPlatform( "" ); |
| pResData = new ResData( sPlatform, GetGID() ); |
| pResData->sId = GetLID(); |
| } |
| |
| pResData->sText[ sLang ] = rText; |
| ConvertStringToDBFormat( pResData->sText[ sLang ] ); |
| } |
| |
| /*****************************************************************************/ |
| void XRMResExport::EndOfText( |
| const ByteString &rOpenTag, |
| const ByteString &rCloseTag |
| ) |
| /*****************************************************************************/ |
| { |
| |
| (void) rOpenTag; // FIXME |
| (void) rCloseTag; // FIXME |
| |
| if ( pResData && pOutputStream ) { |
| |
| char cSearch = 0x00; |
| ByteString sSearch( cSearch ); |
| |
| // if ( !pResData->sText[ ByteString("en-US") ].Len() ) |
| // pResData->sText[ ByteString("en-US") ] = pResData->sText[ ByteString("de") ]; |
| |
| Export::FillInFallbacks( pResData ); |
| |
| ByteString sTimeStamp( Export::GetTimeStamp()); |
| ByteString sCur; |
| for( unsigned int n = 0; n < aLanguages.size(); n++ ){ |
| sCur = aLanguages[ n ]; |
| |
| ByteString sAct = pResData->sText[ sCur ]; |
| //Export::UnquotHTML( sAct ); |
| sAct.EraseAllChars( 0x0A ); |
| |
| ByteString sOutput( sPrj ); sOutput += "\t"; |
| sOutput += sPath; |
| sOutput += "\t0\t"; |
| sOutput += "readmeitem\t"; |
| sOutput += pResData->sId; |
| // USE LID AS GID OR MERGE DON'T WORK |
| //sOutput += pResData->sGId; |
| sOutput += "\t"; |
| sOutput += pResData->sId; |
| sOutput += "\t\t\t0\t"; |
| sOutput += sCur; |
| sOutput += "\t"; |
| |
| sOutput += sAct; sOutput += "\t\t\t\t"; |
| sOutput += sTimeStamp; |
| |
| sOutput.SearchAndReplaceAll( sSearch, "_" ); |
| //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sPrj ) ) ) |
| if( sAct.Len() > 1 ) |
| pOutputStream->WriteLine( sOutput ); |
| } |
| } |
| delete pResData; |
| pResData = NULL; |
| } |
| |
| // |
| // class XRMResMerge |
| // |
| |
| /*****************************************************************************/ |
| XRMResMerge::XRMResMerge( |
| const ByteString &rMergeSource, const ByteString &rOutputFile, |
| ByteString &rFilename) |
| /*****************************************************************************/ |
| : XRMResOutputParser( rOutputFile ), |
| pMergeDataFile( NULL ), |
| sFilename( rFilename ) , |
| pResData( NULL ) |
| { |
| if ( rMergeSource.Len()) |
| pMergeDataFile = new MergeDataFile( |
| rMergeSource, sInputFileName , bErrorLog, RTL_TEXTENCODING_MS_1252);//, bUTF8 ); |
| if( Export::sLanguages.EqualsIgnoreCaseAscii("ALL") ){ |
| Export::SetLanguages( pMergeDataFile->GetLanguages() ); |
| aLanguages = pMergeDataFile->GetLanguages(); |
| } |
| else aLanguages = Export::GetLanguages(); |
| } |
| |
| /*****************************************************************************/ |
| XRMResMerge::~XRMResMerge() |
| /*****************************************************************************/ |
| { |
| delete pMergeDataFile; |
| delete pResData; |
| } |
| |
| /*****************************************************************************/ |
| void XRMResMerge::WorkOnText( |
| const ByteString &rOpenTag, |
| ByteString &rText |
| ) |
| /*****************************************************************************/ |
| { |
| ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); |
| |
| if ( pMergeDataFile ) { |
| if ( !pResData ) { |
| ByteString sPlatform( "" ); |
| // pResData = new ResData( sPlatform, GetGID() , sFilename ); |
| pResData = new ResData( sPlatform, GetLID() , sFilename ); |
| pResData->sId = GetLID(); |
| |
| pResData->sResTyp = "readmeitem"; |
| } |
| |
| PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); |
| if ( pEntrys ) { |
| ByteString sContent; |
| if ( Export::isAllowed( sLang ) && |
| ( pEntrys->GetText( |
| sContent, STRING_TYP_TEXT, sLang )) && |
| ( sContent != "-" ) && ( sContent.Len())) |
| |
| { |
| rText = sContent; |
| ConvertStringToXMLFormat( rText ); |
| //Export::QuotHTMLXRM( rText ); |
| } |
| } |
| } |
| } |
| |
| /*****************************************************************************/ |
| void XRMResMerge::Output( const ByteString& rOutput ) |
| /*****************************************************************************/ |
| { |
| //printf("W: %s\n",rOutput.GetBuffer()); |
| if ( pOutputStream && rOutput.Len() > 0 ) |
| pOutputStream->Write( rOutput.GetBuffer(), rOutput.Len()); |
| } |
| |
| /*****************************************************************************/ |
| void XRMResMerge::EndOfText( |
| const ByteString &rOpenTag, |
| const ByteString &rCloseTag |
| ) |
| /*****************************************************************************/ |
| { |
| |
| Output( rCloseTag ); |
| if ( pMergeDataFile && pResData ) { |
| PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); |
| if ( pEntrys ) { |
| ByteString sCur; |
| for( unsigned int n = 0; n < aLanguages.size(); n++ ){ |
| sCur = aLanguages[ n ]; |
| ByteString sContent; |
| if ( !sCur.EqualsIgnoreCaseAscii("en-US") && |
| ( pEntrys->GetText( |
| sContent, STRING_TYP_TEXT, sCur, sal_True )) && |
| ( sContent != "-" ) && ( sContent.Len())) |
| { |
| ByteString sText( sContent ); |
| //Export::QuotHTMLXRM( sText ); |
| |
| ByteString sAdditionalLine( "\t" ); |
| sAdditionalLine += rOpenTag; |
| ByteString sSearch = "xml:lang=\""; |
| ByteString sReplace( sSearch ); |
| |
| sSearch += GetAttribute( rOpenTag, "xml:lang" ); |
| sReplace += sCur; |
| |
| sAdditionalLine.SearchAndReplace( sSearch, sReplace ); |
| |
| sAdditionalLine += sText; |
| sAdditionalLine += rCloseTag; |
| sAdditionalLine += "\n"; |
| |
| for ( sal_uInt16 i = 0; i + 1 < GetGID().GetTokenCount( '.' ); i++ ) |
| sAdditionalLine += "\t"; |
| |
| Output( sAdditionalLine ); |
| } |
| } |
| } |
| } |
| delete pResData; |
| pResData = NULL; |
| } |
| |