merge the formfield patch from ooo-build
[ooovba.git] / transex3 / source / help / HelpCompiler.cxx
blob2609606e6816c52388866a62c73d4321a7e22555
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: HelpCompiler.cxx,v $
10 * $Revision: 1.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 #include "HelpCompiler.hxx"
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <libxslt/xslt.h>
37 #include <libxslt/xsltInternals.h>
38 #include <libxslt/transform.h>
39 #include <libxslt/xsltutils.h>
40 #ifdef __MINGW32__
41 #include <tools/prewin.h>
42 #include <tools/postwin.h>
43 #endif
44 #include <osl/thread.hxx>
46 static void impl_sleep( sal_uInt32 nSec )
48 TimeValue aTime;
49 aTime.Seconds = nSec;
50 aTime.Nanosec = 0;
52 osl::Thread::wait( aTime );
55 HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile,
56 const fs::path &in_src, const fs::path &in_resEmbStylesheet,
57 const std::string &in_module, const std::string &in_lang, bool in_bExtensionMode)
58 : streamTable(in_streamTable), inputFile(in_inputFile),
59 src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet),
60 bExtensionMode( in_bExtensionMode )
62 xmlKeepBlanksDefaultValue = 0;
65 xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath)
67 static const char *params[4 + 1];
68 static xsltStylesheetPtr cur = NULL;
70 xmlDocPtr res;
71 if( bExtensionMode )
73 res = xmlParseFile(filePath.native_file_string().c_str());
74 if( !res ){
75 impl_sleep( 3 );
76 res = xmlParseFile(filePath.native_file_string().c_str());
79 else
81 if (!cur)
83 static std::string fsroot('\'' + src.toUTF8() + '\'');
84 static std::string esclang('\'' + lang + '\'');
86 xmlSubstituteEntitiesDefault(1);
87 xmlLoadExtDtdDefaultValue = 1;
88 cur = xsltParseStylesheetFile((const xmlChar *)resEmbStylesheet.native_file_string().c_str());
90 int nbparams = 0;
91 params[nbparams++] = "Language";
92 params[nbparams++] = esclang.c_str();
93 params[nbparams++] = "fsroot";
94 params[nbparams++] = fsroot.c_str();
95 params[nbparams] = NULL;
97 xmlDocPtr doc = xmlParseFile(filePath.native_file_string().c_str());
98 if( !doc )
100 impl_sleep( 3 );
101 doc = xmlParseFile(filePath.native_file_string().c_str());
104 //???res = xmlParseFile(filePath.native_file_string().c_str());
106 res = xsltApplyStylesheet(cur, doc, params);
107 xmlFreeDoc(doc);
109 return res;
112 HashSet HelpCompiler::switchFind(xmlDocPtr doc)
114 HashSet hs;
115 xmlChar *xpath = (xmlChar*)"//switchinline";
117 xmlXPathContextPtr context = xmlXPathNewContext(doc);
118 xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context);
119 xmlXPathFreeContext(context);
120 if (result)
122 xmlNodeSetPtr nodeset = result->nodesetval;
123 for (int i = 0; i < nodeset->nodeNr; i++)
125 xmlNodePtr el = nodeset->nodeTab[i];
126 xmlChar *select = xmlGetProp(el, (xmlChar*)"select");
127 if (select)
129 if (!strcmp((const char*)select, "appl"))
131 xmlNodePtr n1 = el->xmlChildrenNode;
132 while (n1)
134 if ((!xmlStrcmp(n1->name, (const xmlChar*)"caseinline")))
136 xmlChar *appl = xmlGetProp(n1, (xmlChar*)"select");
137 hs.push_back(std::string((const char*)appl));
138 xmlFree(appl);
140 else if ((!xmlStrcmp(n1->name, (const xmlChar*)"defaultinline")))
141 hs.push_back(std::string("DEFAULT"));
142 n1 = n1->next;
145 xmlFree(select);
148 xmlXPathFreeObject(result);
150 hs.push_back(std::string("DEFAULT"));
151 return hs;
154 // returns a node representing the whole stuff compiled for the current
155 // application.
156 xmlNodePtr HelpCompiler::clone(xmlNodePtr node, const std::string& appl)
158 xmlNodePtr parent = xmlCopyNode(node, 2);
159 xmlNodePtr n = node->xmlChildrenNode;
160 while (n != NULL)
162 bool isappl = false;
163 if ( (!strcmp((const char*)n->name, "switchinline")) ||
164 (!strcmp((const char*)n->name, "switch")) )
166 xmlChar *select = xmlGetProp(n, (xmlChar*)"select");
167 if (select)
169 if (!strcmp((const char*)select, "appl"))
170 isappl = true;
171 xmlFree(select);
174 if (isappl)
176 xmlNodePtr caseNode = n->xmlChildrenNode;
177 if (appl == "DEFAULT")
179 while (caseNode)
181 if (!strcmp((const char*)caseNode->name, "defaultinline"))
183 xmlNodePtr cnl = caseNode->xmlChildrenNode;
184 while (cnl)
186 xmlAddChild(parent, clone(cnl, appl));
187 cnl = cnl->next;
189 break;
191 caseNode = caseNode->next;
194 else
196 while (caseNode)
198 isappl=false;
199 if (!strcmp((const char*)caseNode->name, "caseinline"))
201 xmlChar *select = xmlGetProp(n, (xmlChar*)"select");
202 if (select)
204 if (!strcmp((const char*)select, appl.c_str()))
205 isappl = true;
206 xmlFree(select);
208 if (isappl)
210 xmlNodePtr cnl = caseNode->xmlChildrenNode;
211 while (cnl)
213 xmlAddChild(parent, clone(cnl, appl));
214 cnl = cnl->next;
216 break;
220 caseNode = caseNode->next;
225 else
226 xmlAddChild(parent, clone(n, appl));
228 n = n->next;
230 return parent;
233 class myparser
235 public:
236 std::string documentId;
237 std::string fileName;
238 std::string title;
239 HashSet *hidlist;
240 Hashtable *keywords;
241 Stringtable *helptexts;
242 private:
243 HashSet extendedHelpText;
244 public:
245 myparser(const std::string &indocumentId, const std::string &infileName,
246 const std::string &intitle) : documentId(indocumentId), fileName(infileName),
247 title(intitle)
249 hidlist = new HashSet;
250 keywords = new Hashtable;
251 helptexts = new Stringtable;
253 void traverse( xmlNodePtr parentNode );
254 private:
255 std::string dump(xmlNodePtr node);
258 std::string myparser::dump(xmlNodePtr node)
260 std::string app;
261 if (node->xmlChildrenNode)
263 xmlNodePtr list = node->xmlChildrenNode;
264 while (list)
266 app += dump(list);
267 list = list->next;
270 if (xmlNodeIsText(node))
272 xmlChar *pContent = xmlNodeGetContent(node);
273 app += std::string((const char*)pContent);
274 xmlFree(pContent);
275 // std::cout << app << std::endl;
277 return app;
280 void trim(std::string& str)
282 std::string::size_type pos = str.find_last_not_of(' ');
283 if(pos != std::string::npos)
285 str.erase(pos + 1);
286 pos = str.find_first_not_of(' ');
287 if(pos != std::string::npos)
288 str.erase(0, pos);
290 else
291 str.erase(str.begin(), str.end());
294 void myparser::traverse( xmlNodePtr parentNode )
296 // traverse all nodes that belong to the parent
297 xmlNodePtr test ;
298 for (test = parentNode->xmlChildrenNode; test; test = test->next)
300 if (fileName.empty() && !strcmp((const char*)test->name, "filename"))
302 xmlNodePtr node = test->xmlChildrenNode;
303 if (xmlNodeIsText(node))
305 xmlChar *pContent = xmlNodeGetContent(node);
306 fileName = std::string((const char*)pContent);
307 xmlFree(pContent);
310 else if (title.empty() && !strcmp((const char*)test->name, "title"))
312 title = dump(test);
313 if (title.empty())
314 title = "<notitle>";
316 else if (!strcmp((const char*)test->name, "bookmark"))
318 xmlChar *branchxml = xmlGetProp(test, (const xmlChar*)"branch");
319 xmlChar *idxml = xmlGetProp(test, (const xmlChar*)"id");
320 std::string branch((const char*)branchxml);
321 std::string anchor((const char*)idxml);
322 xmlFree (branchxml);
323 xmlFree (idxml);
325 std::string hid;
327 if (branch.find("hid") == 0)
329 size_t index = branch.find('/');
330 if (index != std::string::npos)
332 hid = branch.substr(1 + index);
333 // one shall serve as a documentId
334 if (documentId.empty())
335 documentId = hid;
336 extendedHelpText.push_back(hid);
337 std::string foo = anchor.empty() ? hid : hid + "#" + anchor;
338 HCDBG(std::cerr << "hid pushback" << foo << std::endl);
339 hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor);
341 else
342 continue;
344 else if (branch.compare("index") == 0)
346 LinkedList ll;
348 for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next)
350 if (strcmp((const char*)nd->name, "bookmark_value"))
351 continue;
353 std::string embedded;
354 xmlChar *embeddedxml = xmlGetProp(nd, (const xmlChar*)"embedded");
355 if (embeddedxml)
357 embedded = std::string((const char*)embeddedxml);
358 xmlFree (embeddedxml);
359 std::transform (embedded.begin(), embedded.end(),
360 embedded.begin(), tolower);
363 bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0;
364 if (isEmbedded)
365 continue;
367 std::string keyword = dump(nd);
368 size_t keywordSem = keyword.find(';');
369 if (keywordSem != std::string::npos)
371 std::string tmppre =
372 keyword.substr(0,keywordSem);
373 trim(tmppre);
374 std::string tmppos =
375 keyword.substr(1+keywordSem);
376 trim(tmppos);
377 keyword = tmppre + ";" + tmppos;
379 ll.push_back(keyword);
381 if (!ll.empty())
382 (*keywords)[anchor] = ll;
384 else if (branch.compare("contents") == 0)
386 // currently not used
389 else if (!strcmp((const char*)test->name, "ahelp"))
391 std::string text = dump(test);
392 trim(text);
393 std::string name;
395 HashSet::const_iterator aEnd = extendedHelpText.end();
396 for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd;
397 ++iter)
399 name = *iter;
400 (*helptexts)[name] = text;
402 extendedHelpText.clear();
405 // traverse children
406 traverse(test);
410 bool HelpCompiler::compile( void ) throw( HelpProcessingException )
412 // we now have the jaroutputstream, which will contain the document.
413 // now determine the document as a dom tree in variable docResolved
415 xmlDocPtr docResolvedOrg = getSourceDocument(inputFile);
417 // now add path to the document
418 // resolve the dom
419 if (!docResolvedOrg)
421 impl_sleep( 3 );
422 docResolvedOrg = getSourceDocument(inputFile);
423 if( !docResolvedOrg )
425 std::stringstream aStrStream;
426 aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl;
427 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
431 // now find all applications for which one has to compile
432 std::string documentId;
433 std::string fileName;
434 std::string title;
435 // returns all applications for which one has to compile
436 HashSet applications = switchFind(docResolvedOrg);
438 HashSet::const_iterator aEnd = applications.end();
439 for (HashSet::const_iterator aI = applications.begin(); aI != aEnd; ++aI)
441 std::string appl = *aI;
442 std::string modulename = appl;
443 if (modulename[0] == 'S')
445 modulename = modulename.substr(1);
446 std::transform(modulename.begin(), modulename.end(), modulename.begin(), tolower);
448 if (modulename != "DEFAULT" && modulename != module)
449 continue;
451 // returns a clone of the document with swich-cases resolved
452 xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl);
453 myparser aparser(documentId, fileName, title);
454 aparser.traverse(docResolved);
456 documentId = aparser.documentId;
457 fileName = aparser.fileName;
458 title = aparser.title;
460 HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl);
462 xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false);
463 xmlDocSetRootElement(docResolvedDoc, docResolved);
465 if (modulename == "DEFAULT")
467 streamTable.dropdefault();
468 streamTable.default_doc = docResolvedDoc;
469 streamTable.default_hidlist = aparser.hidlist;
470 streamTable.default_helptexts = aparser.helptexts;
471 streamTable.default_keywords = aparser.keywords;
473 else if (modulename == module)
475 streamTable.dropappl();
476 streamTable.appl_doc = docResolvedDoc;
477 streamTable.appl_hidlist = aparser.hidlist;
478 streamTable.appl_helptexts = aparser.helptexts;
479 streamTable.appl_keywords = aparser.keywords;
481 else
483 std::stringstream aStrStream;
484 aStrStream << "ERROR: Found unexpected module name \"" << modulename
485 << "\" in file" << src.native_file_string().c_str() << std::endl;
486 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
489 } // end iteration over all applications
491 streamTable.document_id = documentId;
492 streamTable.document_path = fileName;
493 streamTable.document_title = title;
494 std::string actMod = module;
495 if ( !bExtensionMode && !fileName.empty())
497 if (fileName.find("/text/") == 0)
499 int len = strlen("/text/");
500 actMod = fileName.substr(len);
501 actMod = actMod.substr(0, actMod.find('/'));
504 streamTable.document_module = actMod;
506 xmlFreeDoc(docResolvedOrg);
507 return true;
510 namespace fs
512 rtl_TextEncoding getThreadTextEncoding( void )
514 static bool bNeedsInit = true;
515 static rtl_TextEncoding nThreadTextEncoding;
516 if( bNeedsInit )
518 bNeedsInit = false;
519 nThreadTextEncoding = osl_getThreadTextEncoding();
521 return nThreadTextEncoding;
524 void create_directory(const fs::path indexDirName)
526 HCDBG(
527 std::cerr << "creating " <<
528 rtl::OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr()
529 << std::endl
531 osl::Directory::createPath(indexDirName.data);
534 void rename(const fs::path &src, const fs::path &dest)
536 osl::File::move(src.data, dest.data);
539 void copy(const fs::path &src, const fs::path &dest)
541 osl::File::copy(src.data, dest.data);
544 bool exists(const fs::path &in)
546 osl::File tmp(in.data);
547 return (tmp.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None);
550 void remove(const fs::path &in)
552 osl::File::remove(in.data);
555 void removeRecursive(rtl::OUString const& _suDirURL)
558 osl::Directory aDir(_suDirURL);
559 aDir.open();
560 if (aDir.isOpen())
562 osl::DirectoryItem aItem;
563 osl::FileStatus aStatus(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes);
564 while (aDir.getNextItem(aItem) == ::osl::FileBase::E_None)
566 if (osl::FileBase::E_None == aItem.getFileStatus(aStatus) &&
567 aStatus.isValid(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes))
569 rtl::OUString suFilename = aStatus.getFileName();
570 rtl::OUString suFullFileURL;
571 suFullFileURL += _suDirURL;
572 suFullFileURL += rtl::OUString::createFromAscii("/");
573 suFullFileURL += suFilename;
575 if (aStatus.getFileType() == osl::FileStatus::Directory)
576 removeRecursive(suFullFileURL);
577 else
578 osl::File::remove(suFullFileURL);
581 aDir.close();
584 osl::Directory::remove(_suDirURL);
587 void remove_all(const fs::path &in)
589 removeRecursive(in.data);
593 /* vi:set tabstop=4 shiftwidth=4 expandtab: */