Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "HelpCompiler.hxx"
31 : : #include <limits.h>
32 : : #include <stdlib.h>
33 : : #include <string.h>
34 : : #include <libxslt/xslt.h>
35 : : #include <libxslt/xsltInternals.h>
36 : : #include <libxslt/transform.h>
37 : : #include <libxslt/xsltutils.h>
38 : : #include <osl/thread.hxx>
39 : :
40 : 0 : static void impl_sleep( sal_uInt32 nSec )
41 : : {
42 : : TimeValue aTime;
43 : 0 : aTime.Seconds = nSec;
44 : 0 : aTime.Nanosec = 0;
45 : :
46 [ # # ]: 0 : osl::Thread::wait( aTime );
47 : 0 : }
48 : :
49 : 8981 : HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile,
50 : : const fs::path &in_src, const fs::path &in_resEmbStylesheet,
51 : : const std::string &in_module, const std::string &in_lang, bool in_bExtensionMode)
52 : : : streamTable(in_streamTable), inputFile(in_inputFile),
53 : : src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet),
54 [ + - ][ + - ]: 8981 : bExtensionMode( in_bExtensionMode )
[ + - ]
55 : : {
56 [ + - ]: 8981 : xmlKeepBlanksDefaultValue = 0;
57 : 8981 : char* guitmp = getenv("GUI");
58 [ + - ]: 8981 : if (guitmp)
59 : : {
60 [ - + ][ # # ]: 8981 : gui = (strcmp(guitmp, "UNX") ? gui : "UNIX");
[ + - ][ + - ]
[ + - ][ # # ]
61 [ + - ][ + - ]: 8981 : gui = (strcmp(guitmp, "MAC") ? gui : "MAC");
[ # # ][ + - ]
[ - + ][ # # ]
62 [ + - ][ + - ]: 8981 : gui = (strcmp(guitmp, "WNT") ? gui : "WIN");
[ # # ][ + - ]
[ - + ][ # # ]
63 : : }
64 : 8981 : }
65 : :
66 : 8981 : xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath)
67 : : {
68 : : static const char *params[4 + 1];
69 : : static xsltStylesheetPtr cur = NULL;
70 : :
71 : : xmlDocPtr res;
72 [ + + ]: 8981 : if( bExtensionMode )
73 : : {
74 [ + - ]: 62 : res = xmlParseFile(filePath.native_file_string().c_str());
75 [ - + ]: 62 : if( !res ){
76 : 0 : impl_sleep( 3 );
77 [ # # ]: 0 : res = xmlParseFile(filePath.native_file_string().c_str());
78 : : }
79 : : }
80 : : else
81 : : {
82 [ + + ]: 8919 : if (!cur)
83 : : {
84 [ + - ][ + - ]: 8 : static std::string fsroot('\'' + src.toUTF8() + '\'');
[ + - ][ + - ]
[ + - ][ # # ]
85 [ + - ][ + - ]: 8 : static std::string esclang('\'' + lang + '\'');
[ + - ][ + - ]
[ # # ]
86 : :
87 : 8 : xmlSubstituteEntitiesDefault(1);
88 : 8 : xmlLoadExtDtdDefaultValue = 1;
89 [ + - ]: 8 : cur = xsltParseStylesheetFile((const xmlChar *)resEmbStylesheet.native_file_string().c_str());
90 : :
91 : 8 : int nbparams = 0;
92 : 8 : params[nbparams++] = "Language";
93 : 8 : params[nbparams++] = esclang.c_str();
94 : 8 : params[nbparams++] = "fsroot";
95 : 8 : params[nbparams++] = fsroot.c_str();
96 : 8 : params[nbparams] = NULL;
97 : : }
98 [ + - ]: 8919 : xmlDocPtr doc = xmlParseFile(filePath.native_file_string().c_str());
99 [ - + ]: 8919 : if( !doc )
100 : : {
101 : 0 : impl_sleep( 3 );
102 [ # # ]: 0 : doc = xmlParseFile(filePath.native_file_string().c_str());
103 : : }
104 : :
105 : : //???res = xmlParseFile(filePath.native_file_string().c_str());
106 : :
107 : 8919 : res = xsltApplyStylesheet(cur, doc, params);
108 : 8919 : xmlFreeDoc(doc);
109 : : }
110 : 8981 : return res;
111 : : }
112 : :
113 : : // returns a node representing the whole stuff compiled for the current
114 : : // application.
115 : 947733 : xmlNodePtr HelpCompiler::clone(xmlNodePtr node, const std::string& appl)
116 : : {
117 : 947733 : xmlNodePtr root = xmlCopyNode(node, 2);
118 [ + + ]: 947733 : if (node->xmlChildrenNode)
119 : : {
120 : 538590 : xmlNodePtr list = node->xmlChildrenNode;
121 [ + + ]: 1481734 : while (list)
122 : : {
123 [ + + ][ + + ]: 943144 : if (strcmp((const char*)list->name, "switchinline") == 0 || strcmp((const char*)list->name, "switch") == 0)
124 : : {
125 [ + - ]: 11367 : std::string tmp="";
126 [ + + ][ + - ]: 11367 : if (strcmp((const char*)xmlGetProp(list, (xmlChar*)"select"), "sys"))
127 : : {
128 [ + - ]: 5532 : tmp = gui;
129 : : }
130 [ + - ][ + + ]: 11367 : if (strcmp((const char*)xmlGetProp(list, (xmlChar*)"select"), "appl"))
131 : : {
132 [ + - ]: 5835 : tmp = appl;
133 : : }
134 [ + - ][ + - ]: 11367 : if (tmp.compare("") != 0)
135 : : {
136 : 11367 : bool isCase=false;
137 : 11367 : xmlNodePtr caseList=list->xmlChildrenNode;
138 [ + + ]: 30440 : while (caseList)
139 : : {
140 [ + - ]: 19073 : xmlChar *select = xmlGetProp(caseList, (xmlChar*)"select");
141 [ + + ]: 19073 : if (select)
142 : : {
143 [ - + ][ # # ]: 12743 : if (!strcmp((const char*)select, tmp.c_str()) && !isCase)
[ - + ]
144 : : {
145 : 0 : isCase=true;
146 : 0 : xmlNodePtr clp = caseList->xmlChildrenNode;
147 [ # # ]: 0 : while (clp)
148 : : {
149 [ # # ][ # # ]: 0 : xmlAddChild(root, clone(clp, appl));
150 : 0 : clp = clp->next;
151 : : }
152 : : }
153 [ + - ]: 12743 : xmlFree(select);
154 : : }
155 : : else
156 : : {
157 [ + + ][ - + ]: 6330 : if ((strcmp((const char*)caseList->name, "defaultinline") != 0) && (strcmp((const char*)caseList->name, "default") != 0))
158 : : {
159 [ # # ][ # # ]: 0 : xmlAddChild(root, clone(caseList, appl));
160 : : }
161 : : else
162 : : {
163 [ + - ]: 6330 : if (!isCase)
164 : : {
165 : 6330 : xmlNodePtr clp = caseList->xmlChildrenNode;
166 [ + + ]: 13305 : while (clp)
167 : : {
168 [ + - ][ + - ]: 6975 : xmlAddChild(root, clone(clp, appl));
169 : 6975 : clp = clp->next;
170 : : }
171 : : }
172 : : }
173 : : }
174 : 19073 : caseList = caseList->next;
175 : : }
176 : 11367 : }
177 : : }
178 : : else
179 : : {
180 : 931777 : xmlAddChild(root, clone(list, appl));
181 : : }
182 : 943144 : list = list->next;
183 : : }
184 : : }
185 : 947733 : return root;
186 : : }
187 : :
188 : 8981 : class myparser
189 : : {
190 : : public:
191 : : std::string documentId;
192 : : std::string fileName;
193 : : std::string title;
194 : : HashSet *hidlist;
195 : : Hashtable *keywords;
196 : : Stringtable *helptexts;
197 : : private:
198 : : HashSet extendedHelpText;
199 : : public:
200 : 8981 : myparser(const std::string &indocumentId, const std::string &infileName,
201 : : const std::string &intitle) : documentId(indocumentId), fileName(infileName),
202 [ + - ][ + - ]: 8981 : title(intitle)
[ + - ][ + - ]
203 : : {
204 [ + - ][ + - ]: 8981 : hidlist = new HashSet;
205 [ + - ][ + - ]: 8981 : keywords = new Hashtable;
206 [ + - ][ + - ]: 8981 : helptexts = new Stringtable;
207 : 8981 : }
208 : : void traverse( xmlNodePtr parentNode );
209 : : private:
210 : : std::string module;
211 : : std::string dump(xmlNodePtr node);
212 : : };
213 : :
214 : 141196 : std::string myparser::dump(xmlNodePtr node)
215 : : {
216 : 141196 : std::string app;
217 [ + + ]: 141196 : if (node->xmlChildrenNode)
218 : : {
219 : 67664 : xmlNodePtr list = node->xmlChildrenNode;
220 [ + + ]: 147053 : while (list)
221 : : {
222 [ + - ][ + - ]: 79389 : app += dump(list);
223 : 79389 : list = list->next;
224 : : }
225 : : }
226 [ + - ][ + + ]: 141196 : if (xmlNodeIsText(node))
227 : : {
228 [ + - ]: 73343 : xmlChar *pContent = xmlNodeGetContent(node);
229 [ + - ][ + - ]: 73343 : app += std::string((const char*)pContent);
230 [ + - ]: 73343 : xmlFree(pContent);
231 : : }
232 : 141196 : return app;
233 : : }
234 : :
235 : 61370 : void trim(std::string& str)
236 : : {
237 : 61370 : std::string::size_type pos = str.find_last_not_of(' ');
238 [ + + ]: 61370 : if(pos != std::string::npos)
239 : : {
240 : 61193 : str.erase(pos + 1);
241 : 61193 : pos = str.find_first_not_of(' ');
242 [ + - ]: 61193 : if(pos != std::string::npos)
243 : 61193 : str.erase(0, pos);
244 : : }
245 : : else
246 : 177 : str.erase(str.begin(), str.end());
247 : 61370 : }
248 : :
249 : 940582 : void myparser::traverse( xmlNodePtr parentNode )
250 : : {
251 : : // traverse all nodes that belong to the parent
252 : : xmlNodePtr test ;
253 [ + + ]: 1872183 : for (test = parentNode->xmlChildrenNode; test; test = test->next)
254 : : {
255 [ + + ][ + + ]: 931601 : if (fileName.empty() && !strcmp((const char*)test->name, "filename"))
[ + + ]
256 : : {
257 : 8981 : xmlNodePtr node = test->xmlChildrenNode;
258 [ + - ]: 8981 : if (xmlNodeIsText(node))
259 : : {
260 : 8981 : xmlChar *pContent = xmlNodeGetContent(node);
261 [ + - ][ + - ]: 8981 : fileName = std::string((const char*)pContent);
262 : 8981 : xmlFree(pContent);
263 : : }
264 : : }
265 [ + + ][ + + ]: 922620 : else if (title.empty() && !strcmp((const char*)test->name, "title"))
[ + + ]
266 : : {
267 [ + - ]: 8981 : title = dump(test);
268 [ + + ]: 8981 : if (title.empty())
269 : 8 : title = "<notitle>";
270 : : }
271 [ + + ]: 913639 : else if (!strcmp((const char*)test->name, "bookmark"))
272 : : {
273 [ + - ]: 46601 : xmlChar *branchxml = xmlGetProp(test, (const xmlChar*)"branch");
274 [ + - ]: 46601 : xmlChar *idxml = xmlGetProp(test, (const xmlChar*)"id");
275 [ + - ]: 46601 : std::string branch((const char*)branchxml);
276 [ + - ]: 46601 : std::string anchor((const char*)idxml);
277 [ + - ]: 46601 : xmlFree (branchxml);
278 [ + - ]: 46601 : xmlFree (idxml);
279 : :
280 [ + - ]: 46601 : std::string hid;
281 : :
282 [ + - ][ + + ]: 46601 : if (branch.find("hid") == 0)
283 : : {
284 : 41695 : size_t index = branch.find('/');
285 [ + - ]: 41695 : if (index != std::string::npos)
286 : : {
287 [ + - ][ + - ]: 41695 : hid = branch.substr(1 + index);
288 : : // one shall serve as a documentId
289 [ + + ]: 41695 : if (documentId.empty())
290 [ + - ]: 6096 : documentId = hid;
291 [ + - ]: 41695 : extendedHelpText.push_back(hid);
292 [ - + ][ # # ]: 41695 : std::string foo = anchor.empty() ? hid : hid + "#" + anchor;
[ + - ][ + - ]
[ + - ][ # # ]
293 : : HCDBG(std::cerr << "hid pushback" << foo << std::endl);
294 [ - + ][ # # ]: 41695 : hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor);
[ + - ][ + - ]
[ + - ][ + - ]
[ # # ]
295 : : }
296 : : else
297 : 0 : continue;
298 : : }
299 [ + - ][ + - ]: 4906 : else if (branch.compare("index") == 0)
300 : : {
301 [ + - ]: 4906 : LinkedList ll;
302 : :
303 [ + + ]: 23840 : for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next)
304 : : {
305 [ - + ]: 18934 : if (strcmp((const char*)nd->name, "bookmark_value"))
306 : 0 : continue;
307 : :
308 [ + - ]: 18934 : std::string embedded;
309 [ + - ]: 18934 : xmlChar *embeddedxml = xmlGetProp(nd, (const xmlChar*)"embedded");
310 [ - + ]: 18934 : if (embeddedxml)
311 : : {
312 [ # # ][ # # ]: 0 : embedded = std::string((const char*)embeddedxml);
313 [ # # ]: 0 : xmlFree (embeddedxml);
314 : : std::transform (embedded.begin(), embedded.end(),
315 [ # # ]: 0 : embedded.begin(), tocharlower);
316 : : }
317 : :
318 [ - + ][ # # ]: 18934 : bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0;
[ # # ]
319 [ - + ]: 18934 : if (isEmbedded)
320 : 0 : continue;
321 : :
322 [ + - ]: 18934 : std::string keyword = dump(nd);
323 : 18934 : size_t keywordSem = keyword.find(';');
324 [ + + ]: 18934 : if (keywordSem != std::string::npos)
325 : : {
326 : : std::string tmppre =
327 [ + - ]: 13739 : keyword.substr(0,keywordSem);
328 [ + - ]: 13739 : trim(tmppre);
329 : : std::string tmppos =
330 [ + - ]: 13739 : keyword.substr(1+keywordSem);
331 [ + - ]: 13739 : trim(tmppos);
332 [ + - ][ + - ]: 13739 : keyword = tmppre + ";" + tmppos;
[ + - ]
333 : : }
334 [ + - ]: 18934 : ll.push_back(keyword);
335 [ + - ]: 18934 : }
336 [ + - ]: 4906 : if (!ll.empty())
337 [ + - ][ + - ]: 4906 : (*keywords)[anchor] = ll;
338 : : }
339 [ # # ]: 46601 : else if (branch.compare("contents") == 0)
340 : : {
341 : : // currently not used
342 [ - + ][ - + ]: 46601 : }
[ + - ]
343 : : }
344 [ + + ]: 867038 : else if (!strcmp((const char*)test->name, "ahelp"))
345 : : {
346 [ + - ]: 33892 : std::string text = dump(test);
347 [ + - ]: 33892 : trim(text);
348 [ + - ]: 33892 : std::string name;
349 : :
350 [ + - ]: 33892 : HashSet::const_iterator aEnd = extendedHelpText.end();
351 [ + - ][ + - ]: 75169 : for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd; ++iter)
[ + - ][ + + ]
352 : : {
353 [ + - ][ + - ]: 41277 : name = *iter;
354 [ + - ][ + - ]: 41277 : (*helptexts)[name] = text;
355 : : }
356 : 33892 : extendedHelpText.clear();
357 : : }
358 : : // traverse children
359 : 931601 : traverse(test);
360 : : }
361 : 940582 : }
362 : :
363 : 8981 : bool HelpCompiler::compile( void ) throw( HelpProcessingException )
364 : : {
365 : : // we now have the jaroutputstream, which will contain the document.
366 : : // now determine the document as a dom tree in variable docResolved
367 : :
368 [ + - ]: 8981 : xmlDocPtr docResolvedOrg = getSourceDocument(inputFile);
369 : :
370 : : // now add path to the document
371 : : // resolve the dom
372 : :
373 [ - + ]: 8981 : if (!docResolvedOrg)
374 : : {
375 [ # # ]: 0 : impl_sleep( 3 );
376 [ # # ]: 0 : docResolvedOrg = getSourceDocument(inputFile);
377 [ # # ]: 0 : if( !docResolvedOrg )
378 : : {
379 [ # # ]: 0 : std::stringstream aStrStream;
380 [ # # ][ # # ]: 0 : aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl;
[ # # ][ # # ]
381 [ # # ][ # # ]: 0 : throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
382 : : }
383 : : }
384 : :
385 [ + - ]: 8981 : std::string documentId;
386 [ + - ]: 8981 : std::string fileName;
387 [ + - ]: 8981 : std::string title;
388 : : // returns a clone of the document with switch-cases resolved
389 [ + - ]: 8981 : std::string appl = module.substr(1);
390 [ + + ]: 56710 : for (unsigned int i = 0; i < appl.length(); ++i)
391 : : {
392 [ + - ][ + - ]: 47729 : appl[i]=toupper(appl[i]);
393 : : }
394 [ + - ][ + - ]: 8981 : xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl);
395 [ + - ]: 8981 : myparser aparser(documentId, fileName, title);
396 [ + - ]: 8981 : aparser.traverse(docResolved);
397 [ + - ]: 8981 : documentId = aparser.documentId;
398 [ + - ]: 8981 : fileName = aparser.fileName;
399 [ + - ]: 8981 : title = aparser.title;
400 : :
401 : : HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl);
402 : :
403 [ + - ]: 8981 : xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false);
404 [ + - ]: 8981 : xmlDocSetRootElement(docResolvedDoc, docResolved);
405 : :
406 [ + - ]: 8981 : streamTable.dropappl();
407 : 8981 : streamTable.appl_doc = docResolvedDoc;
408 : 8981 : streamTable.appl_hidlist = aparser.hidlist;
409 : 8981 : streamTable.appl_helptexts = aparser.helptexts;
410 : 8981 : streamTable.appl_keywords = aparser.keywords;
411 : :
412 [ + - ]: 8981 : streamTable.document_id = documentId;
413 [ + - ]: 8981 : streamTable.document_path = fileName;
414 [ + - ]: 8981 : streamTable.document_title = title;
415 [ + - ]: 8981 : std::string actMod = module;
416 : :
417 [ + + ][ + - ]: 8981 : if ( !bExtensionMode && !fileName.empty())
[ + + ]
418 : : {
419 [ + - ][ + - ]: 8919 : if (fileName.find("/text/") == 0)
420 : : {
421 : 8919 : int len = strlen("/text/");
422 [ + - ][ + - ]: 8919 : actMod = fileName.substr(len);
423 [ + - ][ + - ]: 8919 : actMod = actMod.substr(0, actMod.find('/'));
424 : : }
425 : : }
426 [ + - ]: 8981 : streamTable.document_module = actMod;
427 [ + - ]: 8981 : xmlFreeDoc(docResolvedOrg);
428 : 8981 : return true;
429 : : }
430 : :
431 : : namespace fs
432 : : {
433 : 81129 : rtl_TextEncoding getThreadTextEncoding( void )
434 : : {
435 : : static bool bNeedsInit = true;
436 : : static rtl_TextEncoding nThreadTextEncoding;
437 [ + + ]: 81129 : if( bNeedsInit )
438 : : {
439 : 71 : bNeedsInit = false;
440 : 71 : nThreadTextEncoding = osl_getThreadTextEncoding();
441 : : }
442 : 81129 : return nThreadTextEncoding;
443 : : }
444 : :
445 : 149 : void create_directory(const fs::path indexDirName)
446 : : {
447 : : HCDBG(
448 : : std::cerr << "creating " <<
449 : : rtl::OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr()
450 : : << std::endl
451 : : );
452 : 149 : osl::Directory::createPath(indexDirName.data);
453 : 149 : }
454 : :
455 : 30 : void copy(const fs::path &src, const fs::path &dest)
456 : : {
457 : 30 : osl::File::copy(src.data, dest.data);
458 : 30 : }
459 : : }
460 : :
461 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|