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 <cstddef>
23 : #include <fstream>
24 : #include <iterator>
25 : #include <string>
26 :
27 : #include "po.hxx"
28 : #include "lngmerge.hxx"
29 :
30 : namespace {
31 :
32 0 : OString getBracketedContent(const OString& text) {
33 0 : return text.getToken(1, '[').getToken(0, ']');
34 : }
35 :
36 0 : static void lcl_RemoveUTF8ByteOrderMarker( OString &rString )
37 : {
38 0 : if( rString.getLength() >= 3 && rString[0] == '\xEF' &&
39 0 : rString[1] == '\xBB' && rString[2] == '\xBF' )
40 : {
41 0 : rString = rString.copy(3);
42 : }
43 0 : }
44 :
45 : }
46 :
47 :
48 : // class LngParser
49 :
50 0 : LngParser::LngParser(const OString &rLngFile)
51 : : nError( LNG_OK )
52 : , pLines( NULL )
53 0 : , sSource( rLngFile )
54 : {
55 0 : pLines = new LngLineList();
56 0 : std::ifstream aStream(sSource.getStr());
57 0 : if (aStream.is_open())
58 : {
59 0 : bool bFirstLine = true;
60 0 : std::string s;
61 0 : std::getline(aStream, s);
62 0 : while (!aStream.eof())
63 : {
64 0 : OString sLine(s.data(), s.length());
65 :
66 0 : if( bFirstLine )
67 : {
68 : // Always remove UTF8 BOM from the first line
69 0 : lcl_RemoveUTF8ByteOrderMarker( sLine );
70 0 : bFirstLine = false;
71 : }
72 :
73 0 : pLines->push_back( new OString(sLine) );
74 0 : std::getline(aStream, s);
75 0 : }
76 0 : pLines->push_back( new OString() );
77 : }
78 : else
79 0 : nError = LNG_COULD_NOT_OPEN;
80 0 : }
81 :
82 0 : LngParser::~LngParser()
83 : {
84 0 : for ( size_t i = 0, n = pLines->size(); i < n; ++i )
85 0 : delete (*pLines)[ i ];
86 0 : pLines->clear();
87 0 : delete pLines;
88 0 : }
89 :
90 0 : bool LngParser::CreatePO( const OString &rPOFile )
91 : {
92 0 : PoOfstream aPOStream( rPOFile, PoOfstream::APP );
93 0 : if (!aPOStream.isOpen()) {
94 0 : std::cerr << "Ulfex error: Can't open po file:" << rPOFile.getStr() << "\n";
95 : }
96 :
97 0 : size_t nPos = 0;
98 0 : bool bStart = true;
99 0 : OString sGroup, sLine;
100 0 : OStringHashMap Text;
101 0 : OString sID;
102 :
103 0 : while( nPos < pLines->size() ) {
104 0 : sLine = *(*pLines)[ nPos++ ];
105 0 : while( nPos < pLines->size() && !isNextGroup( sGroup , sLine ) ) {
106 0 : ReadLine( sLine , Text );
107 0 : sID = sGroup;
108 0 : sLine = *(*pLines)[ nPos++ ];
109 : };
110 0 : if( bStart ) {
111 0 : bStart = false;
112 0 : sID = sGroup;
113 : }
114 : else {
115 0 : WritePO( aPOStream , Text , sSource , sID );
116 : }
117 : }
118 0 : aPOStream.close();
119 0 : return true;
120 : }
121 :
122 0 : void LngParser::WritePO(PoOfstream &aPOStream,
123 : OStringHashMap &rText_inout, const OString &rActFileName,
124 : const OString &rID)
125 : {
126 :
127 0 : bool bExport = true;
128 0 : if ( bExport )
129 : {
130 : common::writePoEntry(
131 : "Ulfex", aPOStream, rActFileName, "LngText",
132 0 : rID, OString(), OString(), rText_inout["en-US"]);
133 : }
134 0 : }
135 :
136 0 : bool LngParser::isNextGroup(OString &sGroup_out, const OString &sLine_in)
137 : {
138 0 : const OString sLineTrim = sLine_in.trim();
139 0 : if (sLineTrim.startsWith("[") && sLineTrim.endsWith("]"))
140 : {
141 0 : sGroup_out = getBracketedContent(sLineTrim).trim();
142 0 : return true;
143 : }
144 0 : return false;
145 : }
146 :
147 0 : void LngParser::ReadLine(const OString &rLine_in,
148 : OStringHashMap &rText_inout)
149 : {
150 0 : if (!rLine_in.match(" *") && !rLine_in.match("/*"))
151 : {
152 0 : OString sLang(rLine_in.getToken(0, '=').trim());
153 0 : if (!sLang.isEmpty()) {
154 0 : OString sText(rLine_in.getToken(1, '"'));
155 0 : rText_inout[sLang] = sText;
156 0 : }
157 : }
158 0 : }
159 :
160 0 : bool LngParser::Merge(
161 : const OString &rPOFile,
162 : const OString &rDestinationFile,
163 : const OString &rLanguage )
164 : {
165 : std::ofstream aDestination(
166 0 : rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc);
167 0 : if (!aDestination.is_open()) {
168 0 : nError = LNG_COULD_NOT_OPEN;
169 : }
170 0 : nError = LNG_OK;
171 :
172 0 : MergeDataFile aMergeDataFile( rPOFile, sSource, false, true );
173 0 : if( rLanguage.equalsIgnoreAsciiCase("ALL") )
174 0 : aLanguages = aMergeDataFile.GetLanguages();
175 :
176 0 : size_t nPos = 0;
177 0 : bool bGroup = false;
178 0 : OString sGroup;
179 :
180 : // seek to next group
181 0 : while ( nPos < pLines->size() && !bGroup )
182 : {
183 0 : OString sLine( *(*pLines)[ nPos ] );
184 0 : sLine = sLine.trim();
185 0 : if ( sLine.startsWith("[") && sLine.endsWith("]") )
186 : {
187 0 : sGroup = getBracketedContent(sLine).trim();
188 0 : bGroup = true;
189 : }
190 0 : nPos ++;
191 0 : }
192 :
193 0 : while ( nPos < pLines->size()) {
194 0 : OStringHashMap Text;
195 0 : OString sID( sGroup );
196 0 : std::size_t nLastLangPos = 0;
197 :
198 0 : ResData *pResData = new ResData( sID, sSource );
199 0 : pResData->sResTyp = "LngText";
200 0 : MergeEntrys *pEntrys = aMergeDataFile.GetMergeEntrys( pResData );
201 : // read languages
202 0 : bGroup = false;
203 :
204 0 : OString sLanguagesDone;
205 :
206 0 : while ( nPos < pLines->size() && !bGroup )
207 : {
208 0 : OString sLine( *(*pLines)[ nPos ] );
209 0 : sLine = sLine.trim();
210 0 : if ( sLine.startsWith("[") && sLine.endsWith("]") )
211 : {
212 0 : sGroup = getBracketedContent(sLine).trim();
213 0 : bGroup = true;
214 0 : nPos ++;
215 0 : sLanguagesDone = "";
216 : }
217 : else
218 : {
219 0 : sal_Int32 n = 0;
220 0 : OString sLang(sLine.getToken(0, '=', n));
221 0 : if (n == -1 || static_cast<bool>(sLine.match("/*")))
222 : {
223 0 : ++nPos;
224 : }
225 : else
226 : {
227 0 : sLang = sLang.trim();
228 :
229 0 : OString sSearch( ";" );
230 0 : sSearch += sLang;
231 0 : sSearch += ";";
232 :
233 0 : if (( sLanguagesDone.indexOf( sSearch ) != -1 )) {
234 0 : LngLineList::iterator it = pLines->begin();
235 0 : std::advance( it, nPos );
236 0 : pLines->erase( it );
237 : }
238 0 : if( pEntrys )
239 : {
240 0 : if( !sLang.isEmpty() )
241 : {
242 0 : OString sNewText;
243 0 : pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, true );
244 0 : if( sLang == "qtz" )
245 0 : continue;
246 :
247 0 : if ( !sNewText.isEmpty()) {
248 0 : OString *pLine = (*pLines)[ nPos ];
249 :
250 0 : OString sText1( sLang );
251 0 : sText1 += " = \"";
252 : // escape quotes, unescape double escaped quotes fdo#56648
253 0 : sText1 += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
254 0 : sText1 += "\"";
255 0 : *pLine = sText1;
256 0 : Text[ sLang ] = sNewText;
257 0 : }
258 : }
259 0 : nLastLangPos = nPos;
260 0 : nPos ++;
261 0 : sLanguagesDone += sSearch;
262 : }
263 : else {
264 0 : nLastLangPos = nPos;
265 0 : nPos ++;
266 0 : sLanguagesDone += sSearch;
267 0 : }
268 0 : }
269 : }
270 0 : }
271 0 : OString sCur;
272 0 : if ( nLastLangPos )
273 : {
274 0 : for(size_t n = 0; n < aLanguages.size(); ++n)
275 : {
276 0 : sCur = aLanguages[ n ];
277 0 : if( !sCur.equalsIgnoreAsciiCase("en-US") && Text[sCur].isEmpty() && pEntrys )
278 : {
279 :
280 0 : OString sNewText;
281 0 : pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, true );
282 0 : if( sCur == "qtz" )
283 0 : continue;
284 0 : if ( !sNewText.isEmpty() && sCur != "x-comment")
285 : {
286 0 : OString sLine;
287 0 : sLine += sCur;
288 0 : sLine += " = \"";
289 : // escape quotes, unescape double escaped quotes fdo#56648
290 0 : sLine += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
291 0 : sLine += "\"";
292 :
293 0 : nLastLangPos++;
294 0 : nPos++;
295 :
296 0 : if ( nLastLangPos < pLines->size() ) {
297 0 : LngLineList::iterator it = pLines->begin();
298 0 : std::advance( it, nLastLangPos );
299 0 : pLines->insert( it, new OString(sLine) );
300 : } else {
301 0 : pLines->push_back( new OString(sLine) );
302 0 : }
303 0 : }
304 : }
305 : }
306 : }
307 :
308 0 : delete pResData;
309 0 : }
310 :
311 0 : for ( size_t i = 0; i < pLines->size(); ++i )
312 0 : aDestination << (*pLines)[i]->getStr() << '\n';
313 :
314 0 : aDestination.close();
315 0 : return true;
316 0 : }
317 :
318 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|