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/.
15 #include <libxml/tree.h>
16 #include <libxml/parser.h>
17 #include <libxml/xmlmemory.h>
18 #include <libxml/xmlstring.h>
24 #include <treemerge.hxx>
29 // Extract strings from nodes on all level recursively
30 void lcl_ExtractLevel(
31 const xmlDocPtr pSource
, const xmlNodePtr pRoot
,
32 const xmlChar
* pNodeName
, PoOfstream
& rPOStream
)
34 if( !pRoot
->children
)
38 for( xmlNodePtr pCurrent
= pRoot
->children
->next
;
39 pCurrent
; pCurrent
= pCurrent
->next
)
41 if (!xmlStrcmp(pCurrent
->name
, pNodeName
))
43 xmlChar
* pID
= xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("id"));
45 xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("title"));
48 "Treex", rPOStream
, pSource
->name
, helper::xmlStrToOString( pNodeName
),
49 helper::xmlStrToOString( pID
), OString(), OString(), helper::xmlStrToOString( pText
));
55 pSource
, pCurrent
, reinterpret_cast<const xmlChar
*>("node"),
61 // Update id and content of the topic
62 xmlNodePtr
lcl_UpdateTopic(
63 const xmlNodePtr pCurrent
, const OString
& rXhpRoot
)
65 xmlNodePtr pReturn
= pCurrent
;
66 xmlChar
* pID
= xmlGetProp(pReturn
, reinterpret_cast<const xmlChar
*>("id"));
68 helper::xmlStrToOString( pID
);
71 const sal_Int32 nFirstSlash
= sID
.indexOf('/');
72 // Update id attribute of topic
75 sID
.copy( 0, nFirstSlash
+ 1 ) +
76 rXhpRoot
.copy( rXhpRoot
.lastIndexOf('/') + 1 ) +
77 sID
.copy( sID
.indexOf( '/', nFirstSlash
+ 1 ) );
79 pReturn
, reinterpret_cast<const xmlChar
*>("id"),
80 reinterpret_cast<const xmlChar
*>(sNewID
.getStr()));
83 const OString sXhpPath
=
85 sID
.copy(sID
.indexOf('/', nFirstSlash
+ 1));
86 xmlDocPtr pXhpFile
= xmlParseFile( sXhpPath
.getStr() );
87 // if xhpfile is missing than put this topic into comment
90 xmlNodePtr pTemp
= pReturn
;
92 xmlGetProp(pReturn
, reinterpret_cast<const xmlChar
*>("id"));
94 xmlStrcat( xmlCharStrdup("removed "), sNewID
);
95 pReturn
= xmlNewComment( sComment
);
96 xmlReplaceNode( pTemp
, pReturn
);
101 // update topic's content on the basis of xhpfile's title
104 xmlNodePtr pXhpNode
= xmlDocGetRootElement( pXhpFile
);
105 for( pXhpNode
= pXhpNode
->children
;
106 pXhpNode
; pXhpNode
= pXhpNode
->children
)
108 while( pXhpNode
->type
!= XML_ELEMENT_NODE
)
110 pXhpNode
= pXhpNode
->next
;
112 if(!xmlStrcmp(pXhpNode
->name
, reinterpret_cast<const xmlChar
*>("title")))
115 xmlNodeListGetString(pXhpFile
, pXhpNode
->children
, 1);
117 helper::xmlStrToOString( sTitle
).
118 replaceAll("$[officename]","%PRODUCTNAME").
119 replaceAll("$[officeversion]","%PRODUCTVERSION");
122 xmlEncodeSpecialChars( nullptr,
123 reinterpret_cast<const xmlChar
*>(
124 sNewTitle
.getStr() )));
132 << "Treex error: Cannot find title in "
133 << sXhpPath
<< std::endl
;
141 // Localize title attribute of help_section and node tags
143 xmlDocPtr io_pSource
, const xmlNodePtr pRoot
,
144 const xmlChar
* pNodeName
, MergeDataFile
* pMergeDataFile
,
145 const OString
& rLang
, const OString
& rXhpRoot
)
147 if( !pRoot
->children
)
151 for( xmlNodePtr pCurrent
= pRoot
->children
;
152 pCurrent
; pCurrent
= pCurrent
->next
)
154 if( !xmlStrcmp(pCurrent
->name
, pNodeName
) )
156 if( rLang
!= "en-US" )
159 xmlChar
* pID
= xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("id"));
161 helper::xmlStrToOString( pID
),
162 static_cast<OString
>(io_pSource
->name
) );
164 aResData
.sResTyp
= helper::xmlStrToOString( pNodeName
);
167 MergeEntrys
* pEntrys
=
168 pMergeDataFile
->GetMergeEntrys( &aResData
);
171 pEntrys
->GetText( sNewText
, rLang
);
174 else if( rLang
== "qtz" )
176 xmlChar
* pText
= xmlGetProp(pCurrent
, reinterpret_cast<const xmlChar
*>("title"));
177 const OString sOriginText
= helper::xmlStrToOString(pText
);
179 sNewText
= MergeEntrys::GetQTZText(aResData
, sOriginText
);
181 if( !sNewText
.isEmpty() )
184 pCurrent
, reinterpret_cast<const xmlChar
*>("title"),
185 reinterpret_cast<const xmlChar
*>(sNewText
.getStr()));
190 io_pSource
, pCurrent
, reinterpret_cast<const xmlChar
*>("node"),
191 pMergeDataFile
, rLang
, rXhpRoot
);
193 else if( !xmlStrcmp(pCurrent
->name
, reinterpret_cast<const xmlChar
*>("topic")) )
195 pCurrent
= lcl_UpdateTopic( pCurrent
, rXhpRoot
);
201 TreeParser::TreeParser(
202 const OString
& rInputFile
, const OString
& rLang
)
203 : m_pSource( nullptr )
205 , m_bIsInitialized( false )
207 m_pSource
= xmlParseFile( rInputFile
.getStr() );
210 << "Treex error: Cannot open source file: "
211 << rInputFile
<< std::endl
;
214 if( !m_pSource
->name
)
216 m_pSource
->name
= static_cast<char *>(xmlMalloc(strlen(rInputFile
.getStr())+1));
217 strcpy( m_pSource
->name
, rInputFile
.getStr() );
219 m_bIsInitialized
= true;
222 TreeParser::~TreeParser()
224 // be sure m_pSource is freed
225 if (m_bIsInitialized
)
226 xmlFreeDoc( m_pSource
);
229 void TreeParser::Extract( const OString
& rPOFile
)
231 assert( m_bIsInitialized
);
232 PoOfstream
aPOStream( rPOFile
, PoOfstream::APP
);
233 if( !aPOStream
.isOpen() )
236 << "Treex error: Cannot open po file for extract: "
237 << rPOFile
<< std::endl
;
241 xmlNodePtr pRootNode
= xmlDocGetRootElement( m_pSource
);
243 m_pSource
, pRootNode
, reinterpret_cast<const xmlChar
*>("help_section"),
246 xmlFreeDoc( m_pSource
);
249 m_bIsInitialized
= false;
252 void TreeParser::Merge(
253 const OString
&rMergeSrc
, const OString
&rDestinationFile
,
254 const OString
&rXhpRoot
)
256 assert( m_bIsInitialized
);
258 const xmlNodePtr pRootNode
= xmlDocGetRootElement( m_pSource
);
259 std::unique_ptr
<MergeDataFile
> pMergeDataFile
;
260 if( m_sLang
!= "qtz" && m_sLang
!= "en-US" )
262 pMergeDataFile
.reset(new MergeDataFile(
263 rMergeSrc
, static_cast<OString
>( m_pSource
->name
), false, false ));
264 const std::vector
<OString
> vLanguages
= pMergeDataFile
->GetLanguages();
265 if( !vLanguages
.empty() && vLanguages
[0] != m_sLang
)
268 << ("Treex error: given language conflicts with language of"
271 << vLanguages
[0] << std::endl
;
276 m_pSource
, pRootNode
, reinterpret_cast<const xmlChar
*>("help_section"),
277 pMergeDataFile
.get(), m_sLang
, rXhpRoot
);
279 pMergeDataFile
.reset();
280 xmlSaveFile( rDestinationFile
.getStr(), m_pSource
);
281 xmlFreeDoc( m_pSource
);
283 m_bIsInitialized
= false;
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */