Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include <iostream>
11 : #include <fstream>
12 : #include <cassert>
13 : #include <cstring>
14 :
15 : #include <libxml/tree.h>
16 : #include <libxml/parser.h>
17 : #include <libxml/xmlmemory.h>
18 : #include <libxml/xmlstring.h>
19 :
20 : #include "export.hxx"
21 : #include "common.hxx"
22 : #include "treemerge.hxx"
23 :
24 :
25 : namespace
26 : {
27 : //Write out an sdf line
28 0 : static void lcl_WriteSDF(
29 : std::ofstream &aSDFStream, const OString& rText, const OString& rPrj,
30 : const OString& rActFileName, const OString& rID, const OString& rType )
31 : {
32 0 : OString sOutput( rPrj ); sOutput += "\t";
33 0 : sOutput += rActFileName;
34 0 : sOutput += "\t0\t";
35 0 : sOutput += rType; sOutput += "\t";
36 0 : sOutput += rID; sOutput += "\t\t\t\t0\ten-US\t";
37 0 : sOutput += rText; sOutput += "\t\t\t\t";
38 0 : aSDFStream << sOutput.getStr() << std::endl;
39 0 : }
40 :
41 : //Convert xmlChar* to OString
42 0 : static OString lcl_xmlStrToOString( const xmlChar* pString )
43 : {
44 0 : xmlChar* pTemp = xmlStrdup( pString );
45 : OString sResult =
46 0 : static_cast<OString>(reinterpret_cast<sal_Char*>( pTemp ));
47 0 : xmlFree( pTemp );
48 0 : return sResult;
49 : }
50 :
51 : //Extract strings from nodes on all level recursively
52 0 : static void lcl_ExtractLevel(
53 : const xmlDocPtr pSource, const xmlNodePtr pRoot,
54 : const xmlChar* pNodeName, std::ofstream& rSDFStream,
55 : const OString& rPrj, const OString& rRoot )
56 : {
57 0 : if( !pRoot->children )
58 : {
59 0 : return;
60 : }
61 0 : for( xmlNodePtr pCurrent = pRoot->children->next;
62 : pCurrent; pCurrent = pCurrent->next)
63 : {
64 0 : if (!xmlStrcmp(pCurrent->name, pNodeName))
65 : {
66 0 : xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id"));
67 : xmlChar* pText =
68 0 : xmlGetProp(pCurrent, (const xmlChar*)("title"));
69 : lcl_WriteSDF(
70 : rSDFStream,
71 : lcl_xmlStrToOString( pText ),
72 : rPrj,
73 : common::pathnameToken(
74 : pSource->name, rRoot.getStr()),
75 : lcl_xmlStrToOString( pID ),
76 0 : lcl_xmlStrToOString( pNodeName ));
77 :
78 0 : xmlFree( pID );
79 0 : xmlFree( pText );
80 :
81 : lcl_ExtractLevel(
82 : pSource, pCurrent, (const xmlChar *)("node"),
83 0 : rSDFStream, rPrj, rRoot );
84 : }
85 : }
86 : }
87 :
88 : //Update id and content of the topic
89 0 : static xmlNodePtr lcl_UpdateTopic(
90 : const xmlNodePtr pCurrent, const OString& rXhpRoot )
91 : {
92 0 : xmlNodePtr pReturn = pCurrent;
93 0 : xmlChar* pID = xmlGetProp(pReturn, (const xmlChar*)("id"));
94 : const OString sID =
95 0 : lcl_xmlStrToOString( pID );
96 0 : xmlFree( pID );
97 :
98 0 : const sal_Int32 nFirstSlash = sID.indexOf("/");
99 : //Update id attribute of topic
100 : {
101 : OString sNewID =
102 : sID.copy( 0, nFirstSlash + 1 ) +
103 0 : rXhpRoot.copy( rXhpRoot.lastIndexOf("/") + 1 ) +
104 0 : sID.copy( sID.indexOf( "/", nFirstSlash + 1 ) );
105 : xmlSetProp(
106 : pReturn, (const xmlChar*)("id"),
107 0 : reinterpret_cast<const xmlChar*>(sNewID.getStr()));
108 : }
109 :
110 : const OString sXhpPath =
111 : rXhpRoot +
112 0 : sID.copy(sID.indexOf("/", nFirstSlash + 1));
113 0 : xmlDocPtr pXhpFile = xmlParseFile( sXhpPath.getStr() );
114 : //if xhpfile is missing than we put this topic into comment
115 0 : if ( !pXhpFile )
116 : {
117 0 : xmlNodePtr pTemp = pReturn;
118 : xmlChar* sNewID =
119 0 : xmlGetProp(pReturn, (const xmlChar*)("id"));
120 : xmlChar* sComment =
121 0 : xmlStrcat( xmlCharStrdup("removed "), sNewID );
122 0 : pReturn = xmlNewComment( sComment );
123 0 : xmlReplaceNode( pTemp, pReturn );
124 0 : xmlFree( pTemp );
125 0 : xmlFree( sNewID );
126 0 : xmlFree( sComment );
127 : }
128 : //update topic's content on the basis of xhpfile's title
129 : else
130 : {
131 0 : xmlNodePtr pXhpNode = xmlDocGetRootElement( pXhpFile );
132 0 : for( pXhpNode = pXhpNode->children;
133 : pXhpNode; pXhpNode = pXhpNode->children )
134 : {
135 0 : while( pXhpNode->type != XML_ELEMENT_NODE )
136 : {
137 0 : pXhpNode = pXhpNode->next;
138 : }
139 0 : if(!xmlStrcmp(pXhpNode->name, (const xmlChar *)("title")))
140 : {
141 : xmlChar* sTitle =
142 0 : xmlNodeListGetString(pXhpFile, pXhpNode->children, 1);
143 : OString sNewTitle =
144 : lcl_xmlStrToOString( sTitle ).
145 : replaceAll("$[officename]","%PRODUCTNAME").
146 0 : replaceAll("$[officeversion]","%PRODUCTVERSION");
147 : xmlNodeSetContent(
148 : pReturn,
149 : xmlEncodeSpecialChars( NULL,
150 : reinterpret_cast<const xmlChar*>(
151 0 : sNewTitle.getStr() )));
152 0 : xmlFree( sTitle );
153 0 : break;
154 : }
155 : }
156 0 : if( !pXhpNode )
157 : {
158 : std::cerr
159 0 : << "Treex error: Cannot find title in "
160 0 : << sXhpPath.getStr() << std::endl;
161 0 : return 0;
162 : }
163 0 : xmlFree( pXhpFile );
164 0 : xmlCleanupParser();
165 : }
166 0 : return pReturn;
167 : }
168 : //Localize title attribute of help_section and node tags
169 0 : static void lcl_MergeLevel(
170 : xmlDocPtr io_pSource, const xmlNodePtr pRoot,
171 : const xmlChar * pNodeName, MergeDataFile* pMergeDataFile,
172 : const OString& rLang, const OString& rXhpRoot )
173 : {
174 0 : if( !pRoot->children )
175 : {
176 0 : return;
177 : }
178 0 : for( xmlNodePtr pCurrent = pRoot->children;
179 : pCurrent; pCurrent = pCurrent->next)
180 : {
181 0 : if( !xmlStrcmp(pCurrent->name, pNodeName) )
182 : {
183 0 : if( pMergeDataFile )
184 : {
185 0 : xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id"));
186 : ResData aResData(
187 : "", lcl_xmlStrToOString( pID ),
188 0 : static_cast<OString>(io_pSource->name) );
189 0 : xmlFree( pID );
190 0 : aResData.sResTyp = lcl_xmlStrToOString( pNodeName );
191 : PFormEntrys* pEntrys =
192 0 : pMergeDataFile->GetPFormEntrys( &aResData );
193 0 : if( pEntrys )
194 : {
195 0 : OString sNewText;
196 0 : pEntrys->GetText( sNewText, STRING_TYP_TEXT, rLang );
197 : xmlSetProp(
198 : pCurrent, (const xmlChar*)("title"),
199 0 : (const xmlChar*)(sNewText.getStr()));
200 0 : }
201 : }
202 : lcl_MergeLevel(
203 : io_pSource, pCurrent, (const xmlChar *)("node"),
204 0 : pMergeDataFile, rLang, rXhpRoot );
205 : }
206 0 : else if( !xmlStrcmp(pCurrent->name, (const xmlChar *)("topic")) )
207 : {
208 0 : pCurrent = lcl_UpdateTopic( pCurrent, rXhpRoot );
209 : }
210 : }
211 : }
212 : }
213 :
214 : //Parse tree file
215 0 : TreeParser::TreeParser(
216 : const OString& rInputFile, const OString& rLang )
217 : : m_pSource( 0 )
218 : , m_sLang( rLang )
219 0 : , m_bIsInitialized( false )
220 : {
221 0 : m_pSource = xmlParseFile( rInputFile.getStr() );
222 0 : if ( !m_pSource ) {
223 : std::cerr
224 0 : << "Treex error: Cannot open source file: "
225 0 : << rInputFile.getStr() << std::endl;
226 0 : return;
227 : }
228 0 : if( !m_pSource->name )
229 : {
230 0 : m_pSource->name = new char[strlen(rInputFile.getStr())+1];
231 0 : strcpy( m_pSource->name, rInputFile.getStr() );
232 : }
233 0 : m_bIsInitialized = true;
234 : }
235 :
236 0 : TreeParser::~TreeParser()
237 : {
238 0 : }
239 :
240 : //Extract strings form source file
241 0 : void TreeParser::Extract(
242 : const OString& rSDFFile, const OString& rPrj, const OString& rRoot )
243 : {
244 : assert( m_bIsInitialized );
245 : std::ofstream aSDFStream(
246 0 : rSDFFile.getStr(), std::ios_base::out | std::ios_base::trunc );
247 0 : if( !aSDFStream.is_open() )
248 : {
249 : std::cerr
250 0 : << "Treex error: Cannot open sdffile for extract: "
251 0 : << rSDFFile.getStr() << std::endl;
252 0 : return;
253 : }
254 :
255 0 : xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
256 : lcl_ExtractLevel(
257 : m_pSource, pRootNode, (const xmlChar *)("help_section"),
258 0 : aSDFStream, rPrj, rRoot );
259 :
260 0 : xmlFreeDoc( m_pSource );
261 0 : xmlCleanupParser();
262 0 : aSDFStream.close();
263 0 : m_bIsInitialized = false;
264 : }
265 :
266 : //Merge strings to tree file and update reference to help files(xhp)
267 0 : void TreeParser::Merge(
268 : const OString &rMergeSrc, const OString &rDestinationFile,
269 : const OString &rXhpRoot )
270 : {
271 : assert( m_bIsInitialized );
272 :
273 0 : const xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource );
274 0 : if( m_sLang == "en-US" )
275 : {
276 : lcl_MergeLevel(
277 : m_pSource, pRootNode, (const xmlChar *)("help_section"),
278 0 : 0, m_sLang, rXhpRoot );
279 : }
280 : else
281 : {
282 : MergeDataFile aMergeDataFile(
283 0 : rMergeSrc, static_cast<OString>( m_pSource->name ), false, false );
284 0 : const std::vector<OString> vLanguages = aMergeDataFile.GetLanguages();
285 0 : if( vLanguages.size()>=2 &&
286 0 : vLanguages[vLanguages[0]=="qtz" ? 0 : 1] != m_sLang )
287 : {
288 : std::cerr
289 0 : << "Treex error: given language conflicts with "
290 0 : << "language of Mergedata file: "
291 0 : << m_sLang.getStr() << " - "
292 0 : << vLanguages[vLanguages[0]=="qtz" ? 0 : 1].getStr() << std::endl;
293 0 : return;
294 : }
295 : lcl_MergeLevel(
296 : m_pSource, pRootNode, (const xmlChar *)("help_section"),
297 0 : &aMergeDataFile, m_sLang, rXhpRoot );
298 : }
299 :
300 0 : xmlSaveFile( rDestinationFile.getStr(), m_pSource );
301 0 : xmlFreeDoc( m_pSource );
302 0 : xmlCleanupParser();
303 0 : m_bIsInitialized = false;
304 0 : }
305 :
306 :
307 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|