summaryrefslogtreecommitdiff
path: root/transex3/source/help
diff options
context:
space:
mode:
Diffstat (limited to 'transex3/source/help')
-rw-r--r--transex3/source/help/HelpCompiler.cxx593
-rw-r--r--transex3/source/help/HelpCompiler.hxx320
-rw-r--r--transex3/source/help/HelpFileDocument.java89
-rw-r--r--transex3/source/help/HelpIndexerTool.java372
-rw-r--r--transex3/source/help/HelpLinker.cxx1161
-rw-r--r--transex3/source/help/MANIFEST.MF2
-rw-r--r--transex3/source/help/compilehelp.hxx80
-rw-r--r--transex3/source/help/helplinker.pmk35
-rw-r--r--transex3/source/help/makefile.mk139
9 files changed, 2791 insertions, 0 deletions
diff --git a/transex3/source/help/HelpCompiler.cxx b/transex3/source/help/HelpCompiler.cxx
new file mode 100644
index 000000000000..5001d0907972
--- /dev/null
+++ b/transex3/source/help/HelpCompiler.cxx
@@ -0,0 +1,593 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: HelpCompiler.cxx,v $
+ * $Revision: 1.9 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+#include "HelpCompiler.hxx"
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+#ifdef __MINGW32__
+#include <tools/prewin.h>
+#include <tools/postwin.h>
+#endif
+#include <osl/thread.hxx>
+
+static void impl_sleep( sal_uInt32 nSec )
+{
+ TimeValue aTime;
+ aTime.Seconds = nSec;
+ aTime.Nanosec = 0;
+
+ osl::Thread::wait( aTime );
+}
+
+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, bool in_bExtensionMode)
+ : streamTable(in_streamTable), inputFile(in_inputFile),
+ src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet),
+ bExtensionMode( in_bExtensionMode )
+{
+ xmlKeepBlanksDefaultValue = 0;
+}
+
+xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath)
+{
+ static const char *params[4 + 1];
+ static xsltStylesheetPtr cur = NULL;
+
+ xmlDocPtr res;
+ if( bExtensionMode )
+ {
+ res = xmlParseFile(filePath.native_file_string().c_str());
+ if( !res ){
+ impl_sleep( 3 );
+ res = xmlParseFile(filePath.native_file_string().c_str());
+ }
+ }
+ else
+ {
+ 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());
+ if( !doc )
+ {
+ impl_sleep( 3 );
+ doc = xmlParseFile(filePath.native_file_string().c_str());
+ }
+
+ //???res = xmlParseFile(filePath.native_file_string().c_str());
+
+ 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( void ) throw( HelpProcessingException )
+{
+ // 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)
+ {
+ impl_sleep( 3 );
+ docResolvedOrg = getSourceDocument(inputFile);
+ if( !docResolvedOrg )
+ {
+ std::stringstream aStrStream;
+ aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ }
+
+ // 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.dropdefault();
+ streamTable.default_doc = docResolvedDoc;
+ streamTable.default_hidlist = aparser.hidlist;
+ streamTable.default_helptexts = aparser.helptexts;
+ streamTable.default_keywords = aparser.keywords;
+ }
+ else if (modulename == module)
+ {
+ streamTable.dropappl();
+ streamTable.appl_doc = docResolvedDoc;
+ streamTable.appl_hidlist = aparser.hidlist;
+ streamTable.appl_helptexts = aparser.helptexts;
+ streamTable.appl_keywords = aparser.keywords;
+ }
+ else
+ {
+ std::stringstream aStrStream;
+ aStrStream << "ERROR: Found unexpected module name \"" << modulename
+ << "\" in file" << src.native_file_string().c_str() << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ } // end iteration over all applications
+
+ streamTable.document_id = documentId;
+ streamTable.document_path = fileName;
+ streamTable.document_title = title;
+ std::string actMod = module;
+ if ( !bExtensionMode && !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
+{
+ rtl_TextEncoding getThreadTextEncoding( void )
+ {
+ static bool bNeedsInit = true;
+ static rtl_TextEncoding nThreadTextEncoding;
+ if( bNeedsInit )
+ {
+ bNeedsInit = false;
+ nThreadTextEncoding = osl_getThreadTextEncoding();
+ }
+ return nThreadTextEncoding;
+ }
+
+ 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);
+ }
+
+ void copy(const fs::path &src, const fs::path &dest)
+ {
+ osl::File::copy(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: */
diff --git a/transex3/source/help/HelpCompiler.hxx b/transex3/source/help/HelpCompiler.hxx
new file mode 100644
index 000000000000..7ffb096bd635
--- /dev/null
+++ b/transex3/source/help/HelpCompiler.hxx
@@ -0,0 +1,320 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: HelpCompiler.hxx,v $
+ * $Revision: 1.8 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef HELPCOMPILER_HXX
+#define HELPCOMPILER_HXX
+
+#include <string>
+#include <hash_map>
+#include <vector>
+#include <list>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <ctype.h>
+#ifdef SYSTEM_DB
+#include <db.h>
+#else
+#include <berkeleydb/db.h>
+#endif
+
+#include <boost/shared_ptr.hpp>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+
+#include <rtl/ustring.hxx>
+#include <osl/thread.h>
+#include <osl/process.h>
+#include <osl/file.hxx>
+
+#include <compilehelp.hxx>
+
+#define EMULATEORIGINAL 1
+
+#ifdef CMCDEBUG
+ #define HCDBG(foo) do { if (1) foo; } while(0)
+#else
+ #define HCDBG(foo) do { if (0) foo; } while(0)
+#endif
+
+namespace fs
+{
+ rtl_TextEncoding getThreadTextEncoding( void );
+
+ enum convert { native };
+ class path
+ {
+ public:
+ ::rtl::OUString data;
+ public:
+ path() {}
+ path(const path &rOther) : data(rOther.data) {}
+ path(const std::string &in, convert)
+ {
+ rtl::OUString sWorkingDir;
+ osl_getProcessWorkingDir(&sWorkingDir.pData);
+
+ rtl::OString tmp(in.c_str());
+ rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding()));
+ osl::File::getFileURLFromSystemPath(ustrSystemPath, data);
+ osl::File::getAbsoluteFileURL(sWorkingDir, data, data);
+ }
+ path(const std::string &FileURL)
+ {
+ rtl::OString tmp(FileURL.c_str());
+ data = rtl::OStringToOUString(tmp, getThreadTextEncoding());
+ }
+ std::string native_file_string() const
+ {
+ ::rtl::OUString ustrSystemPath;
+ osl::File::getSystemPathFromFileURL(data, ustrSystemPath);
+ rtl::OString tmp(rtl::OUStringToOString(ustrSystemPath, getThreadTextEncoding()));
+ HCDBG(std::cerr << "native_file_string is " << tmp.getStr() << std::endl);
+ return std::string(tmp.getStr());
+ }
+ std::string native_directory_string() const { return native_file_string(); }
+ std::string toUTF8() const
+ {
+ rtl::OString tmp(rtl::OUStringToOString(data, RTL_TEXTENCODING_UTF8));
+ return std::string(tmp.getStr());
+ }
+ bool empty() const { return data.getLength() == 0; }
+ path operator/(const std::string &in) const
+ {
+ path ret(*this);
+ HCDBG(std::cerr << "orig was " <<
+ rtl::OUStringToOString(ret.data, RTL_TEXTENCODING_UTF8).getStr() << std::endl);
+ rtl::OString tmp(in.c_str());
+ rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding()));
+ ret.data += rtl::OUString(sal_Unicode('/'));
+ ret.data += ustrSystemPath;
+ HCDBG(std::cerr << "final is " <<
+ rtl::OUStringToOString(ret.data, RTL_TEXTENCODING_UTF8).getStr() << std::endl);
+ return ret;
+ }
+ void append(const char *in)
+ {
+ rtl::OString tmp(in);
+ rtl::OUString ustrSystemPath(rtl::OStringToOUString(tmp, getThreadTextEncoding()));
+ data = data + ustrSystemPath;
+ }
+ void append(const std::string &in) { append(in.c_str()); }
+ };
+
+ void create_directory(const fs::path indexDirName);
+ void rename(const fs::path &src, const fs::path &dest);
+ void copy(const fs::path &src, const fs::path &dest);
+ bool exists(const fs::path &in);
+ void remove_all(const fs::path &in);
+ void remove(const fs::path &in);
+}
+
+struct joaat_hash
+{
+ size_t operator()(const std::string &str) const
+ {
+ size_t hash = 0;
+ const char *key = str.data();
+ for (size_t i = 0; i < str.size(); i++)
+ {
+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+ return hash;
+ }
+};
+
+#define get16bits(d) ((((sal_uInt32)(((const sal_uInt8 *)(d))[1])) << 8)\
+ +(sal_uInt32)(((const sal_uInt8 *)(d))[0]) )
+
+struct SuperFastHash
+{
+ size_t operator()(const std::string &str) const
+ {
+ const char * data = str.data();
+ int len = str.size();
+ size_t hash = len, tmp;
+ if (len <= 0 || data == NULL) return 0;
+
+ int rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--)
+ {
+ hash += get16bits (data);
+ tmp = (get16bits (data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof (sal_uInt16);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem)
+ {
+ case 3: hash += get16bits (data);
+ hash ^= hash << 16;
+ hash ^= data[sizeof (sal_uInt16)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += *data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+ }
+};
+
+#define pref_hash joaat_hash
+
+typedef std::hash_map<std::string, std::string, pref_hash> Stringtable;
+typedef std::list<std::string> LinkedList;
+typedef std::vector<std::string> HashSet;
+
+typedef std::hash_map<std::string, LinkedList, pref_hash> Hashtable;
+
+class StreamTable
+{
+public:
+ std::string document_id;
+ std::string document_path;
+ std::string document_module;
+ std::string document_title;
+
+ HashSet *appl_hidlist;
+ Hashtable *appl_keywords;
+ Stringtable *appl_helptexts;
+ xmlDocPtr appl_doc;
+
+ HashSet *default_hidlist;
+ Hashtable *default_keywords;
+ Stringtable *default_helptexts;
+ xmlDocPtr default_doc;
+
+ StreamTable() :
+ appl_hidlist(NULL), appl_keywords(NULL), appl_helptexts(NULL), appl_doc(NULL),
+ default_hidlist(NULL), default_keywords(NULL), default_helptexts(NULL), default_doc(NULL)
+ {}
+ void dropdefault()
+ {
+ delete default_hidlist;
+ delete default_keywords;
+ delete default_helptexts;
+ if (default_doc) xmlFreeDoc(default_doc);
+ }
+ void dropappl()
+ {
+ delete appl_hidlist;
+ delete appl_keywords;
+ delete appl_helptexts;
+ if (appl_doc) xmlFreeDoc(appl_doc);
+ }
+ ~StreamTable()
+ {
+ dropappl();
+ dropdefault();
+ }
+};
+
+struct HelpProcessingException
+{
+ HelpProcessingErrorClass m_eErrorClass;
+ std::string m_aErrorMsg;
+ std::string m_aXMLParsingFile;
+ int m_nXMLParsingLine;
+
+ HelpProcessingException( HelpProcessingErrorClass eErrorClass, const std::string& aErrorMsg )
+ : m_eErrorClass( eErrorClass )
+ , m_aErrorMsg( aErrorMsg )
+ {}
+ HelpProcessingException( const std::string& aErrorMsg, const std::string& aXMLParsingFile, int nXMLParsingLine )
+ : m_eErrorClass( HELPPROCESSING_XMLPARSING_ERROR )
+ , m_aErrorMsg( aErrorMsg )
+ , m_aXMLParsingFile( aXMLParsingFile )
+ , m_nXMLParsingLine( nXMLParsingLine )
+ {}
+};
+
+class HelpCompiler
+{
+public:
+ HelpCompiler(StreamTable &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,
+ bool in_bExtensionMode);
+ bool compile( void ) throw (HelpProcessingException);
+ void addEntryToJarFile(const std::string &prefix,
+ const std::string &entryName, const std::string &bytesToAdd);
+ void addEntryToJarFile(const std::string &prefix,
+ const std::string &entryName, const HashSet &bytesToAdd);
+ void addEntryToJarFile(const std::string &prefix,
+ const std::string &entryName, const Stringtable &bytesToAdd);
+ void addEntryToJarFile(const std::string &prefix,
+ const std::string &entryName, const Hashtable &bytesToAdd);
+private:
+ xmlDocPtr getSourceDocument(const fs::path &filePath);
+ HashSet switchFind(xmlDocPtr doc);
+ xmlNodePtr clone(xmlNodePtr node, const std::string& appl);
+ StreamTable &streamTable;
+ const fs::path inputFile, src;
+ const std::string module, lang;
+ const fs::path resEmbStylesheet;
+ bool bExtensionMode;
+};
+
+#endif
+
+/* vi:set tabstop=4 shiftwidth=4 expandtab: */
diff --git a/transex3/source/help/HelpFileDocument.java b/transex3/source/help/HelpFileDocument.java
new file mode 100644
index 000000000000..2212db27f251
--- /dev/null
+++ b/transex3/source/help/HelpFileDocument.java
@@ -0,0 +1,89 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: HelpFileDocument.java,v $
+ * $Revision: 1.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package com.sun.star.help;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+//import java.io.FileReader;
+import java.io.StringReader;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+/** Lucene Document for help files */
+public class HelpFileDocument
+{
+ /** Creates reader for UTF-8 files
+ */
+ private static Reader getReaderForFile( File aFile )
+ throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
+ Reader aReader;
+ if( aFile != null ) {
+ FileInputStream fis = new FileInputStream( aFile );
+ aReader = new InputStreamReader( fis, "UTF-8" );
+ }
+ else {
+ aReader = new StringReader( "" );
+ }
+ return aReader;
+ }
+
+ /** Makes a document for a File.
+ */
+ public static Document Document( String aModule, File aCaptionFile, File aContentFile )
+ throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
+ Document doc = new Document();
+
+ // Add the path of the file as a field named "path". Use a field that is
+ // indexed (i.e. searchable), but don't tokenize the field into words.
+ File aFile = aCaptionFile != null ? aCaptionFile : aContentFile;
+ if( aFile != null )
+ {
+ String aPath = "#HLP#" + aModule + "/" + aFile.getName();
+ doc.add(new Field("path", aPath, Field.Store.YES, Field.Index.UN_TOKENIZED));
+ }
+
+ // Add the caption of the file to a field named "caption". Specify a Reader,
+ // so that the text of the file is tokenized and indexed, but not stored.
+ doc.add( new Field( "caption", getReaderForFile( aCaptionFile ) ) );
+
+ // Add the contents of the file to a field named "content". Specify a Reader,
+ // so that the text of the file is tokenized and indexed, but not stored.
+ doc.add( new Field( "content", getReaderForFile( aContentFile ) ) );
+
+ // return the document
+ return doc;
+ }
+
+ private HelpFileDocument() {}
+}
diff --git a/transex3/source/help/HelpIndexerTool.java b/transex3/source/help/HelpIndexerTool.java
new file mode 100644
index 000000000000..6bf22d1ac344
--- /dev/null
+++ b/transex3/source/help/HelpIndexerTool.java
@@ -0,0 +1,372 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: HelpIndexer.java,v $
+ * $Revision: 1.21 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package com.sun.star.help;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.CRC32;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.analysis.cjk.CJKAnalyzer;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.IndexWriter;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Date;
+
+public class HelpIndexerTool
+{
+ public HelpIndexerTool()
+ {
+ }
+
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main( String[] args )
+ {
+ boolean bExtensionMode = false;
+ mainImpl( args, bExtensionMode );
+ }
+
+ public static void mainImpl( String[] args, boolean bExtensionMode )
+ {
+ String aDirToZipStr = "";
+ String aSrcDirStr = "";
+ String aLanguageStr = "";
+ String aModule = "";
+ String aTargetZipFileStr = "";
+ String aCfsName = "";
+
+ // Scan arguments
+ boolean bLang = false;
+ boolean bMod = false;
+ boolean bZipDir = false;
+ boolean bSrcDir = false;
+ boolean bOutput = false;
+ boolean bCfsName = false;
+
+ int nArgCount = args.length;
+ for( int i = 0 ; i < nArgCount ; i++ )
+ {
+ if( "-lang".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aLanguageStr = args[i + 1];
+ bLang = true;
+ }
+ i++;
+ }
+ else if( "-mod".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aModule = args[i + 1];
+ bMod = true;
+ }
+ i++;
+ }
+ else if( "-zipdir".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aDirToZipStr = args[i + 1];
+ bZipDir = true;
+ }
+ i++;
+ }
+ else if( "-srcdir".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aSrcDirStr = args[i + 1];
+ bSrcDir = true;
+ }
+ i++;
+ }
+ else if( "-o".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aTargetZipFileStr = args[i + 1];
+ bOutput = true;
+ }
+ i++;
+ }
+ else if( "-checkcfsname".equals(args[i]) )
+ {
+ if( i + 1 < nArgCount )
+ {
+ aCfsName = args[i + 1] + ".cfs";
+ bCfsName = true;
+ }
+ i++;
+ }
+ }
+
+ if( !bLang || !bMod || !bZipDir || (!bOutput && !bExtensionMode) )
+ {
+ if( bExtensionMode )
+ return;
+
+ System.out.println("Usage: HelpIndexer -lang ISOLangCode -mod HelpModule -zipdir TempZipDir -o OutputZipFile");
+ System.exit( -1 );
+ }
+
+ String aIndexDirName = aModule + ".idxl";
+ File aIndexDir = new File( aDirToZipStr + File.separator + aIndexDirName );
+ if( !bSrcDir )
+ aSrcDirStr = aDirToZipStr;
+ File aCaptionFilesDir = new File( aSrcDirStr + File.separator + "caption" );
+ File aContentFilesDir = new File( aSrcDirStr + File.separator + "content" );
+
+ try
+ {
+ Date start = new Date();
+ Analyzer analyzer = aLanguageStr.equals("ja") ? (Analyzer)new CJKAnalyzer() : (Analyzer)new StandardAnalyzer();
+ IndexWriter writer = new IndexWriter( aIndexDir, analyzer, true );
+ if( !bExtensionMode )
+ System.out.println( "Lucene: Indexing to directory '" + aIndexDir + "'..." );
+ int nRet = indexDocs( writer, aModule, bExtensionMode, aCaptionFilesDir, aContentFilesDir );
+ if( nRet != -1 )
+ {
+ if( !bExtensionMode )
+ {
+ System.out.println();
+ System.out.println( "Optimizing ..." );
+ }
+ writer.optimize();
+ }
+ writer.close();
+
+ boolean bCfsFileOk = true;
+ if( bCfsName && !bExtensionMode && nRet != -1 )
+ {
+ String aCompleteCfsFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aCfsName;
+ File aCfsFile = new File( aCompleteCfsFileName );
+ bCfsFileOk = aCfsFile.exists();
+ System.out.println( "Checking cfs file " + aCfsName+ ": " + (bCfsFileOk ? "Found" : "Not found") );
+ }
+
+ if( bExtensionMode )
+ {
+ if( !bSrcDir )
+ {
+ deleteRecursively( aCaptionFilesDir );
+ deleteRecursively( aContentFilesDir );
+ }
+ }
+ else
+ {
+ if( nRet == -1 )
+ deleteRecursively( aIndexDir );
+
+ if( bCfsFileOk )
+ System.out.println( "Zipping ..." );
+ File aDirToZipFile = new File( aDirToZipStr );
+ createZipFile( aDirToZipFile, aTargetZipFileStr );
+ deleteRecursively( aDirToZipFile );
+ }
+
+ if( !bCfsFileOk )
+ {
+ System.out.println( "cfs file check failed, terminating..." );
+ System.exit( -1 );
+ }
+
+ Date end = new Date();
+ if( !bExtensionMode )
+ System.out.println(end.getTime() - start.getTime() + " total milliseconds");
+ }
+ catch (IOException e)
+ {
+ if( bExtensionMode )
+ return;
+
+ System.out.println(" caught a " + e.getClass() +
+ "\n with message: " + e.getMessage());
+ System.exit( -1 );
+ }
+ }
+
+ private static int indexDocs(IndexWriter writer, String aModule, boolean bExtensionMode,
+ File aCaptionFilesDir, File aContentFilesDir) throws IOException
+ {
+ if( !aCaptionFilesDir.canRead() || !aCaptionFilesDir.isDirectory() )
+ {
+ if( !bExtensionMode )
+ System.out.println( "Not found: " + aCaptionFilesDir );
+ return -1;
+ }
+ if( !aContentFilesDir.canRead() || !aContentFilesDir.isDirectory() )
+ {
+ if( !bExtensionMode )
+ System.out.println( "Not found: " + aContentFilesDir );
+ return -1;
+ }
+
+ String[] aCaptionFiles = aCaptionFilesDir.list();
+ List aCaptionFilesList = Arrays.asList( aCaptionFiles );
+ HashSet aCaptionFilesHashSet = new HashSet( aCaptionFilesList );
+
+ String[] aContentFiles = aContentFilesDir.list();
+ List aContentFilesList = Arrays.asList( aContentFiles );
+ HashSet aContentFilesHashSet = new HashSet( aContentFilesList );
+
+ // Loop over caption files and find corresponding content file
+ if( !bExtensionMode )
+ System.out.println( "Indexing, adding files" );
+ int nCaptionFilesLen = aCaptionFiles.length;
+ for( int i = 0 ; i < nCaptionFilesLen ; i++ )
+ {
+ String aCaptionFileStr = aCaptionFiles[i];
+ File aCaptionFile = new File( aCaptionFilesDir, aCaptionFileStr );
+ File aContentFile = null;
+ if( aContentFilesHashSet.contains( aCaptionFileStr ) )
+ aContentFile = new File( aContentFilesDir, aCaptionFileStr );
+
+ if( !bExtensionMode )
+ System.out.print( "." );
+ writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) );
+ }
+
+ // Loop over content files to find remaining files not mapped to caption files
+ int nContentFilesLen = aContentFiles.length;
+ for( int i = 0 ; i < nContentFilesLen ; i++ )
+ {
+ String aContentFileStr = aContentFiles[i];
+ if( !aCaptionFilesHashSet.contains( aContentFileStr ) )
+ {
+ // Not already handled in caption files loop
+ File aCaptionFile = null;
+ File aContentFile = new File( aContentFilesDir, aContentFileStr );
+ if( !bExtensionMode )
+ System.out.print( "." );
+ writer.addDocument( HelpFileDocument.Document( aModule, aCaptionFile, aContentFile ) );
+ }
+ }
+ return 0;
+ }
+
+ public static void createZipFile( File aDirToZip, String aTargetZipFileStr )
+ throws FileNotFoundException, IOException
+ {
+ FileOutputStream fos = new FileOutputStream( aTargetZipFileStr );
+ ZipOutputStream zos = new ZipOutputStream( fos );
+
+ File[] aChildrenFiles = aDirToZip.listFiles();
+ int nFileCount = aChildrenFiles.length;
+ for( int i = 0 ; i < nFileCount ; i++ )
+ addToZipRecursively( zos, aChildrenFiles[i], null );
+
+ zos.close();
+ }
+
+ public static void addToZipRecursively( ZipOutputStream zos, File aFile, String aBasePath )
+ throws FileNotFoundException, IOException
+ {
+ if( aFile.isDirectory() )
+ {
+ String aDirName = aFile.getName();
+ if( aDirName.equalsIgnoreCase( "caption" ) || aDirName.equalsIgnoreCase( "content" ) )
+ return;
+
+ File[] aChildrenFiles = aFile.listFiles();
+ String aNewBasePath = "";
+ if( aBasePath != null )
+ aNewBasePath += aBasePath + File.separator;
+ aNewBasePath += aDirName;
+
+ int nFileCount = aChildrenFiles.length;
+ for( int i = 0 ; i < nFileCount ; i++ )
+ addToZipRecursively( zos, aChildrenFiles[i], aNewBasePath );
+
+ return;
+ }
+
+ // No directory
+ // read contents of file we are going to put in the zip
+ int fileLength = (int) aFile.length();
+ FileInputStream fis = new FileInputStream( aFile );
+ byte[] wholeFile = new byte[fileLength];
+ int bytesRead = fis.read( wholeFile, 0, fileLength );
+ fis.close();
+
+ String aFileName = aFile.getName();
+ String aEntryName = "";
+ if( aBasePath != null )
+ aEntryName += aBasePath + "/";
+ aEntryName += aFileName;
+ ZipEntry aZipEntry = new ZipEntry( aEntryName );
+ aZipEntry.setTime( aFile.lastModified() );
+ aZipEntry.setSize( fileLength );
+
+ int nMethod = ( aFileName.toLowerCase().endsWith( ".jar" ) )
+ ? ZipEntry.STORED : ZipEntry.DEFLATED;
+ aZipEntry.setMethod( nMethod );
+
+ CRC32 tempCRC = new CRC32();
+ tempCRC.update( wholeFile, 0, wholeFile.length );
+ aZipEntry.setCrc( tempCRC.getValue() );
+
+ // write the contents into the zip element
+ zos.putNextEntry( aZipEntry );
+ zos.write( wholeFile, 0, fileLength );
+ zos.closeEntry();
+ }
+
+ static public boolean deleteRecursively( File aFile )
+ {
+ if( aFile.isDirectory() )
+ {
+ File[] aChildrenFiles = aFile.listFiles();
+ int nFileCount = aChildrenFiles.length;
+ for( int i = 0 ; i < nFileCount ; i++ )
+ {
+ File aChildrenFile = aChildrenFiles[i];
+ boolean bSuccess = deleteRecursively( aChildrenFile );
+ if( !bSuccess )
+ return false;
+ }
+ }
+
+ return aFile.delete();
+ }
+}
+
diff --git a/transex3/source/help/HelpLinker.cxx b/transex3/source/help/HelpLinker.cxx
new file mode 100644
index 000000000000..8acb129b21fb
--- /dev/null
+++ b/transex3/source/help/HelpLinker.cxx
@@ -0,0 +1,1161 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: HelpLinker.cxx,v $
+ * $Revision: 1.16 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "HelpCompiler.hxx"
+
+#include <map>
+
+#include <string.h>
+#include <limits.h>
+
+#include <libxslt/xslt.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/functions.h>
+#include <libxslt/extensions.h>
+
+#include <sal/types.h>
+#include <osl/time.h>
+#include <rtl/bootstrap.hxx>
+
+#ifdef SYSTEM_EXPAT
+#include <expat.h>
+#else
+#include <expat/xmlparse.h>
+#endif
+
+#define DBHELP_ONLY
+
+
+class IndexerPreProcessor
+{
+private:
+ std::string m_aModuleName;
+ fs::path m_fsIndexBaseDir;
+ fs::path m_fsCaptionFilesDirName;
+ fs::path m_fsContentFilesDirName;
+
+ xsltStylesheetPtr m_xsltStylesheetPtrCaption;
+ xsltStylesheetPtr m_xsltStylesheetPtrContent;
+
+public:
+ IndexerPreProcessor( const std::string& aModuleName, const fs::path& fsIndexBaseDir,
+ const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet );
+ ~IndexerPreProcessor();
+
+ void processDocument( xmlDocPtr doc, const std::string& EncodedDocPath );
+};
+
+IndexerPreProcessor::IndexerPreProcessor
+ ( const std::string& aModuleName, const fs::path& fsIndexBaseDir,
+ const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet )
+ : m_aModuleName( aModuleName )
+ , m_fsIndexBaseDir( fsIndexBaseDir )
+{
+ m_fsCaptionFilesDirName = fsIndexBaseDir / "caption";
+ fs::create_directory( m_fsCaptionFilesDirName );
+
+ m_fsContentFilesDirName = fsIndexBaseDir / "content";
+ fs::create_directory( m_fsContentFilesDirName );
+
+ m_xsltStylesheetPtrCaption = xsltParseStylesheetFile
+ ((const xmlChar *)idxCaptionStylesheet.native_file_string().c_str());
+ m_xsltStylesheetPtrContent = xsltParseStylesheetFile
+ ((const xmlChar *)idxContentStylesheet.native_file_string().c_str());
+}
+
+IndexerPreProcessor::~IndexerPreProcessor()
+{
+ if( m_xsltStylesheetPtrCaption )
+ xsltFreeStylesheet( m_xsltStylesheetPtrCaption );
+ if( m_xsltStylesheetPtrContent )
+ xsltFreeStylesheet( m_xsltStylesheetPtrContent );
+}
+
+
+std::string getEncodedPath( const std::string& Path )
+{
+ rtl::OString aOStr_Path( Path.c_str() );
+ rtl::OUString aOUStr_Path( rtl::OStringToOUString
+ ( aOStr_Path, fs::getThreadTextEncoding() ) );
+ rtl::OUString aPathURL;
+ osl::File::getFileURLFromSystemPath( aOUStr_Path, aPathURL );
+ rtl::OString aOStr_PathURL( rtl::OUStringToOString
+ ( aPathURL, fs::getThreadTextEncoding() ) );
+ std::string aStdStr_PathURL( aOStr_PathURL.getStr() );
+ return aStdStr_PathURL;
+}
+
+void IndexerPreProcessor::processDocument
+ ( xmlDocPtr doc, const std::string &EncodedDocPath )
+{
+ std::string aStdStr_EncodedDocPathURL = getEncodedPath( EncodedDocPath );
+
+ xmlDocPtr resCaption = xsltApplyStylesheet( m_xsltStylesheetPtrCaption, doc, NULL );
+ xmlNodePtr pResNodeCaption = resCaption->xmlChildrenNode;
+ if( pResNodeCaption )
+ {
+ fs::path fsCaptionPureTextFile_docURL = m_fsCaptionFilesDirName / aStdStr_EncodedDocPathURL;
+ std::string aCaptionPureTextFileStr_docURL = fsCaptionPureTextFile_docURL.native_file_string();
+ FILE* pFile_docURL = fopen( aCaptionPureTextFileStr_docURL.c_str(), "w" );
+ if( pFile_docURL )
+ {
+ fprintf( pFile_docURL, "%s\n", pResNodeCaption->content );
+ fclose( pFile_docURL );
+ }
+ }
+ xmlFreeDoc(resCaption);
+
+ xmlDocPtr resContent = xsltApplyStylesheet( m_xsltStylesheetPtrContent, doc, NULL );
+ xmlNodePtr pResNodeContent = resContent->xmlChildrenNode;
+ if( pResNodeContent )
+ {
+ fs::path fsContentPureTextFile_docURL = m_fsContentFilesDirName / aStdStr_EncodedDocPathURL;
+ std::string aContentPureTextFileStr_docURL = fsContentPureTextFile_docURL.native_file_string();
+ FILE* pFile_docURL = fopen( aContentPureTextFileStr_docURL.c_str(), "w" );
+ if( pFile_docURL )
+ {
+ fprintf( pFile_docURL, "%s\n", pResNodeContent->content );
+ fclose( pFile_docURL );
+ }
+ }
+ xmlFreeDoc(resContent);
+}
+
+struct Data
+{
+ std::vector<std::string> _idList;
+ typedef std::vector<std::string>::const_iterator cIter;
+
+ void append(const std::string &id)
+ {
+ _idList.push_back(id);
+ }
+
+ std::string getString() const
+ {
+ std::string ret;
+ cIter aEnd = _idList.end();
+ for (cIter aIter = _idList.begin(); aIter != aEnd; ++aIter)
+ ret += *aIter + ";";
+ return ret;
+ }
+};
+
+void writeKeyValue_DBHelp( FILE* pFile, const std::string& aKeyStr, const std::string& aValueStr )
+{
+ if( pFile == NULL )
+ return;
+ char cLF = 10;
+ int nKeyLen = aKeyStr.length();
+ int nValueLen = aValueStr.length();
+ fprintf( pFile, "%x ", nKeyLen );
+ if( nKeyLen > 0 )
+ fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile );
+ fprintf( pFile, " %x ", nValueLen );
+ if( nValueLen > 0 )
+ fwrite( aValueStr.c_str(), 1, nValueLen, pFile );
+ fprintf( pFile, "%c", cLF );
+}
+
+class HelpKeyword
+{
+private:
+ typedef std::hash_map<std::string, Data, pref_hash> DataHashtable;
+ DataHashtable _hash;
+
+public:
+ void insert(const std::string &key, const std::string &id)
+ {
+ Data &data = _hash[key];
+ data.append(id);
+ }
+
+ void dump(DB* table)
+ {
+ DataHashtable::const_iterator aEnd = _hash.end();
+ for (DataHashtable::const_iterator aIter = _hash.begin(); aIter != aEnd; ++aIter)
+ {
+ const std::string &keystr = aIter->first;
+ DBT key;
+ memset(&key, 0, sizeof(key));
+ key.data = const_cast<char*>(keystr.c_str());
+ key.size = keystr.length();
+
+ const Data &data = aIter->second;
+ std::string str = data.getString();
+ DBT value;
+ memset(&value, 0, sizeof(value));
+ value.data = const_cast<char*>(str.c_str());
+ value.size = str.length();
+
+ table->put(table, NULL, &key, &value, 0);
+ }
+ }
+
+ void dump_DBHelp( const std::string& rFileName )
+ {
+ FILE* pFile = fopen( rFileName.c_str(), "wb" );
+ if( pFile == NULL )
+ return;
+
+ DataHashtable::const_iterator aEnd = _hash.end();
+ for (DataHashtable::const_iterator aIter = _hash.begin(); aIter != aEnd; ++aIter)
+ writeKeyValue_DBHelp( pFile, aIter->first, aIter->second.getString() );
+
+ fclose( pFile );
+ }
+};
+
+class HelpLinker
+{
+public:
+ void main(std::vector<std::string> &args, std::string* pExtensionPath = NULL )
+ throw( HelpProcessingException );
+
+ HelpLinker()
+ : init(true)
+ , m_pIndexerPreProcessor(NULL)
+ {}
+ ~HelpLinker()
+ { delete m_pIndexerPreProcessor; }
+
+private:
+ int locCount, totCount;
+ Stringtable additionalFiles;
+ HashSet helpFiles;
+ fs::path sourceRoot;
+ fs::path embeddStylesheet;
+ fs::path idxCaptionStylesheet;
+ fs::path idxContentStylesheet;
+ fs::path zipdir;
+ fs::path outputFile;
+ std::string module;
+ std::string lang;
+ std::string hid;
+ std::string extensionPath;
+ bool bExtensionMode;
+ fs::path indexDirName;
+ Stringtable hidlistTranslation;
+ fs::path indexDirParentName;
+ bool init;
+ IndexerPreProcessor* m_pIndexerPreProcessor;
+ void initIndexerPreProcessor();
+ void link() throw( HelpProcessingException );
+ void addBookmark( DB* dbBase, FILE* pFile_DBHelp, std::string thishid,
+ const std::string& fileB, const std::string& anchorB,
+ const std::string& jarfileB, const std::string& titleB );
+#if 0
+ /**
+ * @param outputFile
+ * @param module
+ * @param lang
+ * @param hid
+ * @param helpFiles
+ * @param additionalFiles
+ */
+
+ private HelpURLStreamHandlerFactory urlHandler = null;
+#endif
+};
+
+namespace URLEncoder
+{
+ static std::string encode(const std::string &rIn)
+ {
+ const char *good = "!$&'()*+,-.=@_";
+ static const char hex[17] = "0123456789ABCDEF";
+
+ std::string result;
+ for (size_t i=0; i < rIn.length(); ++i)
+ {
+ unsigned char c = rIn[i];
+ if (isalnum (c) || strchr (good, c))
+ result += c;
+ else {
+ result += '%';
+ result += hex[c >> 4];
+ result += hex[c & 0xf];
+ }
+ }
+ return result;
+ }
+}
+
+void HelpLinker::addBookmark( DB* dbBase, FILE* pFile_DBHelp, std::string thishid,
+ const std::string& fileB, const std::string& anchorB,
+ const std::string& jarfileB, const std::string& titleB)
+{
+ HCDBG(std::cerr << "HelpLinker::addBookmark " << thishid << " " <<
+ fileB << " " << anchorB << " " << jarfileB << " " << titleB << std::endl);
+
+ std::string temp = thishid;
+ std::transform (temp.begin(), temp.end(), temp.begin(), toupper);
+ std::replace(temp.begin(), temp.end(), ':', '_');
+ const std::string& translatedHid = hidlistTranslation[temp];
+ if (!translatedHid.empty())
+ thishid = translatedHid;
+
+ thishid = URLEncoder::encode(thishid);
+
+ DBT key;
+ memset(&key, 0, sizeof(key));
+ key.data = const_cast<char*>(thishid.c_str());
+ key.size = thishid.length();
+
+ int fileLen = fileB.length();
+ if (!anchorB.empty())
+ fileLen += (1 + anchorB.length());
+ int dataLen = 1 + fileLen + 1 + jarfileB.length() + 1 + titleB.length();
+
+ std::vector<unsigned char> dataB(dataLen);
+ size_t i = 0;
+ dataB[i++] = static_cast<unsigned char>(fileLen);
+ for (size_t j = 0; j < fileB.length(); ++j)
+ dataB[i++] = fileB[j];
+ if (!anchorB.empty())
+ {
+ dataB[i++] = '#';
+ for (size_t j = 0; j < anchorB.length(); ++j)
+ dataB[i++] = anchorB[j];
+ }
+ dataB[i++] = static_cast<unsigned char>(jarfileB.length());
+ for (size_t j = 0; j < jarfileB.length(); ++j)
+ dataB[i++] = jarfileB[j];
+
+ dataB[i++] = static_cast<unsigned char>(titleB.length());
+ for (size_t j = 0; j < titleB.length(); ++j)
+ dataB[i++] = titleB[j];
+
+ DBT data;
+ memset(&data, 0, sizeof(data));
+ data.data = &dataB[0];
+ data.size = dataB.size();
+
+ if( dbBase != NULL )
+ dbBase->put(dbBase, NULL, &key, &data, 0);
+
+ if( pFile_DBHelp != NULL )
+ {
+ std::string aValueStr( dataB.begin(), dataB.end() );
+ writeKeyValue_DBHelp( pFile_DBHelp, thishid, aValueStr );
+ }
+}
+
+void HelpLinker::initIndexerPreProcessor()
+{
+ if( m_pIndexerPreProcessor )
+ delete m_pIndexerPreProcessor;
+ std::string mod = module;
+ std::transform (mod.begin(), mod.end(), mod.begin(), tolower);
+ m_pIndexerPreProcessor = new IndexerPreProcessor( mod, indexDirParentName,
+ idxCaptionStylesheet, idxContentStylesheet );
+}
+
+/**
+*
+*/
+void HelpLinker::link() throw( HelpProcessingException )
+{
+ bool bIndexForExtension = true;
+
+ if( bExtensionMode )
+ {
+ indexDirParentName = sourceRoot;
+ }
+ else
+ {
+ indexDirParentName = zipdir;
+ fs::create_directory(indexDirParentName);
+ }
+
+#ifdef CMC_DEBUG
+ std::cerr << "will not delete tmpdir of " << indexDirParentName.native_file_string().c_str() << std::endl;
+#endif
+
+ std::string mod = module;
+ std::transform (mod.begin(), mod.end(), mod.begin(), tolower);
+
+ // do the work here
+ // continue with introduction of the overall process thing into the
+ // here all hzip files will be worked on
+ std::string appl = mod;
+ if (appl[0] == 's')
+ appl = appl.substr(1);
+
+ bool bUse_ = true;
+#ifdef DBHELP_ONLY
+ if( !bExtensionMode )
+ bUse_ = false;
+#endif
+
+ DB* helpText(0);
+#ifndef DBHELP_ONLY
+ fs::path helpTextFileName(indexDirParentName / (mod + ".ht"));
+ db_create(&helpText,0,0);
+ helpText->open(helpText, NULL, helpTextFileName.native_file_string().c_str(), NULL, DB_BTREE,
+ DB_CREATE | DB_TRUNCATE, 0644);
+#endif
+
+ fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht")));
+ FILE* pFileHelpText_DBHelp = fopen
+ ( helpTextFileName_DBHelp.native_file_string().c_str(), "wb" );
+
+ DB* dbBase(0);
+#ifndef DBHELP_ONLY
+ fs::path dbBaseFileName(indexDirParentName / (mod + ".db"));
+ db_create(&dbBase,0,0);
+ dbBase->open(dbBase, NULL, dbBaseFileName.native_file_string().c_str(), NULL, DB_BTREE,
+ DB_CREATE | DB_TRUNCATE, 0644);
+#endif
+
+ fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db")));
+ FILE* pFileDbBase_DBHelp = fopen
+ ( dbBaseFileName_DBHelp.native_file_string().c_str(), "wb" );
+
+#ifndef DBHELP_ONLY
+ DB* keyWord(0);
+ fs::path keyWordFileName(indexDirParentName / (mod + ".key"));
+ db_create(&keyWord,0,0);
+ keyWord->open(keyWord, NULL, keyWordFileName.native_file_string().c_str(), NULL, DB_BTREE,
+ DB_CREATE | DB_TRUNCATE, 0644);
+#endif
+
+ fs::path keyWordFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".key_" : ".key")));
+
+ HelpKeyword helpKeyword;
+
+ // catch HelpProcessingException to avoid locking data bases
+ try
+ {
+
+ std::ifstream fileReader(hid.c_str());
+ while (fileReader)
+ {
+ std::string key;
+ fileReader >> key;
+ std::transform (key.begin(), key.end(), key.begin(), toupper);
+ std::replace(key.begin(), key.end(), ':', '_');
+ std::string data;
+ fileReader >> data;
+ if (!key.empty() && !data.empty())
+ hidlistTranslation[key] = data;
+ }
+ fileReader.close();
+
+ // lastly, initialize the indexBuilder
+ if ( (!bExtensionMode || bIndexForExtension) && !helpFiles.empty())
+ initIndexerPreProcessor();
+
+ if( !bExtensionMode )
+ {
+#ifndef OS2 // YD @TODO@ crashes libc runtime :-(
+ std::cout << "Making " << outputFile.native_file_string() <<
+ " from " << helpFiles.size() << " input files" << std::endl;
+#endif
+ }
+
+ // here we start our loop over the hzip files.
+ HashSet::iterator end = helpFiles.end();
+ for (HashSet::iterator iter = helpFiles.begin(); iter != end; ++iter)
+ {
+ if( !bExtensionMode )
+ {
+ std::cout << ".";
+ std::cout.flush();
+ }
+
+ // process one file
+ // streamTable contains the streams in the hzip file
+ StreamTable streamTable;
+ const std::string &xhpFileName = *iter;
+
+ if (!bExtensionMode && xhpFileName.rfind(".xhp") != xhpFileName.length()-4)
+ {
+ // only work on .xhp - files
+ std::cerr <<
+ "ERROR: input list entry '"
+ << xhpFileName
+ << "' has the wrong extension (only files with extension .xhp "
+ << "are accepted)";
+ continue;
+ }
+
+ fs::path langsourceRoot(sourceRoot);
+ fs::path xhpFile;
+
+ if( bExtensionMode )
+ {
+ // langsourceRoot == sourceRoot for extensions
+ std::string xhpFileNameComplete( extensionPath );
+ xhpFileNameComplete.append( '/' + xhpFileName );
+ xhpFile = fs::path( xhpFileNameComplete );
+ }
+ else
+ {
+ langsourceRoot.append('/' + lang + '/');
+ xhpFile = fs::path(xhpFileName, fs::native);
+ }
+
+ HelpCompiler hc( streamTable, xhpFile, langsourceRoot,
+ embeddStylesheet, module, lang, bExtensionMode );
+
+ HCDBG(std::cerr << "before compile of " << xhpFileName << std::endl);
+ bool success = hc.compile();
+ HCDBG(std::cerr << "after compile of " << xhpFileName << std::endl);
+
+ if (!success && !bExtensionMode)
+ {
+ std::stringstream aStrStream;
+ aStrStream <<
+ "\nERROR: compiling help particle '"
+ << xhpFileName
+ << "' for language '"
+ << lang
+ << "' failed!";
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ const std::string documentBaseId = streamTable.document_id;
+ std::string documentPath = streamTable.document_path;
+ if (documentPath.find("/") == 0)
+ documentPath = documentPath.substr(1);
+
+ std::string documentJarfile = streamTable.document_module + ".jar";
+
+ std::string documentTitle = streamTable.document_title;
+ if (documentTitle.empty())
+ documentTitle = "<notitle>";
+
+#if 0
+ std::cout << "for " << xhpFileName << " documentBaseId is " << documentBaseId << "\n";
+ std::cout << "for " << xhpFileName << " documentPath is " << documentPath << "\n";
+ std::cout << "for " << xhpFileName << " documentJarfile is " << documentJarfile << "\n";
+ std::cout << "for " << xhpFileName << " documentPath is " << documentTitle << "\n";
+#endif
+
+ const std::string& fileB = documentPath;
+ const std::string& jarfileB = documentJarfile;
+ std::string& titleB = documentTitle;
+
+ // add once this as its own id.
+ addBookmark(dbBase, pFileDbBase_DBHelp, documentPath, fileB, std::string(), jarfileB, titleB);
+
+ // first the database *.db
+ // ByteArrayInputStream bais = null;
+ // ObjectInputStream ois = null;
+
+ const HashSet *hidlist = streamTable.appl_hidlist;
+ if (!hidlist)
+ hidlist = streamTable.default_hidlist;
+ if (hidlist && !hidlist->empty())
+ {
+ // now iterate over all elements of the hidlist
+ HashSet::const_iterator aEnd = hidlist->end();
+ for (HashSet::const_iterator hidListIter = hidlist->begin();
+ hidListIter != aEnd; ++hidListIter)
+ {
+ std::string thishid = *hidListIter;
+
+ std::string anchorB;
+ size_t index = thishid.rfind('#');
+ if (index != std::string::npos)
+ {
+ anchorB = thishid.substr(1 + index);
+ thishid = thishid.substr(0, index);
+ }
+ addBookmark(dbBase, pFileDbBase_DBHelp, thishid, fileB, anchorB, jarfileB, titleB);
+ }
+ }
+
+ // now the keywords
+ const Hashtable *anchorToLL = streamTable.appl_keywords;
+ if (!anchorToLL)
+ anchorToLL = streamTable.default_keywords;
+ if (anchorToLL && !anchorToLL->empty())
+ {
+ std::string fakedHid = URLEncoder::encode(documentPath);
+ Hashtable::const_iterator aEnd = anchorToLL->end();
+ for (Hashtable::const_iterator enumer = anchorToLL->begin();
+ enumer != aEnd; ++enumer)
+ {
+ const std::string &anchor = enumer->first;
+ addBookmark(dbBase, pFileDbBase_DBHelp, documentPath, fileB,
+ anchor, jarfileB, titleB);
+ std::string totalId = fakedHid + "#" + anchor;
+ // std::cerr << hzipFileName << std::endl;
+ const LinkedList& ll = enumer->second;
+ LinkedList::const_iterator aOtherEnd = ll.end();
+ for (LinkedList::const_iterator llIter = ll.begin();
+ llIter != aOtherEnd; ++llIter)
+ {
+ helpKeyword.insert(*llIter, totalId);
+ }
+ }
+
+ }
+
+ // and last the helptexts
+ const Stringtable *helpTextHash = streamTable.appl_helptexts;
+ if (!helpTextHash)
+ helpTextHash = streamTable.default_helptexts;
+ if (helpTextHash && !helpTextHash->empty())
+ {
+ Stringtable::const_iterator aEnd = helpTextHash->end();
+ for (Stringtable::const_iterator helpTextIter = helpTextHash->begin();
+ helpTextIter != aEnd; ++helpTextIter)
+ {
+ std::string helpTextId = helpTextIter->first;
+ const std::string& helpTextText = helpTextIter->second;
+
+ std::string temp = helpTextId;
+ std::transform (temp.begin(), temp.end(), temp.begin(), toupper);
+ std::replace(temp.begin(), temp.end(), ':', '_');
+
+ const std::string& tHid = hidlistTranslation[temp];
+ if (!tHid.empty())
+ helpTextId = tHid;
+ helpTextId = URLEncoder::encode(helpTextId);
+
+ DBT keyDbt;
+ memset(&keyDbt, 0, sizeof(keyDbt));
+ keyDbt.data = const_cast<char*>(helpTextId.c_str());
+ keyDbt.size = helpTextId.length();
+
+ DBT textDbt;
+ memset(&textDbt, 0, sizeof(textDbt));
+ textDbt.data = const_cast<char*>(helpTextText.c_str());
+ textDbt.size = helpTextText.length();
+
+ if( helpText != NULL )
+ helpText->put(helpText, NULL, &keyDbt, &textDbt, 0);
+
+ if( pFileHelpText_DBHelp != NULL )
+ writeKeyValue_DBHelp( pFileHelpText_DBHelp, helpTextId, helpTextText );
+ }
+ }
+
+ //IndexerPreProcessor
+ if( !bExtensionMode || bIndexForExtension )
+ {
+ // now the indexing
+ xmlDocPtr document = streamTable.appl_doc;
+ if (!document)
+ document = streamTable.default_doc;
+ if (document)
+ {
+ std::string temp = module;
+ std::transform (temp.begin(), temp.end(), temp.begin(), tolower);
+ m_pIndexerPreProcessor->processDocument(document, URLEncoder::encode(documentPath) );
+ }
+ }
+
+ } // while loop over hzip files ending
+ if( !bExtensionMode )
+ std::cout << std::endl;
+
+ } // try
+ catch( HelpProcessingException& )
+ {
+ // catch HelpProcessingException to avoid locking data bases
+#ifndef DBHELP_ONLY
+ helpText->close(helpText, 0);
+ dbBase->close(dbBase, 0);
+ keyWord->close(keyWord, 0);
+#endif
+ if( pFileHelpText_DBHelp != NULL )
+ fclose( pFileHelpText_DBHelp );
+ if( pFileDbBase_DBHelp != NULL )
+ fclose( pFileDbBase_DBHelp );
+ throw;
+ }
+
+#ifndef DBHELP_ONLY
+ helpText->close(helpText, 0);
+ dbBase->close(dbBase, 0);
+ helpKeyword.dump(keyWord);
+ keyWord->close(keyWord, 0);
+#endif
+ if( pFileHelpText_DBHelp != NULL )
+ fclose( pFileHelpText_DBHelp );
+ if( pFileDbBase_DBHelp != NULL )
+ fclose( pFileDbBase_DBHelp );
+
+ helpKeyword.dump_DBHelp( keyWordFileName_DBHelp.native_file_string() );
+
+ if( !bExtensionMode )
+ {
+ // New index
+ Stringtable::iterator aEnd = additionalFiles.end();
+ for (Stringtable::iterator enumer = additionalFiles.begin(); enumer != aEnd;
+ ++enumer)
+ {
+ const std::string &additionalFileName = enumer->second;
+ const std::string &additionalFileKey = enumer->first;
+
+ fs::path fsAdditionalFileName( additionalFileName, fs::native );
+ std::string aNativeStr = fsAdditionalFileName.native_file_string();
+ const char* pStr = aNativeStr.c_str();
+ std::cerr << pStr;
+
+ fs::path fsTargetName( indexDirParentName / additionalFileKey );
+
+ fs::copy( fsAdditionalFileName, fsTargetName );
+ }
+ }
+
+/*
+ /////////////////////////////////////////////////////////////////////////
+ /// remove temprary directory for index creation
+ /////////////////////////////////////////////////////////////////////////
+#ifndef CMC_DEBUG
+ if( !bExtensionMode )
+ fs::remove_all( indexDirParentName );
+#endif
+*/
+}
+
+
+void HelpLinker::main(std::vector<std::string> &args, std::string* pExtensionPath)
+ throw( HelpProcessingException )
+{
+ rtl::OUString aOfficeHelpPath;
+
+ bExtensionMode = false;
+ if( pExtensionPath && pExtensionPath->length() > 0 )
+ {
+ helpFiles.clear();
+ bExtensionMode = true;
+ extensionPath = *pExtensionPath;
+ sourceRoot = fs::path(extensionPath);
+
+ aOfficeHelpPath = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/help") );
+ rtl::Bootstrap::expandMacros( aOfficeHelpPath );
+ }
+ if (args.size() > 0 && args[0][0] == '@')
+ {
+ std::vector<std::string> stringList;
+ std::string strBuf;
+ std::ifstream fileReader(args[0].substr(1).c_str());
+
+ while (fileReader)
+ {
+ std::string token;
+ fileReader >> token;
+ if (!token.empty())
+ stringList.push_back(token);
+ }
+ fileReader.close();
+
+ args = stringList;
+ }
+
+ size_t i = 0;
+
+ while (i < args.size())
+ {
+ if (args[i].compare("-src") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "sourceroot missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ if( !bExtensionMode )
+ sourceRoot = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-sty") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "embeddingStylesheet missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ embeddStylesheet = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-zipdir") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "idxtemp missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ zipdir = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-idxcaption") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "idxcaption stylesheet missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ idxCaptionStylesheet = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-idxcontent") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "idxcontent stylesheet missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ idxContentStylesheet = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-o") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "outputfilename missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ outputFile = fs::path(args[i], fs::native);
+ }
+ else if (args[i].compare("-mod") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "module name missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ module = args[i];
+ }
+ else if (args[i].compare("-lang") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "language name missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ lang = args[i];
+ }
+ else if (args[i].compare("-hid") == 0)
+ {
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "hid list missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ hid = args[i];
+ }
+ else if (args[i].compare("-add") == 0)
+ {
+ std::string addFile, addFileUnderPath;
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "pathname missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ addFileUnderPath = args[i];
+ ++i;
+ if (i >= args.size())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "pathname missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ addFile = args[i];
+ if (!addFileUnderPath.empty() && !addFile.empty())
+ additionalFiles[addFileUnderPath] = addFile;
+ }
+ else
+ helpFiles.push_back(args[i]);
+ ++i;
+ }
+
+ if (!bExtensionMode && zipdir.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no index dir given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (!bExtensionMode && idxCaptionStylesheet.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no index caption stylesheet given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ else if ( bExtensionMode )
+ {
+ rtl::OUString aIdxCaptionPathFileURL( aOfficeHelpPath );
+ aIdxCaptionPathFileURL += rtl::OUString::createFromAscii( "/idxcaption.xsl" );
+
+ rtl::OString aOStr_IdxCaptionPathFileURL( rtl::OUStringToOString
+ ( aIdxCaptionPathFileURL, fs::getThreadTextEncoding() ) );
+ std::string aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL.getStr() );
+
+ idxCaptionStylesheet = fs::path( aStdStr_IdxCaptionPathFileURL );
+ }
+ if (!bExtensionMode && idxContentStylesheet.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no index content stylesheet given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ else if ( bExtensionMode )
+ {
+ rtl::OUString aIdxContentPathFileURL( aOfficeHelpPath );
+ aIdxContentPathFileURL += rtl::OUString::createFromAscii( "/idxcontent.xsl" );
+
+ rtl::OString aOStr_IdxContentPathFileURL( rtl::OUStringToOString
+ ( aIdxContentPathFileURL, fs::getThreadTextEncoding() ) );
+ std::string aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL.getStr() );
+
+ idxContentStylesheet = fs::path( aStdStr_IdxContentPathFileURL );
+ }
+ if (!bExtensionMode && embeddStylesheet.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no embedding resolving file given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (sourceRoot.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no sourceroot given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (!bExtensionMode && outputFile.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "no output file given" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (module.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "module missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (!bExtensionMode && lang.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "language missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+ if (!bExtensionMode && hid.empty())
+ {
+ std::stringstream aStrStream;
+ aStrStream << "hid list missing" << std::endl;
+ throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+ }
+
+ link();
+}
+
+int main(int argc, char**argv)
+{
+ sal_uInt32 starttime = osl_getGlobalTimer();
+ std::vector<std::string> args;
+ for (int i = 1; i < argc; ++i)
+ args.push_back(std::string(argv[i]));
+ try
+ {
+ HelpLinker* pHelpLinker = new HelpLinker();
+ pHelpLinker->main( args );
+ delete pHelpLinker;
+ }
+ catch( const HelpProcessingException& e )
+ {
+ std::cerr << e.m_aErrorMsg;
+ exit(1);
+ }
+ sal_uInt32 endtime = osl_getGlobalTimer();
+#ifndef OS2 // YD @TODO@ crashes libc runtime :-(
+ std::cout << "time taken was " << (endtime-starttime)/1000.0 << " seconds" << std::endl;
+#endif
+ return 0;
+}
+
+// Variable to set an exception in "C" StructuredXMLErrorFunction
+static const HelpProcessingException* GpXMLParsingException = NULL;
+
+extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
+{
+ (void)userData;
+ (void)error;
+
+ std::string aErrorMsg = error->message;
+ std::string aXMLParsingFile;
+ if( error->file != NULL )
+ aXMLParsingFile = error->file;
+ int nXMLParsingLine = error->line;
+ HelpProcessingException* pException = new HelpProcessingException( aErrorMsg, aXMLParsingFile, nXMLParsingLine );
+ GpXMLParsingException = pException;
+
+ // Reset error handler
+ xmlSetStructuredErrorFunc( NULL, NULL );
+}
+
+HelpProcessingErrorInfo& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException& e )
+{
+ m_eErrorClass = e.m_eErrorClass;
+ rtl::OString tmpErrorMsg( e.m_aErrorMsg.c_str() );
+ m_aErrorMsg = rtl::OStringToOUString( tmpErrorMsg, fs::getThreadTextEncoding() );
+ rtl::OString tmpXMLParsingFile( e.m_aXMLParsingFile.c_str() );
+ m_aXMLParsingFile = rtl::OStringToOUString( tmpXMLParsingFile, fs::getThreadTextEncoding() );
+ m_nXMLParsingLine = e.m_nXMLParsingLine;
+ return *this;
+}
+
+
+// Returns true in case of success, false in case of error
+HELPLINKER_DLLPUBLIC bool compileExtensionHelp
+(
+ const rtl::OUString& aExtensionName,
+ const rtl::OUString& aExtensionLanguageRoot,
+ sal_Int32 nXhpFileCount, const rtl::OUString* pXhpFiles,
+ HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo
+)
+{
+ bool bSuccess = true;
+
+ sal_Int32 argc = nXhpFileCount + 3;
+ const char** argv = new const char*[argc];
+ argv[0] = "";
+ argv[1] = "-mod";
+ rtl::OString aOExtensionName = rtl::OUStringToOString( aExtensionName, fs::getThreadTextEncoding() );
+ argv[2] = aOExtensionName.getStr();
+
+ for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
+ {
+ rtl::OUString aXhpFile = pXhpFiles[iXhp];
+
+ rtl::OString aOXhpFile = rtl::OUStringToOString( aXhpFile, fs::getThreadTextEncoding() );
+ char* pArgStr = new char[aOXhpFile.getLength() + 1];
+ strcpy( pArgStr, aOXhpFile.getStr() );
+ argv[iXhp + 3] = pArgStr;
+ }
+
+ std::vector<std::string> args;
+ for( sal_Int32 i = 1; i < argc; ++i )
+ args.push_back(std::string( argv[i]) );
+
+ for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
+ delete argv[iXhp + 3];
+ delete[] argv;
+
+ rtl::OString aOExtensionLanguageRoot = rtl::OUStringToOString( aExtensionLanguageRoot, fs::getThreadTextEncoding() );
+ const char* pExtensionPath = aOExtensionLanguageRoot.getStr();
+ std::string aStdStrExtensionPath = pExtensionPath;
+
+ // Set error handler
+ xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
+ try
+ {
+ HelpLinker* pHelpLinker = new HelpLinker();
+ pHelpLinker->main( args,&aStdStrExtensionPath );
+ delete pHelpLinker;
+ }
+ catch( const HelpProcessingException& e )
+ {
+ if( GpXMLParsingException != NULL )
+ {
+ o_rHelpProcessingErrorInfo = *GpXMLParsingException;
+ delete GpXMLParsingException;
+ GpXMLParsingException = NULL;
+ }
+ else
+ {
+ o_rHelpProcessingErrorInfo = e;
+ }
+ bSuccess = false;
+ }
+ // Reset error handler
+ xmlSetStructuredErrorFunc( NULL, NULL );
+
+ // i83624: Tree files
+ ::rtl::OUString aTreeFileURL = aExtensionLanguageRoot;
+ aTreeFileURL += rtl::OUString::createFromAscii( "/help.tree" );
+ osl::DirectoryItem aTreeFileItem;
+ osl::FileBase::RC rcGet = osl::DirectoryItem::get( aTreeFileURL, aTreeFileItem );
+ osl::FileStatus aFileStatus( FileStatusMask_FileSize );
+ if( rcGet == osl::FileBase::E_None &&
+ aTreeFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None &&
+ aFileStatus.isValid( FileStatusMask_FileSize ) )
+ {
+ sal_uInt64 ret, len = aFileStatus.getFileSize();
+ char* s = new char[ int(len) ]; // the buffer to hold the installed files
+ osl::File aFile( aTreeFileURL );
+ aFile.open( OpenFlag_Read );
+ aFile.read( s, len, ret );
+ aFile.close();
+
+ XML_Parser parser = XML_ParserCreate( 0 );
+ int parsed = XML_Parse( parser, s, int( len ), true );
+
+ if( parsed == 0 )
+ {
+ XML_Error nError = XML_GetErrorCode( parser );
+ o_rHelpProcessingErrorInfo.m_eErrorClass = HELPPROCESSING_XMLPARSING_ERROR;
+ o_rHelpProcessingErrorInfo.m_aErrorMsg = rtl::OUString::createFromAscii( XML_ErrorString( nError ) );;
+ o_rHelpProcessingErrorInfo.m_aXMLParsingFile = aTreeFileURL;
+ // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
+ bSuccess = false;
+ }
+
+ XML_ParserFree( parser );
+ delete[] s;
+ }
+
+ return bSuccess;
+}
+
+// vnd.sun.star.help://swriter/52821?Language=en-US&System=UNIX
+/* vi:set tabstop=4 shiftwidth=4 expandtab: */
+
diff --git a/transex3/source/help/MANIFEST.MF b/transex3/source/help/MANIFEST.MF
new file mode 100644
index 000000000000..bf0e4ab46cb2
--- /dev/null
+++ b/transex3/source/help/MANIFEST.MF
@@ -0,0 +1,2 @@
+RegistrationClassName: com.sun.star.help.HelpComponent
+Class-Path: lucene-core-2.3.jar lucene-analyzers-2.3.jar
diff --git a/transex3/source/help/compilehelp.hxx b/transex3/source/help/compilehelp.hxx
new file mode 100644
index 000000000000..1e9a1c8604b8
--- /dev/null
+++ b/transex3/source/help/compilehelp.hxx
@@ -0,0 +1,80 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: compilehelp.hxx,v $
+ * $Revision: 1.3 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef COMPILE_HXX
+#define COMPILE_HXX
+
+#include "sal/types.h"
+
+#if defined(HELPLINKER_DLLIMPLEMENTATION)
+#define HELPLINKER_DLLPUBLIC SAL_DLLPUBLIC_EXPORT
+#else
+#define HELPLINKER_DLLPUBLIC SAL_DLLPUBLIC_IMPORT
+#endif
+#define HELPLINKER_DLLPRIVATE SAL_DLLPRIVATE
+
+
+//#include <helplinkerdllapi.h>
+#include <rtl/ustring.hxx>
+
+enum HelpProcessingErrorClass
+{
+ HELPPROCESSING_NO_ERROR,
+ HELPPROCESSING_GENERAL_ERROR, // Missing files, options etc.
+ HELPPROCESSING_INTERNAL_ERROR, // Unexpected problems
+ HELPPROCESSING_XMLPARSING_ERROR // Errors thrown by libxml
+};
+
+struct HelpProcessingErrorInfo
+{
+ HelpProcessingErrorClass m_eErrorClass;
+ rtl::OUString m_aErrorMsg;
+ rtl::OUString m_aXMLParsingFile;
+ sal_Int32 m_nXMLParsingLine;
+
+ HelpProcessingErrorInfo( void )
+ : m_eErrorClass( HELPPROCESSING_NO_ERROR )
+ , m_nXMLParsingLine( -1 )
+ {}
+
+ HelpProcessingErrorInfo& operator=( const struct HelpProcessingException& e );
+};
+
+
+// Returns true in case of success, false in case of error
+HELPLINKER_DLLPUBLIC bool compileExtensionHelp
+(
+ const rtl::OUString& aExtensionName,
+ const rtl::OUString& aExtensionLanguageRoot,
+ sal_Int32 nXhpFileCount, const rtl::OUString* pXhpFiles,
+ HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo
+);
+
+#endif
diff --git a/transex3/source/help/helplinker.pmk b/transex3/source/help/helplinker.pmk
new file mode 100644
index 000000000000..569c5f4dbdee
--- /dev/null
+++ b/transex3/source/help/helplinker.pmk
@@ -0,0 +1,35 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: helplinker.pmk,v $
+#
+# $Revision: 1.4 $
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+# define HELPLINKER_DLLIMPLEMENTATION (see @ inc/xmlhelp/helplinkerdllapi.h)
+CDEFS += -DHELPLINKER_DLLIMPLEMENTATION
+
+VISIBILITY_HIDDEN=TRUE
diff --git a/transex3/source/help/makefile.mk b/transex3/source/help/makefile.mk
new file mode 100644
index 000000000000..f010e256368e
--- /dev/null
+++ b/transex3/source/help/makefile.mk
@@ -0,0 +1,139 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.38 $
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org 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 version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ = ..$/..
+PRJNAME = xmlhelp
+TARGET = HelpLinker
+LIBBASENAME = helplinker
+PACKAGE = com$/sun$/star$/help
+TARGETTYPE=CUI
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : helplinker.pmk
+
+.IF "$(SYSTEM_LIBXSLT)" == "YES"
+CFLAGS+= $(LIBXSLT_CFLAGS)
+.ELSE
+LIBXSLTINCDIR=external$/libxslt
+CFLAGS+= -I$(SOLARINCDIR)$/$(LIBXSLTINCDIR)
+.ENDIF
+
+.IF "$(SYSTEM_DB)" == "YES"
+CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES)
+.ENDIF
+
+.IF "$(SYSTEM_EXPAT)" == "YES"
+CFLAGS+=-DSYSTEM_EXPAT
+.ENDIF
+
+OBJFILES=\
+ $(OBJ)$/HelpLinker.obj \
+ $(OBJ)$/HelpCompiler.obj
+SLOFILES=\
+ $(SLO)$/HelpLinker.obj \
+ $(SLO)$/HelpCompiler.obj
+
+EXCEPTIONSFILES=\
+ $(OBJ)$/HelpLinker.obj \
+ $(OBJ)$/HelpCompiler.obj \
+ $(SLO)$/HelpLinker.obj \
+ $(SLO)$/HelpCompiler.obj
+.IF "$(OS)" == "MACOSX" && "$(CPU)" == "P" && "$(COM)" == "GCC"
+# There appears to be a GCC 4.0.1 optimization error causing _file:good() to
+# report true right before the call to writeOut at HelpLinker.cxx:1.12 l. 954
+# but out.good() to report false right at the start of writeOut at
+# HelpLinker.cxx:1.12 l. 537:
+NOOPTFILES=\
+ $(OBJ)$/HelpLinker.obj \
+ $(SLO)$/HelpLinker.obj
+.ENDIF
+
+APP1TARGET= $(TARGET)
+APP1OBJS=\
+ $(OBJ)$/HelpLinker.obj \
+ $(OBJ)$/HelpCompiler.obj
+
+APP1STDLIBS+=$(SALLIB) $(BERKELEYLIB) $(XSLTLIB) $(EXPATASCII3RDLIB)
+
+SHL1TARGET =$(LIBBASENAME)$(DLLPOSTFIX)
+SHL1LIBS= $(SLB)$/$(TARGET).lib
+SHL1IMPLIB =i$(LIBBASENAME)
+SHL1DEF =$(MISC)$/$(SHL1TARGET).def
+SHL1STDLIBS =$(SALLIB) $(BERKELEYLIB) $(XSLTLIB) $(EXPATASCII3RDLIB)
+SHL1USE_EXPORTS =ordinal
+
+DEF1NAME =$(SHL1TARGET)
+DEFLIB1NAME =$(TARGET)
+
+JAVAFILES = \
+ HelpIndexerTool.java \
+ HelpFileDocument.java
+
+
+JAVACLASSFILES = \
+ $(CLASSDIR)$/$(PACKAGE)$/HelpIndexerTool.class \
+ $(CLASSDIR)$/$(PACKAGE)$/HelpFileDocument.class
+
+
+# $(CLASSDIR)$/$(PACKAGE)$/HelpSearch.class \
+# $(CLASSDIR)$/$(PACKAGE)$/HelpIndexer.class \
+# $(CLASSDIR)$/$(PACKAGE)$/HelpComponent.class \
+# $(CLASSDIR)$/$(PACKAGE)$/HelpFileDocument.class
+
+#JARFILES = ridl.jar jurt.jar unoil.jar juh.jar
+.IF "$(SYSTEM_LUCENE)" == "YES"
+XCLASSPATH!:=$(XCLASSPATH)$(PATH_SEPERATOR)$(LUCENE_CORE_JAR)$(PATH_SEPERATOR)$(LUCENE_ANALYZERS_JAR)
+COMP=fix_system_lucene
+.ELSE
+JARFILES += lucene-core-2.3.jar lucene-analyzers-2.3.jar
+.ENDIF
+JAVAFILES = $(subst,$(CLASSDIR)$/$(PACKAGE)$/, $(subst,.class,.java $(JAVACLASSFILES)))
+#JAVAFILES = $(JAVACLASSFILES)
+
+JARCLASSDIRS = $(PACKAGE)/*
+JARTARGET = HelpIndexerTool.jar
+JARCOMPRESS = TRUE
+#CUSTOMMANIFESTFILE = MANIFEST.MF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
+
+.IF "$(JARTARGETN)"!=""
+$(JARTARGETN) : $(COMP)
+.ENDIF
+
+fix_system_lucene:
+ @echo "Fix Java Class-Path entry for Lucene libraries from system."
+ @$(SED) -r -e "s#^(Class-Path:).*#\1 file://$(LUCENE_CORE_JAR) file://$(LUCENE_ANALYZERS_JAR)#" \
+ -i ../../../../../$(INPATH)/class/HelpLinker/META-INF/MANIFEST.MF