You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by ja...@apache.org on 2013/10/03 22:16:17 UTC

svn commit: r1528993 [1/2] - in /openoffice/branches/l10n40/main/l10ntools/source/help: ./ HelpCompiler.cxx HelpCompiler.hxx HelpFileDocument.java HelpIndexerTool.java HelpLinker.cxx compilehelp.hxx helplinker.pmk makefile.mk

Author: jani
Date: Thu Oct  3 20:16:17 2013
New Revision: 1528993

URL: http://svn.apache.org/r1528993
Log:
and add the helpIndexer

Added:
    openoffice/branches/l10n40/main/l10ntools/source/help/
    openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.cxx
    openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.hxx
    openoffice/branches/l10n40/main/l10ntools/source/help/HelpFileDocument.java
    openoffice/branches/l10n40/main/l10ntools/source/help/HelpIndexerTool.java
    openoffice/branches/l10n40/main/l10ntools/source/help/HelpLinker.cxx
    openoffice/branches/l10n40/main/l10ntools/source/help/compilehelp.hxx
    openoffice/branches/l10n40/main/l10ntools/source/help/helplinker.pmk
    openoffice/branches/l10n40/main/l10ntools/source/help/makefile.mk

Added: openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.cxx
URL: http://svn.apache.org/viewvc/openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.cxx?rev=1528993&view=auto
==============================================================================
--- openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.cxx (added)
+++ openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.cxx Thu Oct  3 20:16:17 2013
@@ -0,0 +1,586 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the 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: */

Added: openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.hxx
URL: http://svn.apache.org/viewvc/openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.hxx?rev=1528993&view=auto
==============================================================================
--- openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.hxx (added)
+++ openoffice/branches/l10n40/main/l10ntools/source/help/HelpCompiler.hxx Thu Oct  3 20:16:17 2013
@@ -0,0 +1,316 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the 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>
+
+#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());
+        }
+#ifdef WNT
+        wchar_t const * native_file_string_w() const
+        {
+            ::rtl::OUString ustrSystemPath;
+            osl::File::getSystemPathFromFileURL(data, ustrSystemPath);
+            return reinterpret_cast< wchar_t const * >(ustrSystemPath.getStr());
+        }
+#endif
+        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: */

Added: openoffice/branches/l10n40/main/l10ntools/source/help/HelpFileDocument.java
URL: http://svn.apache.org/viewvc/openoffice/branches/l10n40/main/l10ntools/source/help/HelpFileDocument.java?rev=1528993&view=auto
==============================================================================
--- openoffice/branches/l10n40/main/l10ntools/source/help/HelpFileDocument.java (added)
+++ openoffice/branches/l10n40/main/l10ntools/source/help/HelpFileDocument.java Thu Oct  3 20:16:17 2013
@@ -0,0 +1,82 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the 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.NOT_ANALYZED));
+		}
+		
+		// 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() {}
+}

Added: openoffice/branches/l10n40/main/l10ntools/source/help/HelpIndexerTool.java
URL: http://svn.apache.org/viewvc/openoffice/branches/l10n40/main/l10ntools/source/help/HelpIndexerTool.java?rev=1528993&view=auto
==============================================================================
--- openoffice/branches/l10n40/main/l10ntools/source/help/HelpIndexerTool.java (added)
+++ openoffice/branches/l10n40/main/l10ntools/source/help/HelpIndexerTool.java Thu Oct  3 20:16:17 2013
@@ -0,0 +1,408 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the 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 org.apache.lucene.util.Version;
+import org.apache.lucene.store.NIOFSDirectory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+   When this tool is used with long path names on Windows, that is paths which start
+   with \\?\, then the caller must make sure that the path is unique. This is achieved
+   by removing '.' and '..' from the path. Paths which are created by
+   osl_getSystemPathFromFileURL fulfill this requirement. This is necessary because
+   lucene is patched to not use File.getCanonicalPath. See long_path.patch in the lucene
+   module.
+ */
+
+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 = "";
+        String aSegmentName = "";
+
+        // Scan arguments
+        //If this tool is invoked in the build process for extensions help,
+        //then -extension must be set.
+        boolean bExtension = false;
+        boolean bLang = false;
+        boolean bMod = false;
+        boolean bZipDir = false;
+        boolean bSrcDir = false;
+        boolean bOutput = false;
+        boolean bCfsName = false;
+        boolean bSegmentName = false;
+
+        int nArgCount = args.length;
+        for( int i = 0 ; i < nArgCount ; i++ )
+		{
+            if( "-extension".equals(args[i]) )
+			{
+                bExtension = true;
+            }            
+            else 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( "-checkcfsandsegname".equals(args[i]) )
+			{
+                if( i + 1 < nArgCount )
+				{
+                    aCfsName = args[i + 1] + ".cfs";
+                    bCfsName = true;
+                }
+                i++;
+                if( i + 1 < nArgCount )
+				{
+                    aSegmentName = "segments" + args[i + 1];
+                    bSegmentName = true;
+                }
+                i++;
+                if (!(bCfsName && bSegmentName))
+                {
+                    System.out.println("Usage: HelpIndexer -checkcfsandsegname _0 _3 (2 arguments needed)");
+                    System.exit( -1 );
+                }
+            }
+        }
+
+        if( !bLang || !bMod || !bZipDir || (!bOutput && !bExtensionMode && !bExtension) )
+		{
+			if( bExtensionMode )
+				return;
+
+			System.out.println("Usage: HelpIndexer -lang ISOLangCode -mod HelpModule -zipdir TempZipDir -o OutputZipFile");
+            System.out.println("Usage: HelpIndexer -extension -lang ISOLangCode -mod HelpModule -zipdir PathToLangDir");
+			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(Version.LUCENE_29) : (Analyzer)new StandardAnalyzer(Version.LUCENE_29);
+	    IndexWriter writer = new IndexWriter( NIOFSDirectory.open(aIndexDir), analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED );
+			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;
+			boolean bSegmentFileOk = true;
+			if( bCfsName && bSegmentName && !bExtensionMode && nRet != -1 )
+			{
+				String aCompleteCfsFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aCfsName;
+				String aCompleteSegmentFileName = aDirToZipStr + File.separator + aIndexDirName + File.separator + aSegmentName;
+				File aCfsFile = new File( aCompleteCfsFileName );
+				File aSegmentFile = new File( aCompleteSegmentFileName );
+				bCfsFileOk = aCfsFile.exists();
+				bSegmentFileOk = aSegmentFile.exists();
+				System.out.println( "Checking cfs file " + aCfsName+ ": " + (bCfsFileOk ? "Found" : "Not found") );
+				System.out.println( "Checking segment file " + aSegmentName+ ": " + (bSegmentFileOk ? "Found" : "Not found") );
+			}
+
+			if( bExtensionMode || bExtension)
+			{
+				if( !bSrcDir )
+				{
+					deleteRecursively( aCaptionFilesDir );
+					deleteRecursively( aContentFilesDir );
+				}
+			}
+			else
+			{
+				if( nRet == -1 )
+					deleteRecursively( aIndexDir );
+
+				if( bCfsFileOk && bSegmentFileOk )
+					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 );
+			}
+
+			if( !bSegmentFileOk )
+			{
+				System.out.println( "segment 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();
+    }
+}
+

Added: openoffice/branches/l10n40/main/l10ntools/source/help/HelpLinker.cxx
URL: http://svn.apache.org/viewvc/openoffice/branches/l10n40/main/l10ntools/source/help/HelpLinker.cxx?rev=1528993&view=auto
==============================================================================
--- openoffice/branches/l10n40/main/l10ntools/source/help/HelpLinker.cxx (added)
+++ openoffice/branches/l10n40/main/l10ntools/source/help/HelpLinker.cxx Thu Oct  3 20:16:17 2013
@@ -0,0 +1,1095 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the 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>
+
+#include <expat.h>
+
+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 );
+
+    if( m_xsltStylesheetPtrCaption )
+    {
+        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();
+#ifdef WNT     //We need _wfopen to support long file paths on Windows XP
+            FILE* pFile_docURL = _wfopen(
+                fsCaptionPureTextFile_docURL.native_file_string_w(), L"w" );
+#else            
+            FILE* pFile_docURL = fopen(
+                fsCaptionPureTextFile_docURL.native_file_string().c_str(), "w" );
+#endif            
+            if( pFile_docURL )
+            {
+                fprintf( pFile_docURL, "%s\n", pResNodeCaption->content );
+                fclose( pFile_docURL );
+            }
+        }
+        xmlFreeDoc(resCaption);
+    }
+
+    if( m_xsltStylesheetPtrContent )
+    {
+        xmlDocPtr resContent = xsltApplyStylesheet( m_xsltStylesheetPtrContent, doc, NULL );
+        xmlNodePtr pResNodeContent = resContent->xmlChildrenNode;
+        if( pResNodeContent )
+        {
+            fs::path fsContentPureTextFile_docURL = m_fsContentFilesDirName / aStdStr_EncodedDocPathURL;
+#ifdef WNT     //We need _wfopen to support long file paths on Windows XP
+            FILE* pFile_docURL = _wfopen(
+                fsContentPureTextFile_docURL.native_file_string_w(), L"w" );
+#else            
+            FILE* pFile_docURL = fopen(
+                fsContentPureTextFile_docURL.native_file_string().c_str(), "w" );
+#endif            
+            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;
+    unsigned int nKeyLen = aKeyStr.length();
+    unsigned int nValueLen = aValueStr.length();
+    fprintf( pFile, "%x ", nKeyLen );
+    if( nKeyLen > 0 )
+    {
+        if (fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile ) != nKeyLen)
+            fprintf(stderr, "fwrite to db failed\n");
+    }
+    if (fprintf( pFile, " %x ", nValueLen ) < 0)
+        fprintf(stderr, "fwrite to db failed\n");
+    if( nValueLen > 0 )
+    {
+        if (fwrite( aValueStr.c_str(), 1, nValueLen, pFile ) != nValueLen)
+            fprintf(stderr, "fwrite to db failed\n");
+    }
+    if (fprintf( pFile, "%c", cLF ) < 0)
+        fprintf(stderr, "fwrite to db failed\n");
+}
+
+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_DBHelp( const fs::path& rFileName )
+    {
+#ifdef WNT     //We need _wfopen to support long file paths on Windows XP
+        FILE* pFile = _wfopen( rFileName.native_file_string_w(), L"wb" );
+#else        
+        FILE* pFile = fopen( rFileName.native_file_string().c_str(), "wb" );
+#endif        
+        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,
+              std::string* pDestination = NULL,
+              const rtl::OUString* pOfficeHelpPath = 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 extsource;
+    std::string extdestination;
+    std::string module;
+    std::string lang;
+    std::string extensionPath;
+    std::string extensionDestination;
+    bool bExtensionMode;
+    fs::path indexDirName;
+    fs::path indexDirParentName;
+    bool init;
+    IndexerPreProcessor* m_pIndexerPreProcessor;
+    void initIndexerPreProcessor();
+    void link() throw( HelpProcessingException );
+    void addBookmark( FILE* pFile_DBHelp, std::string thishid,
+        const std::string& fileB, const std::string& anchorB,
+        const std::string& jarfileB, const std::string& titleB );
+};
+
+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( 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);
+
+    thishid = URLEncoder::encode(thishid);
+
+    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];
+
+    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;
+        indexDirParentName = extensionDestination;
+    }
+    else
+    {
+        indexDirParentName = zipdir;
+        fs::create_directory(indexDirParentName);
+    }
+
+    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;
+    if( !bExtensionMode )
+        bUse_ = false;
+
+    fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht")));
+#ifdef WNT
+    //We need _wfopen to support long file paths on Windows XP
+    FILE* pFileHelpText_DBHelp = _wfopen
+        ( helpTextFileName_DBHelp.native_file_string_w(), L"wb" );
+#else
+    
+    FILE* pFileHelpText_DBHelp = fopen
+        ( helpTextFileName_DBHelp.native_file_string().c_str(), "wb" );
+#endif
+
+    fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db")));
+#ifdef WNT
+    //We need _wfopen to support long file paths on Windows XP
+    FILE* pFileDbBase_DBHelp = _wfopen
+        ( dbBaseFileName_DBHelp.native_file_string_w(), L"wb" );
+#else    
+    FILE* pFileDbBase_DBHelp = fopen
+        ( dbBaseFileName_DBHelp.native_file_string().c_str(), "wb" );
+#endif    
+
+    fs::path keyWordFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".key_" : ".key")));
+
+    HelpKeyword helpKeyword;
+
+    // catch HelpProcessingException to avoid locking data bases
+    try
+    {
+
+    // 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>";
+
+        const std::string& fileB = documentPath;
+        const std::string& jarfileB = documentJarfile;
+        std::string& titleB = documentTitle;
+
+        // add once this as its own id.
+        addBookmark(pFileDbBase_DBHelp, documentPath, fileB, std::string(), jarfileB, titleB);
+
+        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(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(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;
+
+                helpTextId = URLEncoder::encode(helpTextId);
+
+                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( const HelpProcessingException& )
+    {
+        // catch HelpProcessingException to avoid locking data bases
+        if( pFileHelpText_DBHelp != NULL )
+            fclose( pFileHelpText_DBHelp );
+        if( pFileDbBase_DBHelp != NULL )
+            fclose( pFileDbBase_DBHelp );
+        throw;
+    }
+
+    if( pFileHelpText_DBHelp != NULL )
+        fclose( pFileHelpText_DBHelp );
+    if( pFileDbBase_DBHelp != NULL )
+        fclose( pFileDbBase_DBHelp );
+
+    helpKeyword.dump_DBHelp( keyWordFileName_DBHelp);
+
+    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 );
+        }
+    }
+
+}
+
+
+void HelpLinker::main( std::vector<std::string> &args,
+                       std::string* pExtensionPath, std::string* pDestination,
+                       const rtl::OUString* pOfficeHelpPath )
+    throw( HelpProcessingException )
+{
+    bExtensionMode = false;
+    helpFiles.clear();
+
+    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;
+    bool bSrcOption = false;
+    while (i < args.size())
+    {
+        if (args[i].compare("-extlangsrc") == 0)
+        {
+            ++i;
+            if (i >= args.size())
+            {
+                std::stringstream aStrStream;
+                aStrStream << "extension source missing" << std::endl;
+                throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+            }
+            extsource = args[i];
+        }
+        else if (args[i].compare("-extlangdest") == 0)
+        {
+            //If this argument is not provided then the location provided in -extsource will
+            //also be the destination
+            ++i;
+            if (i >= args.size())
+            {
+                std::stringstream aStrStream;
+                aStrStream << "extension destination missing" << std::endl;
+                throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+            }
+            extdestination = args[i];
+        }
+        else 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() );
+            }
+            bSrcOption = true;
+            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;
+            throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, "obsolete -hid argument used" );
+        }
+        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;
+    }
+
+    //We can be called from the helplinker executable or the extension manager
+    //In the latter case extsource is not used.
+    if( (pExtensionPath && pExtensionPath->length() > 0 && pOfficeHelpPath)
+        || !extsource.empty())
+    {
+        bExtensionMode = true;
+        if (!extsource.empty())
+        {
+            //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
+            //should be NULL
+            sourceRoot = fs::path(extsource, fs::native);
+            extensionPath = sourceRoot.toUTF8();
+
+            if (extdestination.empty())
+            {
+                std::stringstream aStrStream;
+                aStrStream << "-extlangdest is missing" << std::endl;
+                throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+            }
+            else
+            {
+                //Convert from system path to file URL!!!
+                fs::path p(extdestination, fs::native);
+                extensionDestination = p.toUTF8();
+            }
+        }
+        else
+        { //called from extension manager
+            extensionPath = *pExtensionPath;
+            sourceRoot = fs::path(extensionPath);
+            extensionDestination = *pDestination;
+        }
+        //check if -src option was used. This option must not be used
+        //when extension help is compiled.
+        if (bSrcOption)
+        {
+            std::stringstream aStrStream;
+            aStrStream << "-src must not be used together with -extsource missing" << std::endl;
+            throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+        }
+    }
+
+    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()
+        || !extsource.empty() && idxCaptionStylesheet.empty())
+    {
+        //No extension mode and extension mode using commandline
+        //!extsource.empty indicates extension mode using commandline
+        // -idxcaption paramter is required
+        std::stringstream aStrStream;
+        aStrStream << "no index caption stylesheet given" << std::endl;
+        throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+    }
+    else if ( bExtensionMode &&  extsource.empty())
+    {
+        //This part is used when compileExtensionHelp is called from the extensions manager.
+        //If extension help is compiled using helplinker in the build process
+        rtl::OUString aIdxCaptionPathFileURL( *pOfficeHelpPath );
+        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()
+        || !extsource.empty() && idxContentStylesheet.empty())
+    {
+        //No extension mode and extension mode using commandline
+        //!extsource.empty indicates extension mode using commandline
+        // -idxcontent paramter is required
+        std::stringstream aStrStream;
+        aStrStream << "no index content stylesheet given" << std::endl;
+        throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
+    }
+    else if ( bExtensionMode && extsource.empty())
+    {
+        //If extension help is compiled using helplinker in the build process
+        //then  -idxcontent must be supplied
+        //This part is used when compileExtensionHelp is called from the extensions manager.
+        rtl::OUString aIdxContentPathFileURL( *pOfficeHelpPath );
+        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() );
+    }
+    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& aOfficeHelpPath,
+    const rtl::OUString& aExtensionName,
+    const rtl::OUString& aExtensionLanguageRoot,
+    sal_Int32 nXhpFileCount, const rtl::OUString* pXhpFiles,
+    const rtl::OUString& aDestination,
+    HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo
+)
+{
+    bool bSuccess = true;
+
+    std::vector<std::string> args;
+    args.reserve(nXhpFileCount + 2);
+    args.push_back(std::string("-mod"));
+    rtl::OString aOExtensionName = rtl::OUStringToOString( aExtensionName, fs::getThreadTextEncoding() );
+    args.push_back(std::string(aOExtensionName.getStr()));
+
+    for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
+    {
+        rtl::OUString aXhpFile = pXhpFiles[iXhp];
+
+        rtl::OString aOXhpFile = rtl::OUStringToOString( aXhpFile, fs::getThreadTextEncoding() );
+        args.push_back(std::string(aOXhpFile.getStr()));
+    }
+
+    rtl::OString aOExtensionLanguageRoot = rtl::OUStringToOString( aExtensionLanguageRoot, fs::getThreadTextEncoding() );
+    const char* pExtensionPath = aOExtensionLanguageRoot.getStr();
+    std::string aStdStrExtensionPath = pExtensionPath;
+    rtl::OString aODestination = rtl::OUStringToOString(aDestination, fs::getThreadTextEncoding());
+    const char* pDestination = aODestination.getStr();
+    std::string aStdStrDestination = pDestination;
+
+    // Set error handler
+    xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
+    try
+    {
+        HelpLinker* pHelpLinker = new HelpLinker();
+        pHelpLinker->main( args, &aStdStrExtensionPath, &aStdStrDestination, &aOfficeHelpPath );
+        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;
+}
+