bump product version to 4.1.6.2
[LibreOffice.git] / l10ntools / source / lngmerge.cxx
blob27c7d5d9dcb8804998d3c0179d66487fb368b655
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <cstddef>
23 #include <fstream>
24 #include <iterator>
25 #include <string>
27 #include "po.hxx"
28 #include "lngmerge.hxx"
30 namespace {
32 OString getBracketedContent(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);
48 // class LngParser
50 LngParser::LngParser(const OString &rLngFile,
51 sal_Bool bULFFormat)
52 : nError( LNG_OK )
53 , pLines( NULL )
54 , sSource( rLngFile )
55 , bULF( bULFFormat )
57 pLines = new LngLineList();
58 std::ifstream aStream(sSource.getStr());
59 if (aStream.is_open())
61 bool bFirstLine = true;
62 std::string s;
63 std::getline(aStream, s);
64 while (!aStream.eof())
66 OString sLine(s.data(), s.length());
68 if( bFirstLine )
70 // Always remove UTF8 BOM from the first line
71 lcl_RemoveUTF8ByteOrderMarker( sLine );
72 bFirstLine = false;
75 pLines->push_back( new OString(sLine) );
76 std::getline(aStream, s);
78 pLines->push_back( new OString() );
80 else
81 nError = LNG_COULD_NOT_OPEN;
84 LngParser::~LngParser()
86 for ( size_t i = 0, n = pLines->size(); i < n; ++i )
87 delete (*pLines)[ i ];
88 pLines->clear();
89 delete pLines;
92 sal_Bool LngParser::CreatePO( const OString &rPOFile )
94 PoOfstream aPOStream( rPOFile, PoOfstream::APP );
95 if (!aPOStream.isOpen()) {
96 std::cerr << "Ulfex error: Can't open po file:" << rPOFile.getStr() << "\n";
99 size_t nPos = 0;
100 sal_Bool bStart = true;
101 OString sGroup, sLine;
102 OStringHashMap Text;
103 OString sID;
105 while( nPos < pLines->size() ) {
106 sLine = *(*pLines)[ nPos++ ];
107 while( nPos < pLines->size() && !isNextGroup( sGroup , sLine ) ) {
108 ReadLine( sLine , Text );
109 sID = sGroup;
110 sLine = *(*pLines)[ nPos++ ];
112 if( bStart ) {
113 bStart = false;
114 sID = sGroup;
116 else {
117 WritePO( aPOStream , Text , sSource , sID );
120 aPOStream.close();
121 return true;
124 void LngParser::WritePO(PoOfstream &aPOStream,
125 OStringHashMap &rText_inout, const OString &rActFileName,
126 const OString &rID)
129 sal_Bool bExport = true;
130 if ( bExport )
132 common::writePoEntry(
133 "Ulfex", aPOStream, rActFileName, "LngText",
134 rID, OString(), OString(), rText_inout["en-US"]);
138 bool LngParser::isNextGroup(OString &sGroup_out, const OString &sLine_in)
140 const OString sLineTrim = sLine_in.trim();
141 if ((sLineTrim[0] == '[') && (sLineTrim[sLineTrim.getLength() - 1] == ']'))
143 sGroup_out = getBracketedContent(sLineTrim).trim();
144 return true;
146 return false;
149 void LngParser::ReadLine(const OString &rLine_in,
150 OStringHashMap &rText_inout)
152 if (!rLine_in.match(" *") && !rLine_in.match("/*"))
154 OString sLang(rLine_in.getToken(0, '=').trim());
155 if (!sLang.isEmpty()) {
156 OString sText(rLine_in.getToken(1, '"'));
157 rText_inout[sLang] = sText;
162 sal_Bool LngParser::Merge(
163 const OString &rPOFile,
164 const OString &rDestinationFile,
165 const OString &rLanguage )
167 std::ofstream aDestination(
168 rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc);
169 if (!aDestination.is_open()) {
170 nError = LNG_COULD_NOT_OPEN;
172 nError = LNG_OK;
174 MergeDataFile aMergeDataFile( rPOFile, sSource, false, true );
175 if( rLanguage.equalsIgnoreAsciiCase("ALL") )
176 aLanguages = aMergeDataFile.GetLanguages();
178 size_t nPos = 0;
179 sal_Bool bGroup = sal_False;
180 OString sGroup;
182 // seek to next group
183 while ( nPos < pLines->size() && !bGroup )
185 OString sLine( *(*pLines)[ nPos ] );
186 sLine = sLine.trim();
187 if (!sLine.isEmpty() &&
188 ( sLine[0] == '[' ) &&
189 ( sLine[sLine.getLength() - 1] == ']' ))
191 sGroup = getBracketedContent(sLine).trim();
192 bGroup = sal_True;
194 nPos ++;
197 while ( nPos < pLines->size()) {
198 OStringHashMap Text;
199 OString sID( sGroup );
200 std::size_t nLastLangPos = 0;
202 ResData *pResData = new ResData( sID, sSource );
203 pResData->sResTyp = "LngText";
204 MergeEntrys *pEntrys = aMergeDataFile.GetMergeEntrys( pResData );
205 // read languages
206 bGroup = sal_False;
208 OString sLanguagesDone;
210 while ( nPos < pLines->size() && !bGroup )
212 OString sLine( *(*pLines)[ nPos ] );
213 sLine = sLine.trim();
214 if (!sLine.isEmpty() &&
215 ( sLine[0] == '[' ) &&
216 ( sLine[sLine.getLength() - 1] == ']' ))
218 sGroup = getBracketedContent(sLine).trim();
219 bGroup = sal_True;
220 nPos ++;
221 sLanguagesDone = "";
223 else
225 sal_Int32 n = 0;
226 OString sLang(sLine.getToken(0, '=', n));
227 if (n == -1 || static_cast<bool>(sLine.match("/*")))
229 ++nPos;
231 else
233 sLang = sLang.trim();
235 OString sSearch( ";" );
236 sSearch += sLang;
237 sSearch += ";";
239 if (( sLanguagesDone.indexOf( sSearch ) != -1 )) {
240 LngLineList::iterator it = pLines->begin();
241 std::advance( it, nPos );
242 pLines->erase( it );
244 if( bULF && pEntrys )
246 if( !sLang.isEmpty() )
248 OString sNewText;
249 pEntrys->GetText( sNewText, STRING_TYP_TEXT, sLang, sal_True );
250 if( sLang == "qtz" )
251 sNewText = sNewText.copy(sNewText.indexOf("|") + 2);
253 if ( !sNewText.isEmpty()) {
254 OString *pLine = (*pLines)[ nPos ];
256 OString sText1( sLang );
257 sText1 += " = \"";
258 // escape quotes, unescape double escaped quotes fdo#56648
259 sText1 += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
260 sText1 += "\"";
261 *pLine = sText1;
262 Text[ sLang ] = sNewText;
265 nLastLangPos = nPos;
266 nPos ++;
267 sLanguagesDone += sSearch;
269 else {
270 nLastLangPos = nPos;
271 nPos ++;
272 sLanguagesDone += sSearch;
277 OString sCur;
278 if ( nLastLangPos )
280 for(size_t n = 0; n < aLanguages.size(); ++n)
282 sCur = aLanguages[ n ];
283 if( !sCur.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US")) && Text[sCur].isEmpty() && pEntrys )
286 OString sNewText;
287 pEntrys->GetText( sNewText, STRING_TYP_TEXT, sCur, sal_True );
288 if( sCur == "qtz" )
289 sNewText = sNewText.copy(sNewText.indexOf("|") + 2);
290 if ( !sNewText.isEmpty() && sCur != "x-comment")
292 OString sLine;
293 sLine += sCur;
294 sLine += " = \"";
295 // escape quotes, unescape double escaped quotes fdo#56648
296 sLine += sNewText.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"");
297 sLine += "\"";
299 nLastLangPos++;
300 nPos++;
302 if ( nLastLangPos < pLines->size() ) {
303 LngLineList::iterator it = pLines->begin();
304 std::advance( it, nLastLangPos );
305 pLines->insert( it, new OString(sLine) );
306 } else {
307 pLines->push_back( new OString(sLine) );
314 delete pResData;
317 for ( size_t i = 0; i < pLines->size(); ++i )
318 aDestination << (*pLines)[i]->getStr() << '\n';
320 aDestination.close();
321 return sal_True;
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */