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
This commit is contained in:
534
xmlhelp/source/com/sun/star/help/HelpCompiler.cxx
Normal file
534
xmlhelp/source/com/sun/star/help/HelpCompiler.cxx
Normal file
@@ -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: */
|
Reference in New Issue
Block a user