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