Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <cstring>
23 :
24 : #include <stdio.h>
25 :
26 : #include "common.hxx"
27 : #include "export.hxx"
28 : #include "xrmmerge.hxx"
29 : #include "tokens.h"
30 : #include "helper.hxx"
31 : #include <iostream>
32 : #include <fstream>
33 : #include <vector>
34 :
35 : using namespace std;
36 :
37 : void yyerror( const char * );
38 : void YYWarning( const char * );
39 :
40 : // set of global variables
41 : bool bMergeMode;
42 : sal_Bool bDisplayName;
43 : sal_Bool bExtensionDescription;
44 0 : rtl::OString sPrj;
45 0 : rtl::OString sPrjRoot;
46 0 : rtl::OString sInputFileName;
47 0 : rtl::OString sActFileName;
48 0 : rtl::OString sOutputFile;
49 0 : rtl::OString sMergeSrc;
50 0 : rtl::OString sLangAttribute;
51 0 : rtl::OString sResourceType;
52 : XRMResParser *pParser = NULL;
53 :
54 : extern "C" {
55 : // the whole interface to lexer is in this extern "C" section
56 :
57 : /*****************************************************************************/
58 0 : extern char *GetOutputFile( int argc, char* argv[])
59 : /*****************************************************************************/
60 : {
61 0 : bDisplayName = sal_False;
62 0 : bExtensionDescription = sal_False;
63 0 : sActFileName = "";
64 :
65 0 : HandledArgs aArgs;
66 0 : if ( Export::handleArguments(argc, argv, aArgs) )
67 : {
68 : // command line is valid
69 0 : bMergeMode = aArgs.m_bMergeMode;
70 0 : sPrj = aArgs.m_sPrj;
71 0 : sPrjRoot = aArgs.m_sPrjRoot;
72 0 : sInputFileName = aArgs.m_sInputFile;
73 0 : sOutputFile = aArgs.m_sOutputFile;
74 0 : sMergeSrc = aArgs.m_sMergeSrc;
75 0 : char *pReturn = new char[ sOutputFile.getLength() + 1 ];
76 0 : std::strcpy( pReturn, sOutputFile.getStr());
77 0 : return pReturn;
78 : }
79 : else
80 : {
81 : // command line is not valid
82 0 : Export::writeUsage("xrmex","xrm/xml");
83 0 : return NULL;
84 0 : }
85 : }
86 :
87 : /*****************************************************************************/
88 0 : int InitXrmExport( char *pOutput , char* pFilename)
89 : /*****************************************************************************/
90 : {
91 : // instanciate Export
92 0 : rtl::OString sOutput( pOutput );
93 0 : rtl::OString sFilename( pFilename );
94 0 : Export::InitLanguages( false );
95 :
96 0 : if ( bMergeMode )
97 0 : pParser = new XRMResMerge( sMergeSrc, sOutputFile, sFilename );
98 0 : else if (!sOutputFile.isEmpty()) {
99 0 : pParser = new XRMResExport( sOutputFile, sPrj, sActFileName );
100 : }
101 :
102 0 : return 1;
103 : }
104 :
105 : /*****************************************************************************/
106 0 : int EndXrmExport()
107 : /*****************************************************************************/
108 : {
109 0 : delete pParser;
110 0 : return 1;
111 : }
112 0 : extern const char* getFilename()
113 : {
114 0 : return sInputFileName.getStr();
115 : }
116 : /*****************************************************************************/
117 0 : extern FILE *GetXrmFile()
118 : /*****************************************************************************/
119 : {
120 : // look for valid filename
121 0 : if (!sInputFileName.isEmpty()) {
122 : //TODO: explicit BOM handling?
123 0 : FILE * pFile = fopen(sInputFileName.getStr(), "r");
124 0 : if ( !pFile ){
125 : fprintf( stderr, "Error: Could not open file %s\n",
126 0 : sInputFileName.getStr());
127 : }
128 : else {
129 0 : if (!bMergeMode) {
130 : sActFileName = common::pathnameToken(
131 0 : sInputFileName.getStr(), sPrjRoot.getStr());
132 : }
133 0 : return pFile;
134 : }
135 : }
136 : // this means the file could not be opened
137 0 : return NULL;
138 : }
139 :
140 : /*****************************************************************************/
141 0 : int WorkOnTokenSet( int nTyp, char *pTokenText )
142 : /*****************************************************************************/
143 : {
144 : //printf("Typ = %d , text = '%s'\n",nTyp , pTokenText );
145 0 : pParser->Execute( nTyp, pTokenText );
146 :
147 0 : return 1;
148 : }
149 :
150 : /*****************************************************************************/
151 0 : int SetError()
152 : /*****************************************************************************/
153 : {
154 0 : pParser->SetError();
155 0 : return 1;
156 : }
157 : }
158 :
159 : extern "C" {
160 : /*****************************************************************************/
161 0 : int GetError()
162 : /*****************************************************************************/
163 : {
164 0 : return pParser->GetError();
165 : }
166 : }
167 :
168 : //
169 : // class XRMResParser
170 : //
171 :
172 :
173 : /*****************************************************************************/
174 0 : XRMResParser::XRMResParser()
175 : /*****************************************************************************/
176 : : bError( sal_False ),
177 0 : bText( sal_False )
178 : {
179 0 : aLanguages = Export::GetLanguages();
180 0 : }
181 :
182 : /*****************************************************************************/
183 0 : XRMResParser::~XRMResParser()
184 : /*****************************************************************************/
185 : {
186 0 : }
187 :
188 : /*****************************************************************************/
189 0 : int XRMResParser::Execute( int nToken, char * pToken )
190 : /*****************************************************************************/
191 : {
192 0 : rtl::OString rToken( pToken );
193 :
194 0 : switch ( nToken ) {
195 : case XRM_TEXT_START:{
196 0 : rtl::OString sNewGID = GetAttribute( rToken, "id" );
197 0 : if ( sNewGID != sGID ) {
198 0 : sGID = sNewGID;
199 : }
200 0 : bText = sal_True;
201 0 : sCurrentText = "";
202 0 : sCurrentOpenTag = rToken;
203 0 : Output( rToken );
204 : }
205 0 : break;
206 :
207 : case XRM_TEXT_END: {
208 0 : sCurrentCloseTag = rToken;
209 0 : sResourceType = rtl::OString ( "readmeitem" );
210 0 : sLangAttribute = rtl::OString ( "xml:lang" );
211 0 : WorkOnText( sCurrentOpenTag, sCurrentText );
212 0 : Output( sCurrentText );
213 0 : EndOfText( sCurrentOpenTag, sCurrentCloseTag );
214 0 : bText = sal_False;
215 0 : rToken = rtl::OString("");
216 0 : sCurrentText = rtl::OString("");
217 : }
218 0 : break;
219 :
220 : case DESC_DISPLAY_NAME_START:{
221 0 : bDisplayName = sal_True;
222 : }
223 0 : break;
224 :
225 : case DESC_DISPLAY_NAME_END:{
226 0 : bDisplayName = sal_False;
227 : }
228 0 : break;
229 :
230 : case DESC_TEXT_START:{
231 0 : if (bDisplayName) {
232 0 : sGID = rtl::OString("dispname");
233 0 : bText = sal_True;
234 0 : sCurrentText = "";
235 0 : sCurrentOpenTag = rToken;
236 0 : Output( rToken );
237 : }
238 : }
239 0 : break;
240 :
241 : case DESC_TEXT_END: {
242 0 : if (bDisplayName) {
243 0 : sCurrentCloseTag = rToken;
244 0 : sResourceType = rtl::OString ( "description" );
245 0 : sLangAttribute = rtl::OString ( "lang" );
246 0 : WorkOnText( sCurrentOpenTag, sCurrentText );
247 0 : Output( sCurrentText );
248 0 : EndOfText( sCurrentOpenTag, sCurrentCloseTag );
249 0 : bText = sal_False;
250 0 : rToken = rtl::OString("");
251 0 : sCurrentText = rtl::OString("");
252 : }
253 : }
254 0 : break;
255 :
256 : case DESC_EXTENSION_DESCRIPTION_START: {
257 0 : bExtensionDescription = sal_True;
258 : }
259 0 : break;
260 :
261 : case DESC_EXTENSION_DESCRIPTION_END: {
262 0 : bExtensionDescription = sal_False;
263 : }
264 0 : break;
265 :
266 : case DESC_EXTENSION_DESCRIPTION_SRC: {
267 0 : if (bExtensionDescription) {
268 0 : sGID = rtl::OString("extdesc");
269 0 : sResourceType = rtl::OString ( "description" );
270 0 : sLangAttribute = rtl::OString ( "lang" );
271 0 : sCurrentOpenTag = rToken;
272 0 : sCurrentText = rtl::OString("");
273 0 : Output( rToken );
274 0 : WorkOnDesc( sCurrentOpenTag, sCurrentText );
275 0 : sCurrentCloseTag = rToken;
276 0 : Output( sCurrentText );
277 0 : rToken = rtl::OString("");
278 0 : sCurrentText = rtl::OString("");
279 : }
280 : }
281 0 : break;
282 :
283 : default:
284 0 : if ( bText ) {
285 0 : sCurrentText += rToken;
286 : }
287 0 : break;
288 : }
289 :
290 0 : if ( !bText )
291 : {
292 0 : Output( rToken );
293 : }
294 0 : return 0;
295 : }
296 :
297 : /*****************************************************************************/
298 0 : rtl::OString XRMResParser::GetAttribute( const rtl::OString &rToken, const rtl::OString &rAttribute )
299 : /*****************************************************************************/
300 : {
301 0 : rtl::OString sTmp( rToken );
302 0 : sTmp = sTmp.replace('\t', ' ');
303 :
304 0 : rtl::OString sSearch( " " );
305 0 : sSearch += rAttribute;
306 0 : sSearch += "=";
307 0 : sal_Int32 nPos = sTmp.indexOf( sSearch );
308 :
309 0 : if ( nPos != -1 )
310 : {
311 0 : sTmp = sTmp.copy( nPos );
312 0 : rtl::OString sId = sTmp.getToken(1, '"');
313 0 : return sId;
314 : }
315 0 : return rtl::OString();
316 : }
317 :
318 :
319 : /*****************************************************************************/
320 0 : void XRMResParser::Error( const rtl::OString &rError )
321 : /*****************************************************************************/
322 : {
323 0 : yyerror(( char * ) rError.getStr());
324 0 : }
325 :
326 : /*****************************************************************************/
327 0 : void XRMResParser::ConvertStringToDBFormat( rtl::OString &rString )
328 : /*****************************************************************************/
329 : {
330 0 : rString = rString.trim().replaceAll("\t", "\\t");
331 0 : }
332 :
333 : /*****************************************************************************/
334 0 : void XRMResParser::ConvertStringToXMLFormat( rtl::OString &rString )
335 : /*****************************************************************************/
336 : {
337 0 : rString = rString.replaceAll("\\t", "\t");
338 0 : }
339 :
340 :
341 :
342 : //
343 : // class XRMResOutputParser
344 : //
345 :
346 : /*****************************************************************************/
347 0 : XRMResOutputParser::XRMResOutputParser ( const rtl::OString &rOutputFile )
348 : /*****************************************************************************/
349 : {
350 0 : aLanguages = Export::GetLanguages();
351 : pOutputStream.open(
352 0 : rOutputFile.getStr(), std::ios_base::out | std::ios_base::trunc);
353 0 : if (!pOutputStream.is_open()) {
354 0 : rtl::OString sError( "Unable to open output file: " );
355 0 : sError += rOutputFile;
356 0 : Error( sError );
357 : }
358 0 : }
359 :
360 : /*****************************************************************************/
361 0 : XRMResOutputParser::~XRMResOutputParser()
362 : /*****************************************************************************/
363 : {
364 0 : pOutputStream.close();
365 0 : }
366 :
367 : //
368 : // class XMLResExport
369 : //
370 :
371 : /*****************************************************************************/
372 0 : XRMResExport::XRMResExport(
373 : const rtl::OString &rOutputFile, const rtl::OString &rProject,
374 : const rtl::OString &rFilePath )
375 : /*****************************************************************************/
376 : : XRMResOutputParser( rOutputFile ),
377 : pResData( NULL ),
378 : sPrj( rProject ),
379 0 : sPath( rFilePath )
380 : {
381 0 : aLanguages = Export::GetLanguages();
382 0 : }
383 :
384 : /*****************************************************************************/
385 0 : XRMResExport::~XRMResExport()
386 : /*****************************************************************************/
387 : {
388 0 : delete pResData;
389 0 : }
390 :
391 0 : void XRMResExport::Output( const rtl::OString& ) {}
392 :
393 : /*****************************************************************************/
394 0 : void XRMResExport::WorkOnDesc(
395 : const rtl::OString &rOpenTag,
396 : rtl::OString &rText
397 : )
398 : /*****************************************************************************/
399 : {
400 : rtl::OString sDescFileName(
401 0 : sInputFileName.replaceAll("description.xml", rtl::OString()));
402 0 : sDescFileName += GetAttribute( rOpenTag, "xlink:href" );
403 : int size;
404 : char * memblock;
405 0 : ifstream file (sDescFileName.getStr(), ios::in|ios::binary|ios::ate);
406 0 : if (file.is_open()) {
407 0 : size = static_cast<int>(file.tellg());
408 0 : memblock = new char [size+1];
409 0 : file.seekg (0, ios::beg);
410 0 : file.read (memblock, size);
411 0 : file.close();
412 0 : memblock[size] = '\0';
413 0 : rText = rtl::OString(memblock).replaceAll("\n", "\\n");
414 0 : delete[] memblock;
415 : }
416 0 : WorkOnText( rOpenTag, rText );
417 0 : EndOfText( rOpenTag, rOpenTag );
418 0 : }
419 :
420 : //*****************************************************************************/
421 0 : void XRMResExport::WorkOnText(
422 : const rtl::OString &rOpenTag,
423 : rtl::OString &rText
424 : )
425 : /*****************************************************************************/
426 : {
427 0 : rtl::OString sLang( GetAttribute( rOpenTag, sLangAttribute ));
428 :
429 0 : if ( !pResData )
430 : {
431 0 : rtl::OString sPlatform( "" );
432 0 : pResData = new ResData( sPlatform, GetGID() );
433 : }
434 :
435 0 : rtl::OString sText(rText);
436 0 : ConvertStringToDBFormat(sText);
437 0 : pResData->sText[sLang] = sText;
438 0 : }
439 :
440 : /*****************************************************************************/
441 0 : void XRMResExport::EndOfText(
442 : const rtl::OString &,
443 : const rtl::OString &
444 : )
445 : /*****************************************************************************/
446 : {
447 0 : if ( pResData )
448 : {
449 0 : rtl::OString sCur;
450 0 : for( unsigned int n = 0; n < aLanguages.size(); n++ )
451 : {
452 0 : sCur = aLanguages[ n ];
453 :
454 : rtl::OString sAct(
455 0 : pResData->sText[sCur].replaceAll("\x0A", rtl::OString()));
456 :
457 0 : rtl::OString sOutput( sPrj ); sOutput += "\t";
458 0 : sOutput += sPath;
459 0 : sOutput += "\t0\t";
460 0 : sOutput += sResourceType;
461 0 : sOutput += "\t";
462 0 : sOutput += pResData->sGId;
463 0 : sOutput += "\t\t\t\t0\t";
464 0 : sOutput += sCur;
465 0 : sOutput += "\t";
466 :
467 0 : sOutput += sAct;
468 0 : sOutput += "\t\t\t\t";
469 :
470 0 : sOutput = sOutput.replace('\0', '_');
471 0 : if( sAct.getLength() > 1 )
472 0 : pOutputStream << sOutput.getStr() << '\n';
473 0 : }
474 : }
475 0 : delete pResData;
476 0 : pResData = NULL;
477 0 : }
478 :
479 : //
480 : // class XRMResMerge
481 : //
482 :
483 : /*****************************************************************************/
484 0 : XRMResMerge::XRMResMerge(
485 : const rtl::OString &rMergeSource, const rtl::OString &rOutputFile,
486 : const rtl::OString &rFilename)
487 : /*****************************************************************************/
488 : : XRMResOutputParser( rOutputFile ),
489 : pMergeDataFile( NULL ),
490 : sFilename( rFilename ) ,
491 0 : pResData( NULL )
492 : {
493 0 : if (!rMergeSource.isEmpty())
494 : pMergeDataFile = new MergeDataFile(
495 0 : rMergeSource, sInputFileName, false);
496 0 : if( Export::sLanguages.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("ALL")))
497 : {
498 0 : Export::SetLanguages( pMergeDataFile->GetLanguages() );
499 0 : aLanguages = pMergeDataFile->GetLanguages();
500 : }
501 : else
502 0 : aLanguages = Export::GetLanguages();
503 0 : }
504 :
505 : /*****************************************************************************/
506 0 : XRMResMerge::~XRMResMerge()
507 : /*****************************************************************************/
508 : {
509 0 : delete pMergeDataFile;
510 0 : delete pResData;
511 0 : }
512 :
513 : /*****************************************************************************/
514 0 : void XRMResMerge::WorkOnDesc(
515 : const rtl::OString &rOpenTag,
516 : rtl::OString &rText
517 : )
518 : /*****************************************************************************/
519 : {
520 0 : WorkOnText( rOpenTag, rText);
521 0 : if ( pMergeDataFile && pResData ) {
522 0 : PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
523 0 : if ( pEntrys ) {
524 0 : rtl::OString sCur;
525 0 : rtl::OString sDescFilename = GetAttribute ( rOpenTag, "xlink:href" );
526 0 : for( unsigned int n = 0; n < aLanguages.size(); n++ ){
527 0 : sCur = aLanguages[ n ];
528 0 : rtl::OString sContent;
529 0 : if ( !sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) &&
530 : ( pEntrys->GetText(
531 0 : sContent, STRING_TYP_TEXT, sCur, sal_True )) &&
532 0 : ( sContent != "-" ) && !sContent.isEmpty())
533 : {
534 0 : rtl::OString sText( sContent );
535 0 : rtl::OString sAdditionalLine( "\n " );
536 0 : sAdditionalLine += rOpenTag;
537 0 : rtl::OString sSearch = sLangAttribute;
538 0 : sSearch += "=\"";
539 0 : rtl::OString sReplace( sSearch );
540 :
541 0 : sSearch += GetAttribute( rOpenTag, sLangAttribute );
542 0 : sReplace += sCur;
543 : sAdditionalLine = sAdditionalLine.replaceFirst(
544 0 : sSearch, sReplace);
545 :
546 0 : sSearch = rtl::OString("xlink:href=\"");
547 0 : sReplace = sSearch;
548 :
549 0 : rtl::OString sLocDescFilename = sDescFilename;
550 : sLocDescFilename = sLocDescFilename.replaceFirst(
551 0 : "en-US", sCur);
552 :
553 0 : sSearch += sDescFilename;
554 0 : sReplace += sLocDescFilename;
555 : sAdditionalLine = sAdditionalLine.replaceFirst(
556 0 : sSearch, sReplace);
557 :
558 0 : Output( sAdditionalLine );
559 :
560 0 : sal_Int32 i = sOutputFile.lastIndexOf('/');
561 0 : if (i == -1) {
562 : std::cerr
563 0 : << "Error: output file " << sOutputFile.getStr()
564 0 : << " does not contain any /\n";
565 0 : throw false; //TODO
566 : }
567 : rtl::OString sOutputDescFile(
568 0 : sOutputFile.copy(0, i + 1) + sLocDescFilename);
569 0 : sText = sText.replaceAll("\\n", "\n");
570 0 : ofstream file(sOutputDescFile.getStr());
571 0 : if (file.is_open()) {
572 0 : file << sText.getStr();
573 0 : file.close();
574 : } else {
575 : std::cerr
576 0 : << "Error: cannot write "
577 0 : << sOutputDescFile.getStr() << '\n';
578 0 : throw false; //TODO
579 0 : }
580 : }
581 0 : }
582 : }
583 : }
584 0 : delete pResData;
585 0 : pResData = NULL;
586 0 : }
587 :
588 : /*****************************************************************************/
589 0 : void XRMResMerge::WorkOnText(
590 : const rtl::OString &rOpenTag,
591 : rtl::OString &rText
592 : )
593 : /*****************************************************************************/
594 : {
595 0 : rtl::OString sLang( GetAttribute( rOpenTag, sLangAttribute ));
596 :
597 0 : if ( pMergeDataFile ) {
598 0 : if ( !pResData ) {
599 0 : rtl::OString sPlatform( "" );
600 0 : pResData = new ResData( sPlatform, GetGID() , sFilename );
601 0 : pResData->sResTyp = sResourceType;
602 : }
603 :
604 0 : PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
605 0 : if ( pEntrys ) {
606 0 : rtl::OString sContent;
607 0 : if ( Export::isAllowed( sLang ) &&
608 : ( pEntrys->GetText(
609 0 : sContent, STRING_TYP_TEXT, sLang )) &&
610 0 : ( sContent != "-" ) && !sContent.isEmpty() &&
611 0 : helper::isWellFormedXML( sContent ))
612 : {
613 0 : rText = sContent;
614 0 : ConvertStringToXMLFormat( rText );
615 0 : }
616 : }
617 0 : }
618 0 : }
619 :
620 : /*****************************************************************************/
621 0 : void XRMResMerge::Output( const rtl::OString& rOutput )
622 : /*****************************************************************************/
623 : {
624 0 : if (!rOutput.isEmpty())
625 0 : pOutputStream << rOutput.getStr();
626 0 : }
627 :
628 : /*****************************************************************************/
629 0 : void XRMResMerge::EndOfText(
630 : const rtl::OString &rOpenTag,
631 : const rtl::OString &rCloseTag
632 : )
633 : /*****************************************************************************/
634 : {
635 :
636 0 : Output( rCloseTag );
637 0 : if ( pMergeDataFile && pResData ) {
638 0 : PFormEntrys *pEntrys = pMergeDataFile->GetPFormEntrys( pResData );
639 0 : if ( pEntrys ) {
640 0 : rtl::OString sCur;
641 0 : for( unsigned int n = 0; n < aLanguages.size(); n++ ){
642 0 : sCur = aLanguages[ n ];
643 0 : rtl::OString sContent;
644 0 : if (!sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) &&
645 : ( pEntrys->GetText(
646 0 : sContent, STRING_TYP_TEXT, sCur, sal_True )) &&
647 0 : ( sContent != "-" ) && !sContent.isEmpty() &&
648 0 : helper::isWellFormedXML( sContent ))
649 : {
650 0 : rtl::OString sText( sContent );
651 0 : rtl::OString sAdditionalLine( "\n " );
652 0 : sAdditionalLine += rOpenTag;
653 0 : rtl::OString sSearch = sLangAttribute;
654 0 : sSearch += "=\"";
655 0 : rtl::OString sReplace( sSearch );
656 :
657 0 : sSearch += GetAttribute( rOpenTag, sLangAttribute );
658 0 : sReplace += sCur;
659 :
660 : sAdditionalLine = sAdditionalLine.replaceFirst(
661 0 : sSearch, sReplace);
662 :
663 0 : sAdditionalLine += sText;
664 0 : sAdditionalLine += rCloseTag;
665 :
666 0 : Output( sAdditionalLine );
667 : }
668 0 : }
669 : }
670 : }
671 0 : delete pResData;
672 0 : pResData = NULL;
673 0 : }
674 :
675 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|