1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_l10ntools.hxx" 30 #include <stdio.h> 31 #include <tools/string.hxx> 32 #include <tools/fsys.hxx> 33 34 // local includes 35 #include "export.hxx" 36 #include "xrmmerge.hxx" 37 #include "utf8conv.hxx" 38 #include "tokens.h" 39 #include <iostream> 40 #include <vector> 41 42 using namespace std; 43 44 extern "C" { int yyerror( char * ); } 45 extern "C" { int YYWarning( char * ); } 46 47 // defines to parse command line 48 #define STATE_NON 0x0001 49 #define STATE_INPUT 0x0002 50 #define STATE_OUTPUT 0x0003 51 #define STATE_PRJ 0x0004 52 #define STATE_ROOT 0x0005 53 #define STATE_MERGESRC 0x0006 54 #define STATE_ERRORLOG 0x0007 55 #define STATE_UTF8 0x000B 56 #define STATE_LANGUAGES 0x000C 57 #define STATE_ISOCODE99 0x000D 58 59 // set of global variables 60 sal_Bool bEnableExport; 61 sal_Bool bMergeMode; 62 sal_Bool bErrorLog; 63 sal_Bool bUTF8; 64 ByteString sPrj; 65 ByteString sPrjRoot; 66 ByteString sInputFileName; 67 ByteString sActFileName; 68 ByteString sOutputFile; 69 ByteString sMergeSrc; 70 String sUsedTempFile; 71 XRMResParser *pParser = NULL; 72 73 extern "C" { 74 // the whole interface to lexer is in this extern "C" section 75 76 /*****************************************************************************/ 77 extern char *GetOutputFile( int argc, char* argv[]) 78 /*****************************************************************************/ 79 { 80 bEnableExport = sal_False; 81 bMergeMode = sal_False; 82 bErrorLog = sal_True; 83 bUTF8 = sal_True; 84 sPrj = ""; 85 sPrjRoot = ""; 86 sInputFileName = ""; 87 sActFileName = ""; 88 Export::sLanguages = ""; 89 sal_uInt16 nState = STATE_NON; 90 sal_Bool bInput = sal_False; 91 92 // parse command line 93 for( int i = 1; i < argc; i++ ) { 94 if ( ByteString( argv[ i ] ).ToUpperAscii() == "-I" ) { 95 nState = STATE_INPUT; // next token specifies source file 96 } 97 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-O" ) { 98 nState = STATE_OUTPUT; // next token specifies the dest file 99 } 100 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-P" ) { 101 nState = STATE_PRJ; // next token specifies the cur. project 102 } 103 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-R" ) { 104 nState = STATE_ROOT; // next token specifies path to project root 105 } 106 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-M" ) { 107 nState = STATE_MERGESRC; // next token specifies the merge database 108 } 109 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-E" ) { 110 nState = STATE_ERRORLOG; 111 bErrorLog = sal_False; 112 } 113 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-UTF8" ) { 114 nState = STATE_UTF8; 115 bUTF8 = sal_True; 116 } 117 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-NOUTF8" ) { 118 nState = STATE_UTF8; 119 bUTF8 = sal_False; 120 } 121 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-L" ) { 122 nState = STATE_LANGUAGES; 123 } 124 else if ( ByteString( argv[ i ] ).ToUpperAscii() == "-ISO99" ) { 125 nState = STATE_ISOCODE99; 126 } 127 else { 128 switch ( nState ) { 129 case STATE_NON: { 130 return NULL; // no valid command line 131 } 132 case STATE_INPUT: { 133 sInputFileName = argv[ i ]; 134 bInput = sal_True; // source file found 135 } 136 break; 137 case STATE_OUTPUT: { 138 sOutputFile = argv[ i ]; // the dest. file 139 } 140 break; 141 case STATE_PRJ: { 142 sPrj = ByteString( argv[ i ]); 143 } 144 break; 145 case STATE_ROOT: { 146 sPrjRoot = ByteString( argv[ i ]); // path to project root 147 } 148 break; 149 case STATE_MERGESRC: { 150 sMergeSrc = ByteString( argv[ i ]); 151 bMergeMode = sal_True; // activate merge mode, cause merge database found 152 } 153 break; 154 case STATE_LANGUAGES: { 155 Export::sLanguages = ByteString( argv[ i ]); 156 } 157 break; 158 } 159 } 160 } 161 162 if ( bInput ) { 163 // command line is valid 164 bEnableExport = sal_True; 165 char *pReturn = new char[ sOutputFile.Len() + 1 ]; 166 strcpy( pReturn, sOutputFile.GetBuffer()); // #100211# - checked 167 return pReturn; 168 } 169 170 // command line is not valid 171 return NULL; 172 } 173 void removeTempFile(){ 174 if( !sUsedTempFile.EqualsIgnoreCaseAscii( "" ) ){ 175 DirEntry aTempFile( sUsedTempFile ); 176 aTempFile.Kill(); 177 } 178 } 179 /*****************************************************************************/ 180 int InitXrmExport( char *pOutput , char* pFilename) 181 /*****************************************************************************/ 182 { 183 // instanciate Export 184 ByteString sOutput( pOutput ); 185 ByteString sFilename( pFilename ); 186 Export::InitLanguages( false ); 187 188 if ( bMergeMode ) 189 pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename ); 190 else if ( sOutputFile.Len()) { 191 pParser = new XRMResExport( sOutputFile, sPrj, sActFileName ); 192 } 193 194 return 1; 195 } 196 197 /*****************************************************************************/ 198 int EndXrmExport() 199 /*****************************************************************************/ 200 { 201 delete pParser; 202 return 1; 203 } 204 extern const char* getFilename() 205 { 206 return sInputFileName.GetBuffer(); 207 } 208 /*****************************************************************************/ 209 extern FILE *GetXrmFile() 210 /*****************************************************************************/ 211 { 212 FILE *pFile = 0; 213 // look for valid filename 214 if ( sInputFileName.Len()) { 215 if( Export::fileHasUTF8ByteOrderMarker( sInputFileName ) ){ 216 DirEntry aTempFile = Export::GetTempFile(); 217 DirEntry aSourceFile( String( sInputFileName , RTL_TEXTENCODING_ASCII_US ) ); 218 aSourceFile.CopyTo( aTempFile , FSYS_ACTION_COPYFILE ); 219 String sTempFile = aTempFile.GetFull(); 220 Export::RemoveUTF8ByteOrderMarkerFromFile( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ) ); 221 pFile = fopen( ByteString( sTempFile , RTL_TEXTENCODING_ASCII_US ).GetBuffer(), "r" ); 222 sUsedTempFile = sTempFile; 223 }else{ 224 // able to open file? 225 pFile = fopen( sInputFileName.GetBuffer(), "r" ); 226 sUsedTempFile = String::CreateFromAscii(""); 227 } 228 if ( !pFile ){ 229 fprintf( stderr, "Error: Could not open file %s\n", 230 sInputFileName.GetBuffer()); 231 } 232 else { 233 // this is a valid file which can be opened, so 234 // create path to project root 235 DirEntry aEntry( String( sInputFileName, RTL_TEXTENCODING_ASCII_US )); 236 aEntry.ToAbs(); 237 ByteString sFullEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); 238 aEntry += DirEntry( String( "..", RTL_TEXTENCODING_ASCII_US )); 239 aEntry += DirEntry( sPrjRoot ); 240 ByteString sPrjEntry( aEntry.GetFull(), RTL_TEXTENCODING_ASCII_US ); 241 242 // create file name, beginnig with project root 243 // (e.g.: source\ui\src\menue.src) 244 sActFileName = sFullEntry.Copy( sPrjEntry.Len() + 1 ); 245 246 247 sActFileName.SearchAndReplaceAll( "/", "\\" ); 248 249 return pFile; 250 } 251 } 252 // this means the file could not be opened 253 return NULL; 254 } 255 256 /*****************************************************************************/ 257 int WorkOnTokenSet( int nTyp, char *pTokenText ) 258 /*****************************************************************************/ 259 { 260 //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText ); 261 pParser->Execute( nTyp, pTokenText ); 262 263 return 1; 264 } 265 266 /*****************************************************************************/ 267 int SetError() 268 /*****************************************************************************/ 269 { 270 pParser->SetError(); 271 return 1; 272 } 273 } 274 275 extern "C" { 276 /*****************************************************************************/ 277 int GetError() 278 /*****************************************************************************/ 279 { 280 return pParser->GetError(); 281 } 282 } 283 284 // 285 // class XRMResParser 286 // 287 288 289 /*****************************************************************************/ 290 XRMResParser::XRMResParser() 291 /*****************************************************************************/ 292 : bError( sal_False ), 293 bText( sal_False ) 294 { 295 aLanguages = Export::GetLanguages(); 296 } 297 298 /*****************************************************************************/ 299 XRMResParser::~XRMResParser() 300 /*****************************************************************************/ 301 { 302 } 303 304 /*****************************************************************************/ 305 int XRMResParser::Execute( int nToken, char * pToken ) 306 /*****************************************************************************/ 307 { 308 ByteString rToken( pToken ); 309 310 switch ( nToken ) { 311 case XRM_README_START: 312 sLID = ""; 313 sGID = GetAttribute( rToken, "name" ); 314 break; 315 316 case XRM_README_END: 317 sGID = ""; 318 break; 319 320 case XRM_SECTION_START: 321 sLID = ""; 322 sGID += "."; 323 sGID += GetAttribute( rToken, "id" ); 324 //sLocalized = "1"; 325 326 //sLocalized = "X:"; 327 sLocalized = true; 328 break; 329 330 case XRM_SECTION_END: 331 sGID = sGID.GetToken( 0, '.' ); 332 break; 333 334 case XRM_PARAGRAPH_START: 335 sLID = ""; 336 sGID += "."; 337 sGID += GetAttribute( rToken, "id" ); 338 // if ( GetAttribute( rToken, "localized" ) == "false" ) 339 // sLocalized += "0"; 340 // sLocalized = false; 341 // else 342 // sLocalized += "1"; 343 sLocalized = true; 344 break; 345 346 case XRM_PARAGRAPH_END: { 347 if ( sLID.Len()) 348 EndOfText( sCurrentOpenTag, sCurrentCloseTag ); 349 ByteString sTmp = sGID; 350 sGID = ""; 351 for ( sal_uInt16 i = 0; i + 1 < sTmp.GetTokenCount( '.' ); i++ ) { 352 if ( sGID.Len()) 353 sGID += "."; 354 sGID += sTmp.GetToken( i, '.' ); 355 } 356 //sLocalized = sLocalized.Copy( 0, sLocalized.Len() - 1 ); 357 } 358 break; 359 360 case XRM_TEXT_START:{ 361 //printf("->XRM_TEXT_START\n"); 362 ByteString sNewLID = GetAttribute( rToken, "id" ); 363 if ( sNewLID != sLID ) { 364 //EndOfText( sCurrentOpenTag, sCurrentCloseTag ); 365 sLID = sNewLID; 366 } 367 bText = sal_True; 368 sCurrentText = ""; 369 sCurrentOpenTag = rToken; 370 Output( rToken ); 371 //printf("<-XRM_TEXT_START\n"); 372 } 373 break; 374 375 case XRM_TEXT_END: { 376 sCurrentCloseTag = rToken; 377 //printf("->XRM_TEXT_END\n"); 378 ByteString sLang = GetAttribute( sCurrentOpenTag, "xml:lang" ); 379 WorkOnText( sCurrentOpenTag, sCurrentText ); 380 Output( sCurrentText ); 381 EndOfText( sCurrentOpenTag, sCurrentCloseTag );// <--- 382 bText = sal_False; 383 rToken = ByteString(""); 384 sCurrentText = ByteString(""); 385 //printf("<-XRM_TEXT_END"); 386 } 387 break; 388 389 case XRM_LIST_START: 390 sLID = ""; 391 break; 392 393 case XRM_LIST_END: 394 if ( sLID.Len()) 395 EndOfText( sCurrentOpenTag, sCurrentCloseTag ); 396 break; 397 398 default: 399 if ( bText ) { 400 sCurrentText += rToken; 401 } 402 break; 403 } 404 405 if ( !bText ) 406 { 407 Output( rToken ); 408 } 409 return 0; 410 } 411 412 /*****************************************************************************/ 413 ByteString XRMResParser::GetAttribute( const ByteString &rToken, const ByteString &rAttribute ) 414 /*****************************************************************************/ 415 { 416 ByteString sTmp( rToken ); 417 sTmp.SearchAndReplaceAll( "\t", " " ); 418 419 ByteString sSearch( " " ); 420 sSearch += rAttribute; 421 sSearch += "="; 422 sal_uInt16 nPos = sTmp.Search( sSearch ); 423 424 if ( nPos != STRING_NOTFOUND ) { 425 sTmp = sTmp.Copy( nPos ); 426 ByteString sId = sTmp.GetToken( 1, '\"' ); 427 return sId; 428 } 429 return ""; 430 } 431 432 433 /*****************************************************************************/ 434 void XRMResParser::Error( const ByteString &rError ) 435 /*****************************************************************************/ 436 { 437 yyerror(( char * ) rError.GetBuffer()); 438 } 439 440 /*****************************************************************************/ 441 void XRMResParser::ConvertStringToDBFormat( ByteString &rString ) 442 /*****************************************************************************/ 443 { 444 ByteString sResult; 445 do { 446 sResult = rString; 447 rString.EraseLeadingChars( _LF ); 448 // rString.EraseLeadingChars( ' ' ); 449 rString.EraseLeadingChars( '\t' ); 450 // rString.EraseTrailingChars( ' ' ); 451 rString.EraseTrailingChars( '\t' ); 452 } while ( sResult != rString ); 453 454 rString.SearchAndReplaceAll( "\t", "\\t" ); 455 } 456 457 /*****************************************************************************/ 458 void XRMResParser::ConvertStringToXMLFormat( ByteString &rString ) 459 /*****************************************************************************/ 460 { 461 rString.SearchAndReplaceAll( "\\t", "\t" ); 462 } 463 464 465 466 // 467 // class XRMResOutputParser 468 // 469 470 /*****************************************************************************/ 471 XRMResOutputParser::XRMResOutputParser ( const ByteString &rOutputFile ) 472 /*****************************************************************************/ 473 { 474 aLanguages = Export::GetLanguages(); 475 pOutputStream = 476 new SvFileStream( 477 String( rOutputFile, RTL_TEXTENCODING_ASCII_US ), 478 STREAM_STD_WRITE | STREAM_TRUNC 479 ); 480 pOutputStream->SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); 481 if ( !pOutputStream->IsOpen()) { 482 ByteString sError( "Unable to open output file: " ); 483 sError += rOutputFile; 484 Error( sError ); 485 delete pOutputStream; 486 pOutputStream = NULL; 487 } 488 } 489 490 /*****************************************************************************/ 491 XRMResOutputParser::~XRMResOutputParser() 492 /*****************************************************************************/ 493 { 494 if ( pOutputStream ) { 495 pOutputStream->Close(); 496 delete pOutputStream; 497 } 498 } 499 500 // 501 // class XMLResExport 502 // 503 504 /*****************************************************************************/ 505 XRMResExport::XRMResExport( 506 const ByteString &rOutputFile, const ByteString &rProject, 507 const ByteString &rFilePath ) 508 /*****************************************************************************/ 509 : XRMResOutputParser( rOutputFile ), 510 pResData( NULL ), 511 sPrj( rProject ), 512 sPath( rFilePath ) 513 { 514 aLanguages = Export::GetLanguages(); 515 } 516 517 /*****************************************************************************/ 518 XRMResExport::~XRMResExport() 519 /*****************************************************************************/ 520 { 521 delete pResData; 522 } 523 524 void XRMResExport::Output( const ByteString& rOutput ) 525 { 526 // Dummy to suppress warnings caused by poor class design 527 (void) rOutput; 528 } 529 530 /*****************************************************************************/ 531 void XRMResExport::WorkOnText( 532 const ByteString &rOpenTag, 533 ByteString &rText 534 ) 535 /*****************************************************************************/ 536 { 537 ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); 538 539 if ( !pResData ) { 540 ByteString sPlatform( "" ); 541 pResData = new ResData( sPlatform, GetGID() ); 542 pResData->sId = GetLID(); 543 } 544 545 pResData->sText[ sLang ] = rText; 546 ConvertStringToDBFormat( pResData->sText[ sLang ] ); 547 } 548 549 /*****************************************************************************/ 550 void XRMResExport::EndOfText( 551 const ByteString &rOpenTag, 552 const ByteString &rCloseTag 553 ) 554 /*****************************************************************************/ 555 { 556 557 (void) rOpenTag; // FIXME 558 (void) rCloseTag; // FIXME 559 560 if ( pResData && pOutputStream ) { 561 562 char cSearch = 0x00; 563 ByteString sSearch( cSearch ); 564 565 // if ( !pResData->sText[ ByteString("en-US") ].Len() ) 566 // pResData->sText[ ByteString("en-US") ] = pResData->sText[ ByteString("de") ]; 567 568 Export::FillInFallbacks( pResData ); 569 570 ByteString sTimeStamp( Export::GetTimeStamp()); 571 ByteString sCur; 572 for( unsigned int n = 0; n < aLanguages.size(); n++ ){ 573 sCur = aLanguages[ n ]; 574 575 ByteString sAct = pResData->sText[ sCur ]; 576 //Export::UnquotHTML( sAct ); 577 sAct.EraseAllChars( 0x0A ); 578 579 ByteString sOutput( sPrj ); sOutput += "\t"; 580 sOutput += sPath; 581 sOutput += "\t0\t"; 582 sOutput += "readmeitem\t"; 583 sOutput += pResData->sId; 584 // USE LID AS GID OR MERGE DON'T WORK 585 //sOutput += pResData->sGId; 586 sOutput += "\t"; 587 sOutput += pResData->sId; 588 sOutput += "\t\t\t0\t"; 589 sOutput += sCur; 590 sOutput += "\t"; 591 592 sOutput += sAct; sOutput += "\t\t\t\t"; 593 sOutput += sTimeStamp; 594 595 sOutput.SearchAndReplaceAll( sSearch, "_" ); 596 //if( !sCur.EqualsIgnoreCaseAscii("de") ||( sCur.EqualsIgnoreCaseAscii("de") && !Export::isMergingGermanAllowed( sPrj ) ) ) 597 if( sAct.Len() > 1 ) 598 pOutputStream->WriteLine( sOutput ); 599 } 600 } 601 delete pResData; 602 pResData = NULL; 603 } 604 605 // 606 // class XRMResMerge 607 // 608 609 /*****************************************************************************/ 610 XRMResMerge::XRMResMerge( 611 const ByteString &rMergeSource, const ByteString &rOutputFile, 612 ByteString &rFilename) 613 /*****************************************************************************/ 614 : XRMResOutputParser( rOutputFile ), 615 pMergeDataFile( NULL ), 616 sFilename( rFilename ) , 617 pResData( NULL ) 618 { 619 if ( rMergeSource.Len()) 620 pMergeDataFile = new MergeDataFile( 621 rMergeSource, sInputFileName , bErrorLog, RTL_TEXTENCODING_MS_1252);//, bUTF8 ); 622 if( Export::sLanguages.EqualsIgnoreCaseAscii("ALL") ){ 623 Export::SetLanguages( pMergeDataFile->GetLanguages() ); 624 aLanguages = pMergeDataFile->GetLanguages(); 625 } 626 else aLanguages = Export::GetLanguages(); 627 } 628 629 /*****************************************************************************/ 630 XRMResMerge::~XRMResMerge() 631 /*****************************************************************************/ 632 { 633 delete pMergeDataFile; 634 delete pResData; 635 } 636 637 /*****************************************************************************/ 638 void XRMResMerge::WorkOnText( 639 const ByteString &rOpenTag, 640 ByteString &rText 641 ) 642 /*****************************************************************************/ 643 { 644 ByteString sLang( GetAttribute( rOpenTag, "xml:lang" )); 645 646 if ( pMergeDataFile ) { 647 if ( !pResData ) { 648 ByteString sPlatform( "" ); 649 // pResData = new ResData( sPlatform, GetGID() , sFilename ); 650 pResData = new ResData( sPlatform, GetLID() , sFilename ); 651 pResData->sId = GetLID(); 652 653 pResData->sResTyp = "readmeitem"; 654 } 655 656 PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); 657 if ( pEntrys ) { 658 ByteString sContent; 659 if ( Export::isAllowed( sLang ) && 660 ( pEntrys->GetText( 661 sContent, STRING_TYP_TEXT, sLang )) && 662 ( sContent != "-" ) && ( sContent.Len())) 663 664 { 665 rText = sContent; 666 ConvertStringToXMLFormat( rText ); 667 //Export::QuotHTMLXRM( rText ); 668 } 669 } 670 } 671 } 672 673 /*****************************************************************************/ 674 void XRMResMerge::Output( const ByteString& rOutput ) 675 /*****************************************************************************/ 676 { 677 //printf("W: %s\n",rOutput.GetBuffer()); 678 if ( pOutputStream && rOutput.Len() > 0 ) 679 pOutputStream->Write( rOutput.GetBuffer(), rOutput.Len()); 680 } 681 682 /*****************************************************************************/ 683 void XRMResMerge::EndOfText( 684 const ByteString &rOpenTag, 685 const ByteString &rCloseTag 686 ) 687 /*****************************************************************************/ 688 { 689 690 Output( rCloseTag ); 691 if ( pMergeDataFile && pResData ) { 692 PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData ); 693 if ( pEntrys ) { 694 ByteString sCur; 695 for( unsigned int n = 0; n < aLanguages.size(); n++ ){ 696 sCur = aLanguages[ n ]; 697 ByteString sContent; 698 if ( !sCur.EqualsIgnoreCaseAscii("en-US") && 699 ( pEntrys->GetText( 700 sContent, STRING_TYP_TEXT, sCur, sal_True )) && 701 ( sContent != "-" ) && ( sContent.Len())) 702 { 703 ByteString sText( sContent ); 704 //Export::QuotHTMLXRM( sText ); 705 706 ByteString sAdditionalLine( "\t" ); 707 sAdditionalLine += rOpenTag; 708 ByteString sSearch = "xml:lang=\""; 709 ByteString sReplace( sSearch ); 710 711 sSearch += GetAttribute( rOpenTag, "xml:lang" ); 712 sReplace += sCur; 713 714 sAdditionalLine.SearchAndReplace( sSearch, sReplace ); 715 716 sAdditionalLine += sText; 717 sAdditionalLine += rCloseTag; 718 sAdditionalLine += "\n"; 719 720 for ( sal_uInt16 i = 0; i + 1 < GetGID().GetTokenCount( '.' ); i++ ) 721 sAdditionalLine += "\t"; 722 723 Output( sAdditionalLine ); 724 } 725 } 726 } 727 } 728 delete pResData; 729 pResData = NULL; 730 } 731 732