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