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 0 : Text.erase("x-comment");
118 : }
119 0 : aPOStream.close();
120 0 : return true;
121 : }
122 :
123 0 : void LngParser::WritePO(PoOfstream &aPOStream,
124 : OStringHashMap &rText_inout, const OString &rActFileName,
125 : const OString &rID)
126 : {
127 :
128 0 : bool bExport = true;
129 0 : if ( bExport )
130 : {
131 : common::writePoEntry(
132 : "Ulfex", aPOStream, rActFileName, "LngText",
133 0 : rID, OString(), rText_inout.count("x-comment") ? rText_inout["x-comment"] : OString(), rText_inout["en-US"]);
134 : }
135 0 : }
136 :
137 0 : bool LngParser::isNextGroup(OString &sGroup_out, const OString &sLine_in)
138 : {
139 0 : const OString sLineTrim = sLine_in.trim();
140 0 : if (sLineTrim.startsWith("[") && sLineTrim.endsWith("]"))
141 : {
142 0 : sGroup_out = getBracketedContent(sLineTrim).trim();
143 0 : return true;
144 : }
145 0 : return false;
146 : }
147 :
148 0 : void LngParser::ReadLine(const OString &rLine_in,
149 : OStringHashMap &rText_inout)
150 : {
151 0 : if (!rLine_in.match(" *") && !rLine_in.match("/*"))
152 : {
153 0 : OString sLang(rLine_in.getToken(0, '=').trim());
154 0 : if (!sLang.isEmpty()) {
155 0 : OString sText(rLine_in.getToken(1, '"'));
156 0 : rText_inout[sLang] = sText;
157 0 : }
158 : }
159 0 : }
160 :
161 0 : bool LngParser::Merge(
162 : const OString &rPOFile,
163 : const OString &rDestinationFile,
164 : const OString &rLanguage )
165 : {
166 : std::ofstream aDestination(
167 0 : rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc);
168 0 : if (!aDestination.is_open()) {
169 0 : nError = LNG_COULD_NOT_OPEN;
170 : }
171 0 : nError = LNG_OK;
172 :
173 0 : MergeDataFile aMergeDataFile( rPOFile, sSource, false, true );
174 0 : if( rLanguage.equalsIgnoreAsciiCase("ALL") )
175 0 : aLanguages = aMergeDataFile.GetLanguages();
176 :
177 0 : size_t nPos = 0;
178 0 : bool bGroup = false;
179 0 : OString sGroup;
180 :
181 : // seek to next group
182 0 : while ( nPos < pLines->size() && !bGroup )
183 : {
184 0 : OString sLine( *(*pLines)[ nPos ] );
185 0 : sLine = sLine.trim();
186 0 : if ( sLine.startsWith("[") && sLine.endsWith("]") )
187 : {
188 0 : sGroup = getBracketedContent(sLine).trim();
189 0 : bGroup = true;
190 : }
191 0 : nPos ++;
192 0 : }
193 :
194 0 : while ( nPos < pLines->size()) {
195 0 : OStringHashMap Text;
196 0 : OString sID( sGroup );
197 0 : std::size_t nLastLangPos = 0;
198 :
199 0 : ResData *pResData = new ResData( sID, sSource );
200 0 : pResData->sResTyp = "LngText";
201 0 : MergeEntrys *pEntrys = aMergeDataFile.GetMergeEntrys( pResData );
202 : // read languages
203 0 : bGroup = false;
204 :
205 0 : OString sLanguagesDone;
206 :
207 0 : while ( nPos < pLines->size() && !bGroup )
208 : {
209 0 : OString sLine( *(*pLines)[ nPos ] );
210 0 : sLine = sLine.trim();
211 0 : if ( sLine.startsWith("[") && sLine.endsWith("]") )
212 : {
213 0 : sGroup = getBracketedContent(sLine).trim();
214 0 : bGroup = true;
215 0 : nPos ++;
216 0 : sLanguagesDone = "";
217 : }
218 : else
219 : {
220 0 : sal_Int32 n = 0;
221 0 : OString sLang(sLine.getToken(0, '=', n));
222 0 : if (n == -1 || static_cast<bool>(sLine.match("/*")))
223 : {
224 0 : ++nPos;
225 : }
226 : else
227 : {
228 0 : sLang = sLang.trim();
229 :
230 0 : OString sSearch( ";" );
231 0 : sSearch += sLang;
232 0 : sSearch += ";";
233 :
234 0 : if (( sLanguagesDone.indexOf( sSearch ) != -1 )) {
235 0 : LngLineList::iterator it = pLines->begin();
236 0 : std::advance( it, nPos );
237 0 : pLines->erase( it );
238 : }
239 0 : if( pEntrys )
240 : {
241 0 : if( !sLang.isEmpty() )
242 : {
243 0 : OString sNewText;
244 0 : pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, true );
245 0 : if( sLang == "qtz" )
246 0 : continue;
247 :
248 0 : if ( !sNewText.isEmpty()) {
249 0 : OString *pLine = (*pLines)[ nPos ];
250 :
251 0 : OString sText1( sLang );
252 0 : sText1 += " = \"";
253 : // escape quotes, unescape double escaped quotes fdo#56648
254 0 : sText1 += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
255 0 : sText1 += "\"";
256 0 : *pLine = sText1;
257 0 : Text[ sLang ] = sNewText;
258 0 : }
259 : }
260 0 : nLastLangPos = nPos;
261 0 : nPos ++;
262 0 : sLanguagesDone += sSearch;
263 : }
264 : else {
265 0 : nLastLangPos = nPos;
266 0 : nPos ++;
267 0 : sLanguagesDone += sSearch;
268 0 : }
269 0 : }
270 : }
271 0 : }
272 0 : OString sCur;
273 0 : if ( nLastLangPos )
274 : {
275 0 : for(size_t n = 0; n < aLanguages.size(); ++n)
276 : {
277 0 : sCur = aLanguages[ n ];
278 0 : if( !sCur.equalsIgnoreAsciiCase("en-US") && Text[sCur].isEmpty() && pEntrys )
279 : {
280 :
281 0 : OString sNewText;
282 0 : pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, true );
283 0 : if( sCur == "qtz" )
284 0 : continue;
285 0 : if ( !sNewText.isEmpty() && sCur != "x-comment")
286 : {
287 0 : OString sLine;
288 0 : sLine += sCur;
289 0 : sLine += " = \"";
290 : // escape quotes, unescape double escaped quotes fdo#56648
291 0 : sLine += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
292 0 : sLine += "\"";
293 :
294 0 : nLastLangPos++;
295 0 : nPos++;
296 :
297 0 : if ( nLastLangPos < pLines->size() ) {
298 0 : LngLineList::iterator it = pLines->begin();
299 0 : std::advance( it, nLastLangPos );
300 0 : pLines->insert( it, new OString(sLine) );
301 : } else {
302 0 : pLines->push_back( new OString(sLine) );
303 0 : }
304 0 : }
305 : }
306 : }
307 : }
308 :
309 0 : delete pResData;
310 0 : }
311 :
312 0 : for ( size_t i = 0; i < pLines->size(); ++i )
313 0 : aDestination << (*pLines)[i]->getStr() << '\n';
314 :
315 0 : aDestination.close();
316 0 : return true;
317 0 : }
318 :
319 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|