1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
28 #include "lngmerge.hxx"
32 OString
getBracketedContent(const OString
& text
) {
33 return text
.getToken(1, '[').getToken(0, ']');
36 static void lcl_RemoveUTF8ByteOrderMarker( OString
&rString
)
38 if( rString
.getLength() >= 3 && rString
[0] == '\xEF' &&
39 rString
[1] == '\xBB' && rString
[2] == '\xBF' )
41 rString
= rString
.copy(3);
50 LngParser::LngParser(const OString
&rLngFile
)
55 pLines
= new LngLineList();
56 std::ifstream
aStream(sSource
.getStr());
57 if (aStream
.is_open())
59 bool bFirstLine
= true;
61 std::getline(aStream
, s
);
62 while (!aStream
.eof())
64 OString
sLine(s
.data(), s
.length());
68 // Always remove UTF8 BOM from the first line
69 lcl_RemoveUTF8ByteOrderMarker( sLine
);
73 pLines
->push_back( new OString(sLine
) );
74 std::getline(aStream
, s
);
76 pLines
->push_back( new OString() );
79 nError
= LNG_COULD_NOT_OPEN
;
82 LngParser::~LngParser()
84 for ( size_t i
= 0, n
= pLines
->size(); i
< n
; ++i
)
85 delete (*pLines
)[ i
];
90 bool LngParser::CreatePO( const OString
&rPOFile
)
92 PoOfstream
aPOStream( rPOFile
, PoOfstream::APP
);
93 if (!aPOStream
.isOpen()) {
94 std::cerr
<< "Ulfex error: Can't open po file:" << rPOFile
.getStr() << "\n";
99 OString sGroup
, sLine
;
103 while( nPos
< pLines
->size() ) {
104 sLine
= *(*pLines
)[ nPos
++ ];
105 while( nPos
< pLines
->size() && !isNextGroup( sGroup
, sLine
) ) {
106 ReadLine( sLine
, Text
);
108 sLine
= *(*pLines
)[ nPos
++ ];
115 WritePO( aPOStream
, Text
, sSource
, sID
);
117 Text
.erase("x-comment");
123 void LngParser::WritePO(PoOfstream
&aPOStream
,
124 OStringHashMap
&rText_inout
, const OString
&rActFileName
,
131 common::writePoEntry(
132 "Ulfex", aPOStream
, rActFileName
, "LngText",
133 rID
, OString(), rText_inout
.count("x-comment") ? rText_inout
["x-comment"] : OString(), rText_inout
["en-US"]);
137 bool LngParser::isNextGroup(OString
&sGroup_out
, const OString
&sLine_in
)
139 const OString sLineTrim
= sLine_in
.trim();
140 if (sLineTrim
.startsWith("[") && sLineTrim
.endsWith("]"))
142 sGroup_out
= getBracketedContent(sLineTrim
).trim();
148 void LngParser::ReadLine(const OString
&rLine_in
,
149 OStringHashMap
&rText_inout
)
151 if (!rLine_in
.match(" *") && !rLine_in
.match("/*"))
153 OString
sLang(rLine_in
.getToken(0, '=').trim());
154 if (!sLang
.isEmpty()) {
155 OString
sText(rLine_in
.getToken(1, '"'));
156 rText_inout
[sLang
] = sText
;
161 bool LngParser::Merge(
162 const OString
&rPOFile
,
163 const OString
&rDestinationFile
,
164 const OString
&rLanguage
)
166 std::ofstream
aDestination(
167 rDestinationFile
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
168 if (!aDestination
.is_open()) {
169 nError
= LNG_COULD_NOT_OPEN
;
173 MergeDataFile
aMergeDataFile( rPOFile
, sSource
, false, true );
174 if( rLanguage
.equalsIgnoreAsciiCase("ALL") )
175 aLanguages
= aMergeDataFile
.GetLanguages();
181 // seek to next group
182 while ( nPos
< pLines
->size() && !bGroup
)
184 OString
sLine( *(*pLines
)[ nPos
] );
185 sLine
= sLine
.trim();
186 if ( sLine
.startsWith("[") && sLine
.endsWith("]") )
188 sGroup
= getBracketedContent(sLine
).trim();
194 while ( nPos
< pLines
->size()) {
196 OString
sID( sGroup
);
197 std::size_t nLastLangPos
= 0;
199 ResData
*pResData
= new ResData( sID
, sSource
);
200 pResData
->sResTyp
= "LngText";
201 MergeEntrys
*pEntrys
= aMergeDataFile
.GetMergeEntrys( pResData
);
205 OString sLanguagesDone
;
207 while ( nPos
< pLines
->size() && !bGroup
)
209 OString
sLine( *(*pLines
)[ nPos
] );
210 sLine
= sLine
.trim();
211 if ( sLine
.startsWith("[") && sLine
.endsWith("]") )
213 sGroup
= getBracketedContent(sLine
).trim();
221 OString
sLang(sLine
.getToken(0, '=', n
));
222 if (n
== -1 || static_cast<bool>(sLine
.match("/*")))
228 sLang
= sLang
.trim();
230 OString
sSearch( ";" );
234 if (( sLanguagesDone
.indexOf( sSearch
) != -1 )) {
235 LngLineList::iterator it
= pLines
->begin();
236 std::advance( it
, nPos
);
241 if( !sLang
.isEmpty() )
244 pEntrys
->GetText( sNewText
, STRING_TYP_TEXT
, sLang
, true );
248 if ( !sNewText
.isEmpty()) {
249 OString
*pLine
= (*pLines
)[ nPos
];
251 OString
sText1( sLang
);
253 // escape quotes, unescape double escaped quotes fdo#56648
254 sText1
+= sNewText
.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
257 Text
[ sLang
] = sNewText
;
262 sLanguagesDone
+= sSearch
;
267 sLanguagesDone
+= sSearch
;
275 for(size_t n
= 0; n
< aLanguages
.size(); ++n
)
277 sCur
= aLanguages
[ n
];
278 if( !sCur
.equalsIgnoreAsciiCase("en-US") && Text
[sCur
].isEmpty() && pEntrys
)
282 pEntrys
->GetText( sNewText
, STRING_TYP_TEXT
, sCur
, true );
285 if ( !sNewText
.isEmpty() && sCur
!= "x-comment")
290 // escape quotes, unescape double escaped quotes fdo#56648
291 sLine
+= sNewText
.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
297 if ( nLastLangPos
< pLines
->size() ) {
298 LngLineList::iterator it
= pLines
->begin();
299 std::advance( it
, nLastLangPos
);
300 pLines
->insert( it
, new OString(sLine
) );
302 pLines
->push_back( new OString(sLine
) );
312 for ( size_t i
= 0; i
< pLines
->size(); ++i
)
313 aDestination
<< (*pLines
)[i
]->getStr() << '\n';
315 aDestination
.close();
319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */