android: Update app-specific/MIME type icons
[LibreOffice.git] / l10ntools / source / treemerge.cxx
blob860c85b38598b159d9ab17b547e04632da19ce46
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/.
8 */
10 #include <iostream>
11 #include <cassert>
12 #include <cstring>
14 #include <libxml/tree.h>
15 #include <libxml/parser.h>
16 #include <libxml/xmlstring.h>
18 #include <export.hxx>
19 #include <helper.hxx>
20 #include <common.hxx>
21 #include <po.hxx>
22 #include <treemerge.hxx>
23 #include <utility>
26 namespace
28 // Extract strings from nodes on all level recursively
29 void lcl_ExtractLevel(
30 const xmlDocPtr pSource, const xmlNodePtr pRoot,
31 const xmlChar* pNodeName, PoOfstream& rPOStream )
33 if( !pRoot->children )
35 return;
37 for( xmlNodePtr pCurrent = pRoot->children->next;
38 pCurrent; pCurrent = pCurrent->next)
40 if (!xmlStrcmp(pCurrent->name, pNodeName))
42 xmlChar* pID = xmlGetProp(pCurrent, reinterpret_cast<const xmlChar*>("id"));
43 xmlChar* pText =
44 xmlGetProp(pCurrent, reinterpret_cast<const xmlChar*>("title"));
46 common::writePoEntry(
47 "Treex", rPOStream, pSource->name, helper::xmlStrToOString( pNodeName ),
48 helper::xmlStrToOString( pID ), OString(), OString(), helper::xmlStrToOString( pText ));
50 xmlFree( pID );
51 xmlFree( pText );
53 lcl_ExtractLevel(
54 pSource, pCurrent, reinterpret_cast<const xmlChar *>("node"),
55 rPOStream );
60 // Update id and content of the topic
61 xmlNodePtr lcl_UpdateTopic(
62 const xmlNodePtr pCurrent, std::string_view rXhpRoot )
64 xmlNodePtr pReturn = pCurrent;
65 xmlChar* pID = xmlGetProp(pReturn, reinterpret_cast<const xmlChar*>("id"));
66 const OString sID =
67 helper::xmlStrToOString( pID );
68 xmlFree( pID );
70 const sal_Int32 nFirstSlash = sID.indexOf('/');
71 // Update id attribute of topic
73 OString sNewID =
74 OString::Concat(sID.subView( 0, nFirstSlash + 1 )) +
75 rXhpRoot.substr( rXhpRoot.rfind('/') + 1 ) +
76 sID.subView( sID.indexOf( '/', nFirstSlash + 1 ) );
77 xmlSetProp(
78 pReturn, reinterpret_cast<const xmlChar*>("id"),
79 reinterpret_cast<const xmlChar*>(sNewID.getStr()));
82 const OString sXhpPath =
83 OString::Concat(rXhpRoot) +
84 sID.subView(sID.indexOf('/', nFirstSlash + 1));
85 xmlDocPtr pXhpFile = xmlParseFile( sXhpPath.getStr() );
86 // if xhpfile is missing than put this topic into comment
87 if ( !pXhpFile )
89 xmlNodePtr pTemp = pReturn;
90 xmlChar* sNewID =
91 xmlGetProp(pReturn, reinterpret_cast<const xmlChar*>("id"));
92 xmlChar* sComment =
93 xmlStrcat( xmlCharStrdup("removed "), sNewID );
94 pReturn = xmlNewComment( sComment );
95 xmlReplaceNode( pTemp, pReturn );
96 xmlFree( pTemp );
97 xmlFree( sNewID );
98 xmlFree( sComment );
100 // update topic's content on the basis of xhpfile's title
101 else
103 xmlNodePtr pXhpNode = xmlDocGetRootElement( pXhpFile );
104 for( pXhpNode = pXhpNode->children;
105 pXhpNode; pXhpNode = pXhpNode->children )
107 while( pXhpNode->type != XML_ELEMENT_NODE )
109 pXhpNode = pXhpNode->next;
111 if(!xmlStrcmp(pXhpNode->name, reinterpret_cast<const xmlChar *>("title")))
113 xmlChar* sTitle =
114 xmlNodeListGetString(pXhpFile, pXhpNode->children, 1);
115 OString sNewTitle =
116 helper::xmlStrToOString( sTitle ).
117 replaceAll("$[officename]","%PRODUCTNAME").
118 replaceAll("$[officeversion]","%PRODUCTVERSION");
119 xmlChar *xmlString = xmlEncodeSpecialChars(nullptr,
120 reinterpret_cast<const xmlChar*>( sNewTitle.getStr() ));
121 xmlNodeSetContent( pReturn, xmlString);
122 xmlFree( xmlString );
123 xmlFree( sTitle );
124 break;
127 if( !pXhpNode )
129 std::cerr
130 << "Treex error: Cannot find title in "
131 << sXhpPath << std::endl;
132 pReturn = nullptr;
134 xmlFreeDoc( pXhpFile );
135 xmlCleanupParser();
137 return pReturn;
139 // Localize title attribute of help_section and node tags
140 void lcl_MergeLevel(
141 xmlDocPtr io_pSource, const xmlNodePtr pRoot,
142 const xmlChar * pNodeName, MergeDataFile* pMergeDataFile,
143 const OString& rLang, const OString& rXhpRoot )
145 if( !pRoot->children )
147 return;
149 for( xmlNodePtr pCurrent = pRoot->children;
150 pCurrent; pCurrent = pCurrent->next)
152 if( !xmlStrcmp(pCurrent->name, pNodeName) )
154 if( rLang != "en-US" )
156 OString sNewText;
157 xmlChar* pID = xmlGetProp(pCurrent, reinterpret_cast<const xmlChar*>("id"));
158 ResData aResData(
159 helper::xmlStrToOString( pID ),
160 static_cast<OString>(io_pSource->name) );
161 xmlFree( pID );
162 aResData.sResTyp = helper::xmlStrToOString( pNodeName );
163 if( pMergeDataFile )
165 MergeEntrys* pEntrys =
166 pMergeDataFile->GetMergeEntrys( &aResData );
167 if( pEntrys )
169 pEntrys->GetText( sNewText, rLang );
172 else if( rLang == "qtz" )
174 xmlChar* pText = xmlGetProp(pCurrent, reinterpret_cast<const xmlChar*>("title"));
175 const OString sOriginText = helper::xmlStrToOString(pText);
176 xmlFree( pText );
177 sNewText = MergeEntrys::GetQTZText(aResData, sOriginText);
179 if( !sNewText.isEmpty() )
181 xmlSetProp(
182 pCurrent, reinterpret_cast<const xmlChar*>("title"),
183 reinterpret_cast<const xmlChar*>(sNewText.getStr()));
187 lcl_MergeLevel(
188 io_pSource, pCurrent, reinterpret_cast<const xmlChar *>("node"),
189 pMergeDataFile, rLang, rXhpRoot );
191 else if( !xmlStrcmp(pCurrent->name, reinterpret_cast<const xmlChar *>("topic")) )
193 pCurrent = lcl_UpdateTopic( pCurrent, rXhpRoot );
199 TreeParser::TreeParser(
200 const OString& rInputFile, OString _sLang )
201 : m_pSource( nullptr )
202 , m_sLang(std::move( _sLang ))
203 , m_bIsInitialized( false )
205 m_pSource = xmlParseFile( rInputFile.getStr() );
206 if ( !m_pSource ) {
207 std::cerr
208 << "Treex error: Cannot open source file: "
209 << rInputFile << std::endl;
210 return;
212 if( !m_pSource->name )
214 m_pSource->name = static_cast<char *>(xmlMalloc(strlen(rInputFile.getStr())+1));
215 strcpy( m_pSource->name, rInputFile.getStr() );
217 m_bIsInitialized = true;
220 TreeParser::~TreeParser()
222 // be sure m_pSource is freed
223 if (m_bIsInitialized)
224 xmlFreeDoc( m_pSource );
227 void TreeParser::Extract( const OString& rPOFile )
229 assert( m_bIsInitialized );
230 PoOfstream aPOStream( rPOFile, PoOfstream::APP );
231 if( !aPOStream.isOpen() )
233 std::cerr
234 << "Treex error: Cannot open po file for extract: "
235 << rPOFile << std::endl;
236 return;
239 xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
240 lcl_ExtractLevel(
241 m_pSource, pRootNode, reinterpret_cast<const xmlChar *>("help_section"),
242 aPOStream );
244 xmlFreeDoc( m_pSource );
245 xmlCleanupParser();
246 aPOStream.close();
247 m_bIsInitialized = false;
250 void TreeParser::Merge(
251 const OString &rMergeSrc, const OString &rDestinationFile,
252 const OString &rXhpRoot )
254 assert( m_bIsInitialized );
256 const xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
257 std::unique_ptr<MergeDataFile> pMergeDataFile;
258 if( m_sLang != "qtz" && m_sLang != "en-US" )
260 pMergeDataFile.reset(new MergeDataFile(
261 rMergeSrc, static_cast<OString>( m_pSource->name ), false, false ));
262 const std::vector<OString> vLanguages = pMergeDataFile->GetLanguages();
263 if( !vLanguages.empty() && vLanguages[0] != m_sLang )
265 std::cerr
266 << ("Treex error: given language conflicts with language of"
267 " Mergedata file: ")
268 << m_sLang << " - "
269 << vLanguages[0] << std::endl;
270 return;
273 lcl_MergeLevel(
274 m_pSource, pRootNode, reinterpret_cast<const xmlChar *>("help_section"),
275 pMergeDataFile.get(), m_sLang, rXhpRoot );
277 pMergeDataFile.reset();
278 xmlSaveFile( rDestinationFile.getStr(), m_pSource );
279 xmlFreeDoc( m_pSource );
280 xmlCleanupParser();
281 m_bIsInitialized = false;
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */