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/.
14 #include <libxml/tree.h>
15 #include <libxml/parser.h>
16 #include <libxml/xmlstring.h>
22 #include <treemerge.hxx>
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
)
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"));
44 xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("title"));
47 "Treex", rPOStream
, pSource
->name
, helper::xmlStrToOString( pNodeName
),
48 helper::xmlStrToOString( pID
), OString(), OString(), helper::xmlStrToOString( pText
));
54 pSource
, pCurrent
, reinterpret_cast<const xmlChar
*>("node"),
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"));
67 helper::xmlStrToOString( pID
);
70 const sal_Int32 nFirstSlash
= sID
.indexOf('/');
71 // Update id attribute of topic
74 OString::Concat(sID
.subView( 0, nFirstSlash
+ 1 )) +
75 rXhpRoot
.substr( rXhpRoot
.rfind('/') + 1 ) +
76 sID
.subView( sID
.indexOf( '/', nFirstSlash
+ 1 ) );
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
89 xmlNodePtr pTemp
= pReturn
;
91 xmlGetProp(pReturn
, reinterpret_cast<const xmlChar
*>("id"));
93 xmlStrcat( xmlCharStrdup("removed "), sNewID
);
94 pReturn
= xmlNewComment( sComment
);
95 xmlReplaceNode( pTemp
, pReturn
);
100 // update topic's content on the basis of xhpfile's title
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")))
114 xmlNodeListGetString(pXhpFile
, pXhpNode
->children
, 1);
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
);
130 << "Treex error: Cannot find title in "
131 << sXhpPath
<< std::endl
;
134 xmlFreeDoc( pXhpFile
);
139 // Localize title attribute of help_section and node tags
141 xmlDocPtr io_pSource
, const xmlNodePtr pRoot
,
142 const xmlChar
* pNodeName
, MergeDataFile
* pMergeDataFile
,
143 const OString
& rLang
, const OString
& rXhpRoot
)
145 if( !pRoot
->children
)
149 for( xmlNodePtr pCurrent
= pRoot
->children
;
150 pCurrent
; pCurrent
= pCurrent
->next
)
152 if( !xmlStrcmp(pCurrent
->name
, pNodeName
) )
154 if( rLang
!= "en-US" )
157 xmlChar
* pID
= xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("id"));
159 helper::xmlStrToOString( pID
),
160 static_cast<OString
>(io_pSource
->name
) );
162 aResData
.sResTyp
= helper::xmlStrToOString( pNodeName
);
165 MergeEntrys
* pEntrys
=
166 pMergeDataFile
->GetMergeEntrys( &aResData
);
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
);
177 sNewText
= MergeEntrys::GetQTZText(aResData
, sOriginText
);
179 if( !sNewText
.isEmpty() )
182 pCurrent
, reinterpret_cast<const xmlChar
*>("title"),
183 reinterpret_cast<const xmlChar
*>(sNewText
.getStr()));
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() );
208 << "Treex error: Cannot open source file: "
209 << rInputFile
<< std::endl
;
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() )
234 << "Treex error: Cannot open po file for extract: "
235 << rPOFile
<< std::endl
;
239 xmlNodePtr pRootNode
= xmlDocGetRootElement( m_pSource
);
241 m_pSource
, pRootNode
, reinterpret_cast<const xmlChar
*>("help_section"),
244 xmlFreeDoc( m_pSource
);
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
)
266 << ("Treex error: given language conflicts with language of"
269 << vLanguages
[0] << std::endl
;
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
);
281 m_bIsInitialized
= false;
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */