1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
29 #include <lngmerge.hxx>
33 bool lcl_isNextGroup(OString
&sGroup_out
, const OString
&sLineTrim
)
35 if (sLineTrim
.startsWith("[") && sLineTrim
.endsWith("]"))
37 sGroup_out
= sLineTrim
.getToken(1, '[').getToken(0, ']').trim();
43 void lcl_RemoveUTF8ByteOrderMarker( OString
&rString
)
45 if( rString
.getLength() >= 3 && rString
[0] == '\xEF' &&
46 rString
[1] == '\xBB' && rString
[2] == '\xBF' )
48 rString
= rString
.copy(3);
56 LngParser::LngParser(const OString
&rLngFile
)
59 std::ifstream
aStream(sSource
.getStr());
60 if (!aStream
.is_open())
63 bool bFirstLine
= true;
65 std::getline(aStream
, s
);
66 while (!aStream
.eof())
68 OString
sLine(s
.data(), s
.length());
72 // Always remove UTF8 BOM from the first line
73 lcl_RemoveUTF8ByteOrderMarker( sLine
);
77 mvLines
.push_back( sLine
);
78 std::getline(aStream
, s
);
80 mvLines
.push_back( OString() );
83 LngParser::~LngParser()
87 void LngParser::CreatePO( const OString
&rPOFile
)
89 PoOfstream
aPOStream( rPOFile
, PoOfstream::APP
);
90 if (!aPOStream
.isOpen()) {
91 std::cerr
<< "Ulfex error: Can't open po file:" << rPOFile
<< "\n";
96 OString sGroup
, sLine
;
100 while( nPos
< mvLines
.size() ) {
101 sLine
= mvLines
[ nPos
++ ];
102 while( nPos
< mvLines
.size() && !isNextGroup( sGroup
, sLine
) ) {
103 ReadLine( sLine
, Text
);
105 sLine
= mvLines
[ nPos
++ ];
112 WritePO( aPOStream
, Text
, sSource
, sID
);
114 Text
.erase("x-comment");
119 void LngParser::WritePO(PoOfstream
&aPOStream
,
120 OStringHashMap
&rText_inout
, const OString
&rActFileName
,
123 common::writePoEntry(
124 "Ulfex", aPOStream
, rActFileName
, "LngText",
125 rID
, OString(), rText_inout
.count("x-comment") ? rText_inout
["x-comment"] : OString(), rText_inout
["en-US"]);
128 bool LngParser::isNextGroup(OString
&sGroup_out
, const OString
&sLine_in
)
130 return lcl_isNextGroup(sGroup_out
, sLine_in
.trim());
133 void LngParser::ReadLine(const OString
&rLine_in
,
134 OStringHashMap
&rText_inout
)
136 if (!rLine_in
.match(" *") && !rLine_in
.match("/*"))
138 OString
sLang(rLine_in
.getToken(0, '=').trim());
139 if (!sLang
.isEmpty()) {
140 OString
sText(rLine_in
.getToken(1, '"'));
141 rText_inout
[sLang
] = sText
;
146 void LngParser::Merge(
147 const OString
&rPOFile
,
148 const OString
&rDestinationFile
,
149 const OString
&rLanguage
)
151 std::ofstream
aDestination(
152 rDestinationFile
.getStr(), std::ios_base::out
| std::ios_base::trunc
);
154 MergeDataFile
aMergeDataFile( rPOFile
, sSource
, false, true );
155 if( rLanguage
.equalsIgnoreAsciiCase("ALL") )
156 aLanguages
= aMergeDataFile
.GetLanguages();
162 // seek to next group
163 while ( nPos
< mvLines
.size() && !bGroup
)
164 bGroup
= lcl_isNextGroup(sGroup
, mvLines
[nPos
++].trim());
166 while ( nPos
< mvLines
.size()) {
168 OString
sID( sGroup
);
169 std::size_t nLastLangPos
= 0;
171 std::unique_ptr
<ResData
> pResData( new ResData( sID
, sSource
) );
172 pResData
->sResTyp
= "LngText";
173 MergeEntrys
*pEntrys
= aMergeDataFile
.GetMergeEntrys( pResData
.get() );
177 OString sLanguagesDone
;
179 while ( nPos
< mvLines
.size() && !bGroup
)
181 const OString sLine
{ mvLines
[nPos
].trim() };
182 if ( lcl_isNextGroup(sGroup
, sLine
) )
191 OString
sLang(sLine
.getToken(0, '=', n
));
192 if (n
== -1 || static_cast<bool>(sLine
.match("/*")))
198 sLang
= sLang
.trim();
200 OString sSearch
{ ";" + sLang
+ ";" };
202 if ( sLanguagesDone
.indexOf( sSearch
) != -1 ) {
203 mvLines
.erase( mvLines
.begin() + nPos
);
207 if( !sLang
.isEmpty() )
210 pEntrys
->GetText( sNewText
, sLang
, true );
214 if ( !sNewText
.isEmpty()) {
215 mvLines
[ nPos
] = sLang
217 // escape quotes, unescape double escaped quotes fdo#56648
218 + sNewText
.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"")
220 Text
[ sLang
] = sNewText
;
225 sLanguagesDone
+= sSearch
;
230 sLanguagesDone
+= sSearch
;
238 for(size_t n
= 0; n
< aLanguages
.size(); ++n
)
240 sCur
= aLanguages
[ n
];
241 if( !sCur
.equalsIgnoreAsciiCase("en-US") && Text
[sCur
].isEmpty() && pEntrys
)
245 pEntrys
->GetText( sNewText
, sCur
, true );
248 if ( !sNewText
.isEmpty() && sCur
!= "x-comment")
250 const OString sLine
{ sCur
252 // escape quotes, unescape double escaped quotes fdo#56648
253 + sNewText
.replaceAll("\"","\\\"").replaceAll("\\\\\"","\\\"")
259 if ( nLastLangPos
< mvLines
.size() ) {
260 mvLines
.insert( mvLines
.begin() + nLastLangPos
, sLine
);
262 mvLines
.push_back( sLine
);
270 for ( size_t i
= 0; i
< mvLines
.size(); ++i
)
271 aDestination
<< mvLines
[i
] << '\n';
273 aDestination
.close();
276 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */