diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2007-06-05 09:24:30 +0000 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2007-06-05 09:24:30 +0000 |
commit | 9baa583eed190d3527447256de431f8ecb7a1b51 (patch) | |
tree | a969813151af2d7e9b761512a7bbc6ae572bb18b /xmlhelp | |
parent | e5c5ec8747f7ecc1220dee1068a8fd88098083fa (diff) |
INTEGRATION: CWS helplinker01 (1.1.2); FILE ADDED
2007/05/21 13:13:15 cmc 1.1.2.2: #i70155# nitpicky macox warnings
2007/05/19 12:16:07 cmc 1.1.2.1: #ii70155# add a native HelpLinker
Diffstat (limited to 'xmlhelp')
-rw-r--r-- | xmlhelp/source/com/sun/star/help/HelpCompiler.cxx | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/xmlhelp/source/com/sun/star/help/HelpCompiler.cxx b/xmlhelp/source/com/sun/star/help/HelpCompiler.cxx new file mode 100644 index 000000000000..e136e1ea1f20 --- /dev/null +++ b/xmlhelp/source/com/sun/star/help/HelpCompiler.cxx @@ -0,0 +1,534 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: HelpCompiler.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: ihi $ $Date: 2007-06-05 10:24:30 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + + +#include "HelpCompiler.hxx" +#include <limits.h> +#include <stdlib.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + +HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile, + const fs::path &in_src, const fs::path &in_resEmbStylesheet, + const std::string &in_module, const std::string &in_lang) + : streamTable(in_streamTable), inputFile(in_inputFile), + src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet) +{ + xmlKeepBlanksDefaultValue = 0; +} + +xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath) +{ + static const char *params[4 + 1]; + static xsltStylesheetPtr cur = NULL; + if (!cur) + { + static std::string fsroot('\'' + src.toUTF8() + '\''); + static std::string esclang('\'' + lang + '\''); + + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 1; + cur = xsltParseStylesheetFile((const xmlChar *)resEmbStylesheet.native_file_string().c_str()); + + int nbparams = 0; + params[nbparams++] = "Language"; + params[nbparams++] = esclang.c_str(); + params[nbparams++] = "fsroot"; + params[nbparams++] = fsroot.c_str(); + params[nbparams] = NULL; + } + xmlDocPtr doc = xmlParseFile(filePath.native_file_string().c_str()); + xmlDocPtr res = xsltApplyStylesheet(cur, doc, params); + xmlFreeDoc(doc); + return res; +} + +HashSet HelpCompiler::switchFind(xmlDocPtr doc) +{ + HashSet hs; + xmlChar *xpath = (xmlChar*)"//switchinline"; + + xmlXPathContextPtr context = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context); + xmlXPathFreeContext(context); + if (result) + { + xmlNodeSetPtr nodeset = result->nodesetval; + for (int i = 0; i < nodeset->nodeNr; i++) + { + xmlNodePtr el = nodeset->nodeTab[i]; + xmlChar *select = xmlGetProp(el, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, "appl")) + { + xmlNodePtr n1 = el->xmlChildrenNode; + while (n1) + { + if ((!xmlStrcmp(n1->name, (const xmlChar*)"caseinline"))) + { + xmlChar *appl = xmlGetProp(n1, (xmlChar*)"select"); + hs.push_back(std::string((const char*)appl)); + xmlFree(appl); + } + else if ((!xmlStrcmp(n1->name, (const xmlChar*)"defaultinline"))) + hs.push_back(std::string("DEFAULT")); + n1 = n1->next; + } + } + xmlFree(select); + } + } + xmlXPathFreeObject(result); + } + hs.push_back(std::string("DEFAULT")); + return hs; +} + +// returns a node representing the whole stuff compiled for the current +// application. +xmlNodePtr HelpCompiler::clone(xmlNodePtr node, const std::string& appl) +{ + xmlNodePtr parent = xmlCopyNode(node, 2); + xmlNodePtr n = node->xmlChildrenNode; + while (n != NULL) + { + bool isappl = false; + if ( (!strcmp((const char*)n->name, "switchinline")) || + (!strcmp((const char*)n->name, "switch")) ) + { + xmlChar *select = xmlGetProp(n, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, "appl")) + isappl = true; + xmlFree(select); + } + } + if (isappl) + { + xmlNodePtr caseNode = n->xmlChildrenNode; + if (appl == "DEFAULT") + { + while (caseNode) + { + if (!strcmp((const char*)caseNode->name, "defaultinline")) + { + xmlNodePtr cnl = caseNode->xmlChildrenNode; + while (cnl) + { + xmlAddChild(parent, clone(cnl, appl)); + cnl = cnl->next; + } + break; + } + caseNode = caseNode->next; + } + } + else + { + while (caseNode) + { + isappl=false; + if (!strcmp((const char*)caseNode->name, "caseinline")) + { + xmlChar *select = xmlGetProp(n, (xmlChar*)"select"); + if (select) + { + if (!strcmp((const char*)select, appl.c_str())) + isappl = true; + xmlFree(select); + } + if (isappl) + { + xmlNodePtr cnl = caseNode->xmlChildrenNode; + while (cnl) + { + xmlAddChild(parent, clone(cnl, appl)); + cnl = cnl->next; + } + break; + } + + } + caseNode = caseNode->next; + } + } + + } + else + xmlAddChild(parent, clone(n, appl)); + + n = n->next; + } + return parent; +} + +class myparser +{ +public: + std::string documentId; + std::string fileName; + std::string title; + HashSet *hidlist; + Hashtable *keywords; + Stringtable *helptexts; +private: + HashSet extendedHelpText; +public: + myparser(const std::string &indocumentId, const std::string &infileName, + const std::string &intitle) : documentId(indocumentId), fileName(infileName), + title(intitle) + { + hidlist = new HashSet; + keywords = new Hashtable; + helptexts = new Stringtable; + } + void traverse( xmlNodePtr parentNode ); +private: + std::string dump(xmlNodePtr node); +}; + +std::string myparser::dump(xmlNodePtr node) +{ + std::string app; + if (node->xmlChildrenNode) + { + xmlNodePtr list = node->xmlChildrenNode; + while (list) + { + app += dump(list); + list = list->next; + } + } + if (xmlNodeIsText(node)) + { + xmlChar *pContent = xmlNodeGetContent(node); + app += std::string((const char*)pContent); + xmlFree(pContent); + // std::cout << app << std::endl; + } + return app; +} + +void trim(std::string& str) +{ + std::string::size_type pos = str.find_last_not_of(' '); + if(pos != std::string::npos) + { + str.erase(pos + 1); + pos = str.find_first_not_of(' '); + if(pos != std::string::npos) + str.erase(0, pos); + } + else + str.erase(str.begin(), str.end()); +} + +void myparser::traverse( xmlNodePtr parentNode ) +{ + // traverse all nodes that belong to the parent + xmlNodePtr test ; + for (test = parentNode->xmlChildrenNode; test; test = test->next) + { + if (fileName.empty() && !strcmp((const char*)test->name, "filename")) + { + xmlNodePtr node = test->xmlChildrenNode; + if (xmlNodeIsText(node)) + { + xmlChar *pContent = xmlNodeGetContent(node); + fileName = std::string((const char*)pContent); + xmlFree(pContent); + } + } + else if (title.empty() && !strcmp((const char*)test->name, "title")) + { + title = dump(test); + if (title.empty()) + title = "<notitle>"; + } + else if (!strcmp((const char*)test->name, "bookmark")) + { + xmlChar *branchxml = xmlGetProp(test, (const xmlChar*)"branch"); + xmlChar *idxml = xmlGetProp(test, (const xmlChar*)"id"); + std::string branch((const char*)branchxml); + std::string anchor((const char*)idxml); + xmlFree (branchxml); + xmlFree (idxml); + + std::string hid; + + if (branch.find("hid") == 0) + { + size_t index = branch.find('/'); + if (index != std::string::npos) + { + hid = branch.substr(1 + index); + // one shall serve as a documentId + if (documentId.empty()) + documentId = hid; + extendedHelpText.push_back(hid); + std::string foo = anchor.empty() ? hid : hid + "#" + anchor; + HCDBG(std::cerr << "hid pushback" << foo << std::endl); + hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor); + } + else + continue; + } + else if (branch.compare("index") == 0) + { + LinkedList ll; + + for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next) + { + if (strcmp((const char*)nd->name, "bookmark_value")) + continue; + + std::string embedded; + xmlChar *embeddedxml = xmlGetProp(nd, (const xmlChar*)"embedded"); + if (embeddedxml) + { + embedded = std::string((const char*)embeddedxml); + xmlFree (embeddedxml); + std::transform (embedded.begin(), embedded.end(), + embedded.begin(), tolower); + } + + bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0; + if (isEmbedded) + continue; + + std::string keyword = dump(nd); + size_t keywordSem = keyword.find(';'); + if (keywordSem != std::string::npos) + { + std::string tmppre = + keyword.substr(0,keywordSem); + trim(tmppre); + std::string tmppos = + keyword.substr(1+keywordSem); + trim(tmppos); + keyword = tmppre + ";" + tmppos; + } + ll.push_back(keyword); + } + if (!ll.empty()) + (*keywords)[anchor] = ll; + } + else if (branch.compare("contents") == 0) + { + // currently not used + } + } + else if (!strcmp((const char*)test->name, "ahelp")) + { + std::string text = dump(test); + trim(text); + std::string name; + + HashSet::const_iterator aEnd = extendedHelpText.end(); + for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd; + ++iter) + { + name = *iter; + (*helptexts)[name] = text; + } + extendedHelpText.clear(); + } + + // traverse children + traverse(test); + } +} + +bool HelpCompiler::compile() +{ + // we now have the jaroutputstream, which will contain the document. + // now determine the document as a dom tree in variable docResolved + + xmlDocPtr docResolvedOrg = getSourceDocument(inputFile); + + // now add path to the document + // resolve the dom + if (!docResolvedOrg) + { + std::cerr << "ERROR: file not existing: " << src.native_file_string().c_str() << std::endl; + exit(1); + } + + // now find all applications for which one has to compile + std::string documentId; + std::string fileName; + std::string title; + // returns all applications for which one has to compile + HashSet applications = switchFind(docResolvedOrg); + + HashSet::const_iterator aEnd = applications.end(); + for (HashSet::const_iterator aI = applications.begin(); aI != aEnd; ++aI) + { + std::string appl = *aI; + std::string modulename = appl; + if (modulename[0] == 'S') + { + modulename = modulename.substr(1); + std::transform(modulename.begin(), modulename.end(), modulename.begin(), tolower); + } + if (modulename != "DEFAULT" && modulename != module) + continue; + + // returns a clone of the document with swich-cases resolved + xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl); + myparser aparser(documentId, fileName, title); + aparser.traverse(docResolved); + + documentId = aparser.documentId; + fileName = aparser.fileName; + title = aparser.title; + + HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl); + + xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false); + xmlDocSetRootElement(docResolvedDoc, docResolved); + + if (modulename == "DEFAULT") + { + streamTable.default_doc = docResolvedDoc; + streamTable.default_hidlist = aparser.hidlist; + streamTable.default_helptexts = aparser.helptexts; + streamTable.default_keywords = aparser.keywords; + } + else if (modulename == module) + { + streamTable.appl_doc = docResolvedDoc; + streamTable.appl_hidlist = aparser.hidlist; + streamTable.appl_helptexts = aparser.helptexts; + streamTable.appl_keywords = aparser.keywords; + } + else + { + std::cerr << "unexpected case situation" << std::endl; + exit(-1); + } + + } // end iteration over all applications + + streamTable.document_id = documentId; + streamTable.document_path = fileName; + streamTable.document_title = title; + std::string actMod = module; + if (!fileName.empty()) + { + if (fileName.find("/text/") == 0) + { + int len = strlen("/text/"); + actMod = fileName.substr(len); + actMod = actMod.substr(0, actMod.find('/')); + } + } + streamTable.document_module = actMod; + + xmlFreeDoc(docResolvedOrg); + return true; +} + +namespace fs +{ + void create_directory(const fs::path indexDirName) + { + HCDBG( + std::cerr << "creating " << + rtl::OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr() + << std::endl + ); + osl::Directory::createPath(indexDirName.data); + } + + void rename(const fs::path &src, const fs::path &dest) + { + osl::File::move(src.data, dest.data); + } + + bool exists(const fs::path &in) + { + osl::File tmp(in.data); + return (tmp.open(osl_File_OpenFlag_Read) == osl::FileBase::E_None); + } + + void remove(const fs::path &in) + { + osl::File::remove(in.data); + } + + void removeRecursive(rtl::OUString const& _suDirURL) + { + { + osl::Directory aDir(_suDirURL); + aDir.open(); + if (aDir.isOpen()) + { + osl::DirectoryItem aItem; + osl::FileStatus aStatus(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes); + while (aDir.getNextItem(aItem) == ::osl::FileBase::E_None) + { + if (osl::FileBase::E_None == aItem.getFileStatus(aStatus) && + aStatus.isValid(osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Attributes)) + { + rtl::OUString suFilename = aStatus.getFileName(); + rtl::OUString suFullFileURL; + suFullFileURL += _suDirURL; + suFullFileURL += rtl::OUString::createFromAscii("/"); + suFullFileURL += suFilename; + + if (aStatus.getFileType() == osl::FileStatus::Directory) + removeRecursive(suFullFileURL); + else + osl::File::remove(suFullFileURL); + } + } + aDir.close(); + } + } + osl::Directory::remove(_suDirURL); + } + + void remove_all(const fs::path &in) + { + removeRecursive(in.data); + } +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ |