1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
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.
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).
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.
27 ************************************************************************/
30 #include "HelpCompiler.hxx"
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>
40 static void impl_sleep( sal_uInt32 nSec
)
46 osl::Thread::wait( aTime
);
49 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 bExtensionMode( in_bExtensionMode
)
56 xmlKeepBlanksDefaultValue
= 0;
59 xmlDocPtr
HelpCompiler::getSourceDocument(const fs::path
&filePath
)
61 static const char *params
[4 + 1];
62 static xsltStylesheetPtr cur
= NULL
;
67 res
= xmlParseFile(filePath
.native_file_string().c_str());
70 res
= xmlParseFile(filePath
.native_file_string().c_str());
77 static std::string
fsroot('\'' + src
.toUTF8() + '\'');
78 static std::string
esclang('\'' + lang
+ '\'');
80 xmlSubstituteEntitiesDefault(1);
81 xmlLoadExtDtdDefaultValue
= 1;
82 cur
= xsltParseStylesheetFile((const xmlChar
*)resEmbStylesheet
.native_file_string().c_str());
85 params
[nbparams
++] = "Language";
86 params
[nbparams
++] = esclang
.c_str();
87 params
[nbparams
++] = "fsroot";
88 params
[nbparams
++] = fsroot
.c_str();
89 params
[nbparams
] = NULL
;
91 xmlDocPtr doc
= xmlParseFile(filePath
.native_file_string().c_str());
95 doc
= xmlParseFile(filePath
.native_file_string().c_str());
98 //???res = xmlParseFile(filePath.native_file_string().c_str());
100 res
= xsltApplyStylesheet(cur
, doc
, params
);
106 HashSet
HelpCompiler::switchFind(xmlDocPtr doc
)
109 xmlChar
*xpath
= (xmlChar
*)"//switchinline";
111 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
112 xmlXPathObjectPtr result
= xmlXPathEvalExpression(xpath
, context
);
113 xmlXPathFreeContext(context
);
116 xmlNodeSetPtr nodeset
= result
->nodesetval
;
117 for (int i
= 0; i
< nodeset
->nodeNr
; i
++)
119 xmlNodePtr el
= nodeset
->nodeTab
[i
];
120 xmlChar
*select
= xmlGetProp(el
, (xmlChar
*)"select");
123 if (!strcmp((const char*)select
, "appl"))
125 xmlNodePtr n1
= el
->xmlChildrenNode
;
128 if ((!xmlStrcmp(n1
->name
, (const xmlChar
*)"caseinline")))
130 xmlChar
*appl
= xmlGetProp(n1
, (xmlChar
*)"select");
131 hs
.push_back(std::string((const char*)appl
));
134 else if ((!xmlStrcmp(n1
->name
, (const xmlChar
*)"defaultinline")))
135 hs
.push_back(std::string("DEFAULT"));
142 xmlXPathFreeObject(result
);
144 hs
.push_back(std::string("DEFAULT"));
148 // returns a node representing the whole stuff compiled for the current
150 xmlNodePtr
HelpCompiler::clone(xmlNodePtr node
, const std::string
& appl
)
152 xmlNodePtr parent
= xmlCopyNode(node
, 2);
153 xmlNodePtr n
= node
->xmlChildrenNode
;
157 if ( (!strcmp((const char*)n
->name
, "switchinline")) ||
158 (!strcmp((const char*)n
->name
, "switch")) )
160 xmlChar
*select
= xmlGetProp(n
, (xmlChar
*)"select");
163 if (!strcmp((const char*)select
, "appl"))
170 xmlNodePtr caseNode
= n
->xmlChildrenNode
;
171 if (appl
== "DEFAULT")
175 if (!strcmp((const char*)caseNode
->name
, "defaultinline"))
177 xmlNodePtr cnl
= caseNode
->xmlChildrenNode
;
180 xmlAddChild(parent
, clone(cnl
, appl
));
185 caseNode
= caseNode
->next
;
193 if (!strcmp((const char*)caseNode
->name
, "caseinline"))
195 xmlChar
*select
= xmlGetProp(n
, (xmlChar
*)"select");
198 if (!strcmp((const char*)select
, appl
.c_str()))
204 xmlNodePtr cnl
= caseNode
->xmlChildrenNode
;
207 xmlAddChild(parent
, clone(cnl
, appl
));
214 caseNode
= caseNode
->next
;
220 xmlAddChild(parent
, clone(n
, appl
));
230 std::string documentId
;
231 std::string fileName
;
235 Stringtable
*helptexts
;
237 HashSet extendedHelpText
;
239 myparser(const std::string
&indocumentId
, const std::string
&infileName
,
240 const std::string
&intitle
) : documentId(indocumentId
), fileName(infileName
),
243 hidlist
= new HashSet
;
244 keywords
= new Hashtable
;
245 helptexts
= new Stringtable
;
247 void traverse( xmlNodePtr parentNode
);
249 std::string
dump(xmlNodePtr node
);
252 std::string
myparser::dump(xmlNodePtr node
)
255 if (node
->xmlChildrenNode
)
257 xmlNodePtr list
= node
->xmlChildrenNode
;
264 if (xmlNodeIsText(node
))
266 xmlChar
*pContent
= xmlNodeGetContent(node
);
267 app
+= std::string((const char*)pContent
);
273 void trim(std::string
& str
)
275 std::string::size_type pos
= str
.find_last_not_of(' ');
276 if(pos
!= std::string::npos
)
279 pos
= str
.find_first_not_of(' ');
280 if(pos
!= std::string::npos
)
284 str
.erase(str
.begin(), str
.end());
287 void myparser::traverse( xmlNodePtr parentNode
)
289 // traverse all nodes that belong to the parent
291 for (test
= parentNode
->xmlChildrenNode
; test
; test
= test
->next
)
293 if (fileName
.empty() && !strcmp((const char*)test
->name
, "filename"))
295 xmlNodePtr node
= test
->xmlChildrenNode
;
296 if (xmlNodeIsText(node
))
298 xmlChar
*pContent
= xmlNodeGetContent(node
);
299 fileName
= std::string((const char*)pContent
);
303 else if (title
.empty() && !strcmp((const char*)test
->name
, "title"))
309 else if (!strcmp((const char*)test
->name
, "bookmark"))
311 xmlChar
*branchxml
= xmlGetProp(test
, (const xmlChar
*)"branch");
312 xmlChar
*idxml
= xmlGetProp(test
, (const xmlChar
*)"id");
313 std::string
branch((const char*)branchxml
);
314 std::string
anchor((const char*)idxml
);
320 if (branch
.find("hid") == 0)
322 size_t index
= branch
.find('/');
323 if (index
!= std::string::npos
)
325 hid
= branch
.substr(1 + index
);
326 // one shall serve as a documentId
327 if (documentId
.empty())
329 extendedHelpText
.push_back(hid
);
330 std::string foo
= anchor
.empty() ? hid
: hid
+ "#" + anchor
;
331 HCDBG(std::cerr
<< "hid pushback" << foo
<< std::endl
);
332 hidlist
->push_back( anchor
.empty() ? hid
: hid
+ "#" + anchor
);
337 else if (branch
.compare("index") == 0)
341 for (xmlNodePtr nd
= test
->xmlChildrenNode
; nd
; nd
= nd
->next
)
343 if (strcmp((const char*)nd
->name
, "bookmark_value"))
346 std::string embedded
;
347 xmlChar
*embeddedxml
= xmlGetProp(nd
, (const xmlChar
*)"embedded");
350 embedded
= std::string((const char*)embeddedxml
);
351 xmlFree (embeddedxml
);
352 std::transform (embedded
.begin(), embedded
.end(),
353 embedded
.begin(), tocharlower
);
356 bool isEmbedded
= !embedded
.empty() && embedded
.compare("true") == 0;
360 std::string keyword
= dump(nd
);
361 size_t keywordSem
= keyword
.find(';');
362 if (keywordSem
!= std::string::npos
)
365 keyword
.substr(0,keywordSem
);
368 keyword
.substr(1+keywordSem
);
370 keyword
= tmppre
+ ";" + tmppos
;
372 ll
.push_back(keyword
);
375 (*keywords
)[anchor
] = ll
;
377 else if (branch
.compare("contents") == 0)
379 // currently not used
382 else if (!strcmp((const char*)test
->name
, "ahelp"))
384 std::string text
= dump(test
);
388 HashSet::const_iterator aEnd
= extendedHelpText
.end();
389 for (HashSet::const_iterator iter
= extendedHelpText
.begin(); iter
!= aEnd
;
393 (*helptexts
)[name
] = text
;
395 extendedHelpText
.clear();
403 bool HelpCompiler::compile( void ) throw( HelpProcessingException
)
405 // we now have the jaroutputstream, which will contain the document.
406 // now determine the document as a dom tree in variable docResolved
408 xmlDocPtr docResolvedOrg
= getSourceDocument(inputFile
);
410 // now add path to the document
415 docResolvedOrg
= getSourceDocument(inputFile
);
416 if( !docResolvedOrg
)
418 std::stringstream aStrStream
;
419 aStrStream
<< "ERROR: file not existing: " << inputFile
.native_file_string().c_str() << std::endl
;
420 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
424 // now find all applications for which one has to compile
425 std::string documentId
;
426 std::string fileName
;
428 // returns all applications for which one has to compile
429 HashSet applications
= switchFind(docResolvedOrg
);
431 HashSet::const_iterator aEnd
= applications
.end();
432 for (HashSet::const_iterator aI
= applications
.begin(); aI
!= aEnd
; ++aI
)
434 std::string appl
= *aI
;
435 std::string modulename
= appl
;
436 if (modulename
[0] == 'S')
438 modulename
= modulename
.substr(1);
439 std::transform(modulename
.begin(), modulename
.end(), modulename
.begin(), tocharlower
);
441 if (modulename
!= "DEFAULT" && modulename
!= module
)
444 // returns a clone of the document with swich-cases resolved
445 xmlNodePtr docResolved
= clone(xmlDocGetRootElement(docResolvedOrg
), appl
);
446 myparser
aparser(documentId
, fileName
, title
);
447 aparser
.traverse(docResolved
);
449 documentId
= aparser
.documentId
;
450 fileName
= aparser
.fileName
;
451 title
= aparser
.title
;
453 HCDBG(std::cerr
<< documentId
<< " : " << fileName
<< " : " << title
<< std::endl
);
455 xmlDocPtr docResolvedDoc
= xmlCopyDoc(docResolvedOrg
, false);
456 xmlDocSetRootElement(docResolvedDoc
, docResolved
);
458 if (modulename
== "DEFAULT")
460 streamTable
.dropdefault();
461 streamTable
.default_doc
= docResolvedDoc
;
462 streamTable
.default_hidlist
= aparser
.hidlist
;
463 streamTable
.default_helptexts
= aparser
.helptexts
;
464 streamTable
.default_keywords
= aparser
.keywords
;
468 streamTable
.dropappl();
469 streamTable
.appl_doc
= docResolvedDoc
;
470 streamTable
.appl_hidlist
= aparser
.hidlist
;
471 streamTable
.appl_helptexts
= aparser
.helptexts
;
472 streamTable
.appl_keywords
= aparser
.keywords
;
474 } // end iteration over all applications
476 streamTable
.document_id
= documentId
;
477 streamTable
.document_path
= fileName
;
478 streamTable
.document_title
= title
;
479 std::string actMod
= module
;
480 if ( !bExtensionMode
&& !fileName
.empty())
482 if (fileName
.find("/text/") == 0)
484 int len
= strlen("/text/");
485 actMod
= fileName
.substr(len
);
486 actMod
= actMod
.substr(0, actMod
.find('/'));
489 streamTable
.document_module
= actMod
;
491 xmlFreeDoc(docResolvedOrg
);
497 rtl_TextEncoding
getThreadTextEncoding( void )
499 static bool bNeedsInit
= true;
500 static rtl_TextEncoding nThreadTextEncoding
;
504 nThreadTextEncoding
= osl_getThreadTextEncoding();
506 return nThreadTextEncoding
;
509 void create_directory(const fs::path indexDirName
)
512 std::cerr
<< "creating " <<
513 rtl::OUStringToOString(indexDirName
.data
, RTL_TEXTENCODING_UTF8
).getStr()
516 osl::Directory::createPath(indexDirName
.data
);
519 void copy(const fs::path
&src
, const fs::path
&dest
)
521 osl::File::copy(src
.data
, dest
.data
);
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */