1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: HelpCompiler.cxx,v $
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"
36 #include <libxslt/xslt.h>
37 #include <libxslt/xsltInternals.h>
38 #include <libxslt/transform.h>
39 #include <libxslt/xsltutils.h>
41 #include <tools/prewin.h>
42 #include <tools/postwin.h>
44 #include <osl/thread.hxx>
46 static void impl_sleep( sal_uInt32 nSec
)
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
;
73 res
= xmlParseFile(filePath
.native_file_string().c_str());
76 res
= xmlParseFile(filePath
.native_file_string().c_str());
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());
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());
101 doc
= xmlParseFile(filePath
.native_file_string().c_str());
104 //???res = xmlParseFile(filePath.native_file_string().c_str());
106 res
= xsltApplyStylesheet(cur
, doc
, params
);
112 HashSet
HelpCompiler::switchFind(xmlDocPtr doc
)
115 xmlChar
*xpath
= (xmlChar
*)"//switchinline";
117 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
118 xmlXPathObjectPtr result
= xmlXPathEvalExpression(xpath
, context
);
119 xmlXPathFreeContext(context
);
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");
129 if (!strcmp((const char*)select
, "appl"))
131 xmlNodePtr n1
= el
->xmlChildrenNode
;
134 if ((!xmlStrcmp(n1
->name
, (const xmlChar
*)"caseinline")))
136 xmlChar
*appl
= xmlGetProp(n1
, (xmlChar
*)"select");
137 hs
.push_back(std::string((const char*)appl
));
140 else if ((!xmlStrcmp(n1
->name
, (const xmlChar
*)"defaultinline")))
141 hs
.push_back(std::string("DEFAULT"));
148 xmlXPathFreeObject(result
);
150 hs
.push_back(std::string("DEFAULT"));
154 // returns a node representing the whole stuff compiled for the current
156 xmlNodePtr
HelpCompiler::clone(xmlNodePtr node
, const std::string
& appl
)
158 xmlNodePtr parent
= xmlCopyNode(node
, 2);
159 xmlNodePtr n
= node
->xmlChildrenNode
;
163 if ( (!strcmp((const char*)n
->name
, "switchinline")) ||
164 (!strcmp((const char*)n
->name
, "switch")) )
166 xmlChar
*select
= xmlGetProp(n
, (xmlChar
*)"select");
169 if (!strcmp((const char*)select
, "appl"))
176 xmlNodePtr caseNode
= n
->xmlChildrenNode
;
177 if (appl
== "DEFAULT")
181 if (!strcmp((const char*)caseNode
->name
, "defaultinline"))
183 xmlNodePtr cnl
= caseNode
->xmlChildrenNode
;
186 xmlAddChild(parent
, clone(cnl
, appl
));
191 caseNode
= caseNode
->next
;
199 if (!strcmp((const char*)caseNode
->name
, "caseinline"))
201 xmlChar
*select
= xmlGetProp(n
, (xmlChar
*)"select");
204 if (!strcmp((const char*)select
, appl
.c_str()))
210 xmlNodePtr cnl
= caseNode
->xmlChildrenNode
;
213 xmlAddChild(parent
, clone(cnl
, appl
));
220 caseNode
= caseNode
->next
;
226 xmlAddChild(parent
, clone(n
, appl
));
236 std::string documentId
;
237 std::string fileName
;
241 Stringtable
*helptexts
;
243 HashSet extendedHelpText
;
245 myparser(const std::string
&indocumentId
, const std::string
&infileName
,
246 const std::string
&intitle
) : documentId(indocumentId
), fileName(infileName
),
249 hidlist
= new HashSet
;
250 keywords
= new Hashtable
;
251 helptexts
= new Stringtable
;
253 void traverse( xmlNodePtr parentNode
);
255 std::string
dump(xmlNodePtr node
);
258 std::string
myparser::dump(xmlNodePtr node
)
261 if (node
->xmlChildrenNode
)
263 xmlNodePtr list
= node
->xmlChildrenNode
;
270 if (xmlNodeIsText(node
))
272 xmlChar
*pContent
= xmlNodeGetContent(node
);
273 app
+= std::string((const char*)pContent
);
275 // std::cout << app << std::endl;
280 void trim(std::string
& str
)
282 std::string::size_type pos
= str
.find_last_not_of(' ');
283 if(pos
!= std::string::npos
)
286 pos
= str
.find_first_not_of(' ');
287 if(pos
!= std::string::npos
)
291 str
.erase(str
.begin(), str
.end());
294 void myparser::traverse( xmlNodePtr parentNode
)
296 // traverse all nodes that belong to the parent
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
);
310 else if (title
.empty() && !strcmp((const char*)test
->name
, "title"))
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
);
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())
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
);
344 else if (branch
.compare("index") == 0)
348 for (xmlNodePtr nd
= test
->xmlChildrenNode
; nd
; nd
= nd
->next
)
350 if (strcmp((const char*)nd
->name
, "bookmark_value"))
353 std::string embedded
;
354 xmlChar
*embeddedxml
= xmlGetProp(nd
, (const xmlChar
*)"embedded");
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;
367 std::string keyword
= dump(nd
);
368 size_t keywordSem
= keyword
.find(';');
369 if (keywordSem
!= std::string::npos
)
372 keyword
.substr(0,keywordSem
);
375 keyword
.substr(1+keywordSem
);
377 keyword
= tmppre
+ ";" + tmppos
;
379 ll
.push_back(keyword
);
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
);
395 HashSet::const_iterator aEnd
= extendedHelpText
.end();
396 for (HashSet::const_iterator iter
= extendedHelpText
.begin(); iter
!= aEnd
;
400 (*helptexts
)[name
] = text
;
402 extendedHelpText
.clear();
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
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
;
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
)
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
;
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
);
512 rtl_TextEncoding
getThreadTextEncoding( void )
514 static bool bNeedsInit
= true;
515 static rtl_TextEncoding nThreadTextEncoding
;
519 nThreadTextEncoding
= osl_getThreadTextEncoding();
521 return nThreadTextEncoding
;
524 void create_directory(const fs::path indexDirName
)
527 std::cerr
<< "creating " <<
528 rtl::OUStringToOString(indexDirName
.data
, RTL_TEXTENCODING_UTF8
).getStr()
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
);
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
);
578 osl::File::remove(suFullFileURL
);
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: */