cid#1636693 COPY_INSTEAD_OF_MOVE
[LibreOffice.git] / l10ntools / source / lngmerge.cxx
blob9a1b172a098166764f891aadd4344fce692ad333
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 <o3tl/string_view.hxx>
24 #include <cstddef>
25 #include <iostream>
26 #include <memory>
27 #include <string>
29 #include <common.hxx>
30 #include <po.hxx>
31 #include <lngmerge.hxx>
32 #include <utility>
34 namespace {
36 bool lcl_isNextGroup(OString &sGroup_out, std::string_view sLineTrim)
38 if (o3tl::starts_with(sLineTrim, "[") && o3tl::ends_with(sLineTrim, "]"))
40 sLineTrim = o3tl::getToken(sLineTrim, 1, '[');
41 sLineTrim = o3tl::getToken(sLineTrim, 0, ']');
42 sGroup_out = OString(o3tl::trim(sLineTrim));
43 return true;
45 return false;
48 void lcl_RemoveUTF8ByteOrderMarker( OString &rString )
50 if( rString.getLength() >= 3 && rString[0] == '\xEF' &&
51 rString[1] == '\xBB' && rString[2] == '\xBF' )
53 rString = rString.copy(3);
61 LngParser::LngParser(OString sLngFile)
62 : sSource(std::move( sLngFile ))
64 std::ifstream aStream(sSource.getStr());
65 if (!aStream.is_open())
66 return;
68 bool bFirstLine = true;
69 std::string s;
70 while (std::getline(aStream, s))
72 OString sLine(s.data(), s.length());
74 if( bFirstLine )
76 // Always remove UTF8 BOM from the first line
77 lcl_RemoveUTF8ByteOrderMarker( sLine );
78 bFirstLine = false;
81 mvLines.push_back( sLine );
83 mvLines.push_back( OString() );
86 LngParser::~LngParser()
90 void 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 << "\n";
97 size_t nPos = 0;
98 bool bStart = true;
99 OString sGroup, sLine;
100 OStringHashMap Text;
101 OString sID;
103 while( nPos < mvLines.size() ) {
104 sLine = mvLines[ nPos++ ];
105 while( nPos < mvLines.size() && !isNextGroup( sGroup , sLine ) ) {
106 ReadLine( sLine , Text );
107 sID = sGroup;
108 sLine = mvLines[ nPos++ ];
110 if( bStart ) {
111 bStart = false;
112 sID = sGroup;
114 else {
115 WritePO( aPOStream , Text , sSource , sID );
117 Text.erase("x-comment"_ostr);
119 aPOStream.close();
122 void LngParser::WritePO(PoOfstream &aPOStream,
123 OStringHashMap &rText_inout, const OString &rActFileName,
124 const OString &rID)
126 common::writePoEntry(
127 "Ulfex"_ostr, aPOStream, rActFileName, "LngText",
128 rID, OString(), rText_inout.count("x-comment"_ostr) ? rText_inout["x-comment"_ostr] : OString(), rText_inout["en-US"_ostr]);
131 bool LngParser::isNextGroup(OString &sGroup_out, std::string_view sLine_in)
133 return lcl_isNextGroup(sGroup_out, o3tl::trim(sLine_in));
136 void LngParser::ReadLine(std::string_view rLine_in,
137 OStringHashMap &rText_inout)
139 if (!o3tl::starts_with(rLine_in, " *") && !o3tl::starts_with(rLine_in, "/*"))
141 OString sLang(o3tl::trim(o3tl::getToken(rLine_in, 0, '=')));
142 if (!sLang.isEmpty()) {
143 rText_inout[sLang] = OString(o3tl::getToken(rLine_in, 1, '"'));
148 void LngParser::Merge(
149 const OString &rPOFile,
150 const OString &rDestinationFile,
151 std::string_view rLanguage )
153 std::ofstream aDestination(
154 rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc);
156 MergeDataFile aMergeDataFile( rPOFile, sSource, false, true );
157 if( o3tl::equalsIgnoreAsciiCase(rLanguage, "ALL") )
158 aLanguages = aMergeDataFile.GetLanguages();
160 size_t nPos = 0;
161 bool bGroup = false;
162 OString sGroup;
164 // seek to next group
165 while ( nPos < mvLines.size() && !bGroup )
166 bGroup = lcl_isNextGroup(sGroup, o3tl::trim(mvLines[nPos++]));
168 while ( nPos < mvLines.size()) {
169 OStringHashMap Text;
170 OString sID( sGroup );
171 std::size_t nLastLangPos = 0;
173 ResData aResData( sID, sSource );
174 aResData.sResTyp = "LngText"_ostr;
175 MergeEntrys *pEntrys = aMergeDataFile.GetMergeEntrys( &aResData );
176 // read languages
177 bGroup = false;
179 OString sLanguagesDone;
181 while ( nPos < mvLines.size() && !bGroup )
183 const OString sLine{ mvLines[nPos].trim() };
184 if ( lcl_isNextGroup(sGroup, sLine) )
186 bGroup = true;
187 nPos ++;
188 sLanguagesDone = ""_ostr;
190 else
192 sal_Int32 n = 0;
193 OString sLang(sLine.getToken(0, '=', n));
194 if (n == -1 || static_cast<bool>(sLine.match("/*")))
196 ++nPos;
198 else
200 sLang = sLang.trim();
202 OString sSearch{ ";" + sLang + ";" };
204 if ( sLanguagesDone.indexOf( sSearch ) != -1 ) {
205 mvLines.erase( mvLines.begin() + nPos );
207 if( pEntrys )
209 if( !sLang.isEmpty() )
211 OString sNewText;
212 pEntrys->GetText( sNewText, sLang, true );
213 if( sLang == "qtz" )
214 continue;
216 if ( !sNewText.isEmpty()) {
217 mvLines[ nPos ] = sLang
218 + " = \""
219 // escape quotes, unescape double escaped quotes fdo#56648
220 + sNewText.replaceAll("\""_ostr,"\\\""_ostr).replaceAll("\\\\\""_ostr,"\\\""_ostr)
221 + "\"";
222 Text[ sLang ] = sNewText;
225 nLastLangPos = nPos;
226 nPos ++;
227 sLanguagesDone += sSearch;
229 else {
230 nLastLangPos = nPos;
231 nPos ++;
232 sLanguagesDone += sSearch;
237 OString sCur;
238 if ( nLastLangPos )
240 for(size_t n = 0; n < aLanguages.size(); ++n)
242 sCur = aLanguages[ n ];
243 if( !sCur.equalsIgnoreAsciiCase("en-US") && Text[sCur].isEmpty() && pEntrys )
246 OString sNewText;
247 pEntrys->GetText( sNewText, sCur, true );
248 if( sCur == "qtz" )
249 continue;
250 if ( !sNewText.isEmpty() && sCur != "x-comment")
252 const OString sLine { sCur
253 + " = \""
254 // escape quotes, unescape double escaped quotes fdo#56648
255 + sNewText.replaceAll("\""_ostr,"\\\""_ostr).replaceAll("\\\\\""_ostr,"\\\""_ostr)
256 + "\"" };
258 nLastLangPos++;
259 nPos++;
261 if ( nLastLangPos < mvLines.size() ) {
262 mvLines.insert( mvLines.begin() + nLastLangPos, sLine );
263 } else {
264 mvLines.push_back( sLine );
272 for ( size_t i = 0; i < mvLines.size(); ++i )
273 aDestination << mvLines[i] << '\n';
275 aDestination.close();
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */