Bump for 3.6-28
[LibreOffice.git] / l10ntools / source / xrmmerge.cxx
bloba26e866388af932ac4d2ddbbc83c3f683b1d4c3a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "sal/config.h"
31 #include <cstring>
33 #include <stdio.h>
35 #include "common.hxx"
36 #include "export.hxx"
37 #include "xrmmerge.hxx"
38 #include "tokens.h"
39 #include <iostream>
40 #include <fstream>
41 #include <vector>
43 using namespace std;
45 void yyerror( const char * );
46 void YYWarning( const char * );
48 // defines to parse command line
49 #define STATE_NON 0x0001
50 #define STATE_INPUT 0x0002
51 #define STATE_OUTPUT 0x0003
52 #define STATE_PRJ 0x0004
53 #define STATE_ROOT 0x0005
54 #define STATE_MERGESRC 0x0006
55 #define STATE_ERRORLOG 0x0007
56 #define STATE_LANGUAGES 0x000C
58 // set of global variables
59 sal_Bool bEnableExport;
60 sal_Bool bMergeMode;
61 sal_Bool bErrorLog;
62 sal_Bool bUTF8;
63 sal_Bool bDisplayName;
64 sal_Bool bExtensionDescription;
65 rtl::OString sPrj;
66 rtl::OString sPrjRoot;
67 rtl::OString sInputFileName;
68 rtl::OString sActFileName;
69 rtl::OString sOutputFile;
70 rtl::OString sMergeSrc;
71 rtl::OString sLangAttribute;
72 rtl::OString sResourceType;
73 XRMResParser *pParser = NULL;
75 extern "C" {
76 // the whole interface to lexer is in this extern "C" section
78 /*****************************************************************************/
79 extern char *GetOutputFile( int argc, char* argv[])
80 /*****************************************************************************/
82 bEnableExport = sal_False;
83 bMergeMode = sal_False;
84 bErrorLog = sal_True;
85 bUTF8 = sal_True;
86 bDisplayName = sal_False;
87 bExtensionDescription = sal_False;
88 sPrj = "";
89 sPrjRoot = "";
90 sInputFileName = "";
91 sActFileName = "";
92 Export::sLanguages = "";
93 sal_uInt16 nState = STATE_NON;
94 sal_Bool bInput = sal_False;
96 // parse command line
97 for( int i = 1; i < argc; i++ ) {
98 if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-I" ) {
99 nState = STATE_INPUT; // next token specifies source file
101 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-O" ) {
102 nState = STATE_OUTPUT; // next token specifies the dest file
104 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-P" ) {
105 nState = STATE_PRJ; // next token specifies the cur. project
107 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-R" ) {
108 nState = STATE_ROOT; // next token specifies path to project root
110 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-M" ) {
111 nState = STATE_MERGESRC; // next token specifies the merge database
113 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-E" ) {
114 nState = STATE_ERRORLOG;
115 bErrorLog = sal_False;
117 else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-L" ) {
118 nState = STATE_LANGUAGES;
120 else {
121 switch ( nState ) {
122 case STATE_NON: {
123 return NULL; // no valid command line
125 case STATE_INPUT: {
126 sInputFileName = argv[ i ];
127 bInput = sal_True; // source file found
129 break;
130 case STATE_OUTPUT: {
131 sOutputFile = argv[ i ]; // the dest. file
133 break;
134 case STATE_PRJ: {
135 sPrj = rtl::OString( argv[ i ]);
137 break;
138 case STATE_ROOT: {
139 sPrjRoot = rtl::OString( argv[ i ]); // path to project root
141 break;
142 case STATE_MERGESRC: {
143 sMergeSrc = rtl::OString( argv[ i ]);
144 bMergeMode = sal_True; // activate merge mode, cause merge database found
146 break;
147 case STATE_LANGUAGES: {
148 Export::sLanguages = rtl::OString( argv[ i ]);
150 break;
155 if ( bInput ) {
156 // command line is valid
157 bEnableExport = sal_True;
158 char *pReturn = new char[ sOutputFile.getLength() + 1 ];
159 std::strcpy( pReturn, sOutputFile.getStr()); // #100211# - checked
160 return pReturn;
163 // command line is not valid
164 return NULL;
167 /*****************************************************************************/
168 int InitXrmExport( char *pOutput , char* pFilename)
169 /*****************************************************************************/
171 // instanciate Export
172 rtl::OString sOutput( pOutput );
173 rtl::OString sFilename( pFilename );
174 Export::InitLanguages( false );
176 if ( bMergeMode )
177 pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename );
178 else if (!sOutputFile.isEmpty()) {
179 pParser = new XRMResExport( sOutputFile, sPrj, sActFileName );
182 return 1;
185 /*****************************************************************************/
186 int EndXrmExport()
187 /*****************************************************************************/
189 delete pParser;
190 return 1;
192 extern const char* getFilename()
194 return sInputFileName.getStr();
196 /*****************************************************************************/
197 extern FILE *GetXrmFile()
198 /*****************************************************************************/
200 // look for valid filename
201 if (!sInputFileName.isEmpty()) {
202 //TODO: explicit BOM handling?
203 FILE * pFile = fopen(sInputFileName.getStr(), "r");
204 if ( !pFile ){
205 fprintf( stderr, "Error: Could not open file %s\n",
206 sInputFileName.getStr());
208 else {
209 if (!bMergeMode) {
210 sActFileName = common::pathnameToken(
211 sInputFileName.getStr(), sPrjRoot.getStr());
213 return pFile;
216 // this means the file could not be opened
217 return NULL;
220 /*****************************************************************************/
221 int WorkOnTokenSet( int nTyp, char *pTokenText )
222 /*****************************************************************************/
224 //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText );
225 pParser->Execute( nTyp, pTokenText );
227 return 1;
230 /*****************************************************************************/
231 int SetError()
232 /*****************************************************************************/
234 pParser->SetError();
235 return 1;
239 extern "C" {
240 /*****************************************************************************/
241 int GetError()
242 /*****************************************************************************/
244 return pParser->GetError();
249 // class XRMResParser
253 /*****************************************************************************/
254 XRMResParser::XRMResParser()
255 /*****************************************************************************/
256 : bError( sal_False ),
257 bText( sal_False )
259 aLanguages = Export::GetLanguages();
262 /*****************************************************************************/
263 XRMResParser::~XRMResParser()
264 /*****************************************************************************/
268 /*****************************************************************************/
269 int XRMResParser::Execute( int nToken, char * pToken )
270 /*****************************************************************************/
272 rtl::OString rToken( pToken );
274 switch ( nToken ) {
275 case XRM_TEXT_START:{
276 rtl::OString sNewLID = GetAttribute( rToken, "id" );
277 if ( sNewLID != sLID ) {
278 sLID = sNewLID;
280 bText = sal_True;
281 sCurrentText = "";
282 sCurrentOpenTag = rToken;
283 Output( rToken );
285 break;
287 case XRM_TEXT_END: {
288 sCurrentCloseTag = rToken;
289 sResourceType = rtl::OString ( "readmeitem" );
290 sLangAttribute = rtl::OString ( "xml:lang" );
291 WorkOnText( sCurrentOpenTag, sCurrentText );
292 Output( sCurrentText );
293 EndOfText( sCurrentOpenTag, sCurrentCloseTag );
294 bText = sal_False;
295 rToken = rtl::OString("");
296 sCurrentText = rtl::OString("");
298 break;
300 case DESC_DISPLAY_NAME_START:{
301 bDisplayName = sal_True;
303 break;
305 case DESC_DISPLAY_NAME_END:{
306 bDisplayName = sal_False;
308 break;
310 case DESC_TEXT_START:{
311 if (bDisplayName) {
312 sLID = rtl::OString("dispname");
313 bText = sal_True;
314 sCurrentText = "";
315 sCurrentOpenTag = rToken;
316 Output( rToken );
319 break;
321 case DESC_TEXT_END: {
322 if (bDisplayName) {
323 sCurrentCloseTag = rToken;
324 sResourceType = rtl::OString ( "description" );
325 sLangAttribute = rtl::OString ( "lang" );
326 WorkOnText( sCurrentOpenTag, sCurrentText );
327 Output( sCurrentText );
328 EndOfText( sCurrentOpenTag, sCurrentCloseTag );
329 bText = sal_False;
330 rToken = rtl::OString("");
331 sCurrentText = rtl::OString("");
334 break;
336 case DESC_EXTENSION_DESCRIPTION_START: {
337 bExtensionDescription = sal_True;
339 break;
341 case DESC_EXTENSION_DESCRIPTION_END: {
342 bExtensionDescription = sal_False;
344 break;
346 case DESC_EXTENSION_DESCRIPTION_SRC: {
347 if (bExtensionDescription) {
348 sLID = rtl::OString("extdesc");
349 sResourceType = rtl::OString ( "description" );
350 sLangAttribute = rtl::OString ( "lang" );
351 sCurrentOpenTag = rToken;
352 sCurrentText = rtl::OString("");
353 Output( rToken );
354 WorkOnDesc( sCurrentOpenTag, sCurrentText );
355 sCurrentCloseTag = rToken;
356 Output( sCurrentText );
357 rToken = rtl::OString("");
358 sCurrentText = rtl::OString("");
361 break;
363 default:
364 if ( bText ) {
365 sCurrentText += rToken;
367 break;
370 if ( !bText )
372 Output( rToken );
374 return 0;
377 /*****************************************************************************/
378 rtl::OString XRMResParser::GetAttribute( const rtl::OString &rToken, const rtl::OString &rAttribute )
379 /*****************************************************************************/
381 rtl::OString sTmp( rToken );
382 sTmp = sTmp.replace('\t', ' ');
384 rtl::OString sSearch( " " );
385 sSearch += rAttribute;
386 sSearch += "=";
387 sal_Int32 nPos = sTmp.indexOf( sSearch );
389 if ( nPos != -1 )
391 sTmp = sTmp.copy( nPos );
392 rtl::OString sId = sTmp.getToken(1, '"');
393 return sId;
395 return rtl::OString();
399 /*****************************************************************************/
400 void XRMResParser::Error( const rtl::OString &rError )
401 /*****************************************************************************/
403 yyerror(( char * ) rError.getStr());
406 /*****************************************************************************/
407 void XRMResParser::ConvertStringToDBFormat( rtl::OString &rString )
408 /*****************************************************************************/
410 rString = rString.trim().replaceAll("\t", "\\t");
413 /*****************************************************************************/
414 void XRMResParser::ConvertStringToXMLFormat( rtl::OString &rString )
415 /*****************************************************************************/
417 rString = rString.replaceAll("\\t", "\t");
423 // class XRMResOutputParser
426 /*****************************************************************************/
427 XRMResOutputParser::XRMResOutputParser ( const rtl::OString &rOutputFile )
428 /*****************************************************************************/
430 aLanguages = Export::GetLanguages();
431 pOutputStream.open(
432 rOutputFile.getStr(), std::ios_base::out | std::ios_base::trunc);
433 if (!pOutputStream.is_open()) {
434 rtl::OString sError( "Unable to open output file: " );
435 sError += rOutputFile;
436 Error( sError );
440 /*****************************************************************************/
441 XRMResOutputParser::~XRMResOutputParser()
442 /*****************************************************************************/
444 pOutputStream.close();
448 // class XMLResExport
451 /*****************************************************************************/
452 XRMResExport::XRMResExport(
453 const rtl::OString &rOutputFile, const rtl::OString &rProject,
454 const rtl::OString &rFilePath )
455 /*****************************************************************************/
456 : XRMResOutputParser( rOutputFile ),
457 pResData( NULL ),
458 sPrj( rProject ),
459 sPath( rFilePath )
461 aLanguages = Export::GetLanguages();
464 /*****************************************************************************/
465 XRMResExport::~XRMResExport()
466 /*****************************************************************************/
468 delete pResData;
471 void XRMResExport::Output( const rtl::OString& ) {}
473 /*****************************************************************************/
474 void XRMResExport::WorkOnDesc(
475 const rtl::OString &rOpenTag,
476 rtl::OString &rText
478 /*****************************************************************************/
480 rtl::OString sDescFileName(
481 sInputFileName.replaceAll("description.xml", rtl::OString()));
482 sDescFileName += GetAttribute( rOpenTag, "xlink:href" );
483 int size;
484 char * memblock;
485 ifstream file (sDescFileName.getStr(), ios::in|ios::binary|ios::ate);
486 if (file.is_open()) {
487 size = static_cast<int>(file.tellg());
488 memblock = new char [size+1];
489 file.seekg (0, ios::beg);
490 file.read (memblock, size);
491 file.close();
492 memblock[size] = '\0';
493 rText = rtl::OString(memblock).replaceAll("\n", "\\n");
494 delete[] memblock;
496 WorkOnText( rOpenTag, rText );
497 EndOfText( rOpenTag, rOpenTag );
500 //*****************************************************************************/
501 void XRMResExport::WorkOnText(
502 const rtl::OString &rOpenTag,
503 rtl::OString &rText
505 /*****************************************************************************/
507 rtl::OString sLang( GetAttribute( rOpenTag, sLangAttribute ));
509 if ( !pResData )
511 rtl::OString sPlatform( "" );
512 pResData = new ResData( sPlatform, GetGID() );
513 pResData->sId = GetLID();
516 rtl::OString sText(rText);
517 ConvertStringToDBFormat(sText);
518 pResData->sText[sLang] = sText;
521 /*****************************************************************************/
522 void XRMResExport::EndOfText(
523 const rtl::OString &,
524 const rtl::OString &
526 /*****************************************************************************/
528 if ( pResData )
530 rtl::OString sCur;
531 for( unsigned int n = 0; n < aLanguages.size(); n++ )
533 sCur = aLanguages[ n ];
535 rtl::OString sAct(
536 pResData->sText[sCur].replaceAll("\x0A", rtl::OString()));
538 rtl::OString sOutput( sPrj ); sOutput += "\t";
539 sOutput += sPath;
540 sOutput += "\t0\t";
541 sOutput += sResourceType;
542 sOutput += "\t";
543 sOutput += pResData->sId;
544 // USE LID AS GID OR MERGE DON'T WORK
545 //sOutput += pResData->sGId;
546 sOutput += "\t";
547 sOutput += pResData->sId;
548 sOutput += "\t\t\t0\t";
549 sOutput += sCur;
550 sOutput += "\t";
552 sOutput += sAct;
553 sOutput += "\t\t\t\t";
555 sOutput = sOutput.replace('\0', '_');
556 if( sAct.getLength() > 1 )
557 pOutputStream << sOutput.getStr() << '\n';
560 delete pResData;
561 pResData = NULL;
565 // class XRMResMerge
568 /*****************************************************************************/
569 XRMResMerge::XRMResMerge(
570 const rtl::OString &rMergeSource, const rtl::OString &rOutputFile,
571 const rtl::OString &rFilename)
572 /*****************************************************************************/
573 : XRMResOutputParser( rOutputFile ),
574 pMergeDataFile( NULL ),
575 sFilename( rFilename ) ,
576 pResData( NULL )
578 if (!rMergeSource.isEmpty())
579 pMergeDataFile = new MergeDataFile(
580 rMergeSource, sInputFileName, bErrorLog);
581 if( Export::sLanguages.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ALL")))
583 Export::SetLanguages( pMergeDataFile->GetLanguages() );
584 aLanguages = pMergeDataFile->GetLanguages();
586 else
587 aLanguages = Export::GetLanguages();
590 /*****************************************************************************/
591 XRMResMerge::~XRMResMerge()
592 /*****************************************************************************/
594 delete pMergeDataFile;
595 delete pResData;
598 /*****************************************************************************/
599 void XRMResMerge::WorkOnDesc(
600 const rtl::OString &rOpenTag,
601 rtl::OString &rText
603 /*****************************************************************************/
605 WorkOnText( rOpenTag, rText);
606 if ( pMergeDataFile && pResData ) {
607 PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
608 if ( pEntrys ) {
609 rtl::OString sCur;
610 rtl::OString sDescFilename = GetAttribute ( rOpenTag, "xlink:href" );
611 for( unsigned int n = 0; n < aLanguages.size(); n++ ){
612 sCur = aLanguages[ n ];
613 rtl::OString sContent;
614 if ( !sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) &&
615 ( pEntrys->GetText(
616 sContent, STRING_TYP_TEXT, sCur, sal_True )) &&
617 ( sContent != "-" ) && !sContent.isEmpty())
619 rtl::OString sText( sContent );
620 rtl::OString sAdditionalLine( "\n " );
621 sAdditionalLine += rOpenTag;
622 rtl::OString sSearch = sLangAttribute;
623 sSearch += "=\"";
624 rtl::OString sReplace( sSearch );
626 sSearch += GetAttribute( rOpenTag, sLangAttribute );
627 sReplace += sCur;
628 sAdditionalLine = sAdditionalLine.replaceFirst(
629 sSearch, sReplace);
631 sSearch = rtl::OString("xlink:href=\"");
632 sReplace = sSearch;
634 rtl::OString sLocDescFilename = sDescFilename;
635 sLocDescFilename = sLocDescFilename.replaceFirst(
636 "en-US", sCur);
638 sSearch += sDescFilename;
639 sReplace += sLocDescFilename;
640 sAdditionalLine = sAdditionalLine.replaceFirst(
641 sSearch, sReplace);
643 Output( sAdditionalLine );
645 sal_Int32 i = sOutputFile.lastIndexOf('/');
646 if (i == -1) {
647 std::cerr
648 << "Error: output file " << sOutputFile.getStr()
649 << " does not contain any /\n";
650 throw false; //TODO
652 rtl::OString sOutputDescFile(
653 sOutputFile.copy(0, i + 1) + sLocDescFilename);
654 sText = sText.replaceAll("\\n", "\n");
655 ofstream file(sOutputDescFile.getStr());
656 if (file.is_open()) {
657 file << sText.getStr();
658 file.close();
659 } else {
660 std::cerr
661 << "Error: cannot write "
662 << sOutputDescFile.getStr() << '\n';
663 throw false; //TODO
669 delete pResData;
670 pResData = NULL;
673 /*****************************************************************************/
674 void XRMResMerge::WorkOnText(
675 const rtl::OString &rOpenTag,
676 rtl::OString &rText
678 /*****************************************************************************/
680 rtl::OString sLang( GetAttribute( rOpenTag, sLangAttribute ));
682 if ( pMergeDataFile ) {
683 if ( !pResData ) {
684 rtl::OString sPlatform( "" );
685 pResData = new ResData( sPlatform, GetLID() , sFilename );
686 pResData->sId = GetLID();
687 pResData->sResTyp = sResourceType;
690 PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
691 if ( pEntrys ) {
692 rtl::OString sContent;
693 if ( Export::isAllowed( sLang ) &&
694 ( pEntrys->GetText(
695 sContent, STRING_TYP_TEXT, sLang )) &&
696 ( sContent != "-" ) && !sContent.isEmpty())
699 rText = sContent;
700 ConvertStringToXMLFormat( rText );
706 /*****************************************************************************/
707 void XRMResMerge::Output( const rtl::OString& rOutput )
708 /*****************************************************************************/
710 if (!rOutput.isEmpty())
711 pOutputStream << rOutput.getStr();
714 /*****************************************************************************/
715 void XRMResMerge::EndOfText(
716 const rtl::OString &rOpenTag,
717 const rtl::OString &rCloseTag
719 /*****************************************************************************/
722 Output( rCloseTag );
723 if ( pMergeDataFile && pResData ) {
724 PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
725 if ( pEntrys ) {
726 rtl::OString sCur;
727 for( unsigned int n = 0; n < aLanguages.size(); n++ ){
728 sCur = aLanguages[ n ];
729 rtl::OString sContent;
730 if (!sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) &&
731 ( pEntrys->GetText(
732 sContent, STRING_TYP_TEXT, sCur, sal_True )) &&
733 ( sContent != "-" ) && !sContent.isEmpty())
735 rtl::OString sText( sContent );
736 rtl::OString sAdditionalLine( "\n " );
737 sAdditionalLine += rOpenTag;
738 rtl::OString sSearch = sLangAttribute;
739 sSearch += "=\"";
740 rtl::OString sReplace( sSearch );
742 sSearch += GetAttribute( rOpenTag, sLangAttribute );
743 sReplace += sCur;
745 sAdditionalLine = sAdditionalLine.replaceFirst(
746 sSearch, sReplace);
748 sAdditionalLine += sText;
749 sAdditionalLine += rCloseTag;
751 Output( sAdditionalLine );
756 delete pResData;
757 pResData = NULL;
760 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */