LCOV - code coverage report
Current view: top level - helpcompiler/source - HelpCompiler.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 1 253 0.4 %
Date: 2014-04-11 Functions: 2 18 11.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <HelpCompiler.hxx>
      22             : #include <BasCodeTagger.hxx>
      23             : #include <limits.h>
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : #include <libxslt/xslt.h>
      27             : #include <libxslt/xsltInternals.h>
      28             : #include <libxslt/transform.h>
      29             : #include <libxslt/xsltutils.h>
      30             : #include <osl/thread.hxx>
      31             : 
      32           0 : static void impl_sleep( sal_uInt32 nSec )
      33             : {
      34             :     TimeValue aTime;
      35           0 :     aTime.Seconds = nSec;
      36           0 :     aTime.Nanosec = 0;
      37             : 
      38           0 :     osl::Thread::wait( aTime );
      39           0 : }
      40           0 : HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile,
      41             :     const fs::path &in_src, const fs::path &in_zipdir, const fs::path &in_resCompactStylesheet,
      42             :     const fs::path &in_resEmbStylesheet, const std::string &in_module, const std::string &in_lang,
      43             :     bool in_bExtensionMode)
      44             :     : streamTable(in_streamTable), inputFile(in_inputFile),
      45             :     src(in_src), zipdir(in_zipdir), module(in_module), lang(in_lang), resCompactStylesheet(in_resCompactStylesheet),
      46           0 :     resEmbStylesheet(in_resEmbStylesheet), bExtensionMode( in_bExtensionMode )
      47             : {
      48           0 :     xmlKeepBlanksDefaultValue = 0;
      49           0 :     char* os = getenv("OS");
      50           0 :     if (os)
      51             :     {
      52           0 :         gui = (strcmp(os, "WNT") ? "UNIX" : "WIN");
      53           0 :         gui = (strcmp(os, "MACOSX") ? gui : "MAC");
      54             :     }
      55           0 : }
      56             : 
      57           0 : void HelpCompiler::tagBasicCodeExamples( xmlDocPtr doc )
      58             : {
      59             :     try
      60             :     {
      61           0 :         BasicCodeTagger bct( doc );
      62           0 :         bct.tagBasicCodes();
      63             :     }
      64           0 :     catch ( BasicCodeTagger::TaggerException &ex )
      65             :     {
      66           0 :         if ( ex != BasicCodeTagger::EMPTY_DOCUMENT )
      67           0 :             throw;
      68             :     }
      69           0 : }
      70             : 
      71           0 : xmlDocPtr HelpCompiler::compactXhpForJar( xmlDocPtr doc )
      72             : {
      73             :     static xsltStylesheetPtr compact = NULL;
      74             :     static const char *params[2 + 1];
      75           0 :     params[0] = NULL;
      76             :     xmlDocPtr compacted;
      77             : 
      78           0 :     if (!compact)
      79             :     {
      80           0 :         compact = xsltParseStylesheetFile((const xmlChar *)resCompactStylesheet.native_file_string().c_str());
      81             :     }
      82             : 
      83           0 :     compacted = xsltApplyStylesheet(compact, doc, params);
      84           0 :     return compacted;
      85             : }
      86             : 
      87           0 : void HelpCompiler::saveXhpForJar( xmlDocPtr doc, const fs::path &filePath )
      88             : {
      89             :     //save processed xhp document in ziptmp<module>_<lang>/text directory
      90             : #ifdef WNT
      91             :     std::string pathSep = "\\";
      92             : #else
      93           0 :     std::string pathSep = "/";
      94             : #endif
      95           0 :     const std::string& sourceXhpPath = filePath.native_file_string();
      96           0 :     std::string zipdirPath = zipdir.native_file_string();
      97           0 :     const std::string srcdirPath( src.native_file_string() );
      98             :     // srcdirPath contains trailing /, but we want the file path with / at the beginning
      99           0 :     std::string jarXhpPath = sourceXhpPath.substr( srcdirPath.length() - 1 );
     100           0 :     std::string xhpFileName = jarXhpPath.substr( jarXhpPath.rfind( pathSep ) + 1 );
     101           0 :     jarXhpPath = jarXhpPath.substr( 0, jarXhpPath.rfind( pathSep ) );
     102           0 :     if ( !jarXhpPath.compare( 1, 11, "text" + pathSep + "sbasic" ) )
     103             :     {
     104           0 :         tagBasicCodeExamples( doc );
     105             :     }
     106           0 :     if ( !jarXhpPath.compare( 1, 11, "text" + pathSep + "shared" ) )
     107             :     {
     108           0 :         const size_t pos = zipdirPath.find( "ziptmp" );
     109           0 :         if ( pos != std::string::npos )
     110           0 :             zipdirPath.replace( pos + 6, module.length(), "shared" );
     111             :     }
     112           0 :     xmlDocPtr compacted = compactXhpForJar( doc );
     113           0 :     fs::create_directory( fs::path( zipdirPath + jarXhpPath, fs::native ) );
     114           0 :     if ( -1 == xmlSaveFormatFileEnc( (zipdirPath + jarXhpPath + pathSep + xhpFileName).c_str(), compacted, "utf-8", 0 ) )
     115           0 :         std::cerr << "Error saving file to " << (zipdirPath + jarXhpPath + pathSep + xhpFileName).c_str() << std::endl;
     116           0 :     xmlFreeDoc(compacted);
     117           0 : }
     118             : 
     119             : 
     120           0 : xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath)
     121             : {
     122             :     static xsltStylesheetPtr cur = NULL;
     123             : 
     124             :     xmlDocPtr res;
     125           0 :     if( bExtensionMode )
     126             :     {
     127           0 :         res = xmlParseFile(filePath.native_file_string().c_str());
     128           0 :         if( !res ){
     129           0 :             impl_sleep( 3 );
     130           0 :             res = xmlParseFile(filePath.native_file_string().c_str());
     131             :         }
     132             :     }
     133             :     else
     134             :     {
     135             :         static const char *params[2 + 1];
     136           0 :         if (!cur)
     137             :         {
     138           0 :             static std::string fsroot('\'' + src.toUTF8() + '\'');
     139             : 
     140           0 :             xmlSubstituteEntitiesDefault(1);
     141           0 :             xmlLoadExtDtdDefaultValue = 1;
     142           0 :             cur = xsltParseStylesheetFile((const xmlChar *)resEmbStylesheet.native_file_string().c_str());
     143             : 
     144           0 :             int nbparams = 0;
     145           0 :             params[nbparams++] = "fsroot";
     146           0 :             params[nbparams++] = fsroot.c_str();
     147           0 :             params[nbparams] = NULL;
     148             :         }
     149           0 :         xmlDocPtr doc = xmlParseFile(filePath.native_file_string().c_str());
     150           0 :         if( !doc )
     151             :         {
     152           0 :             impl_sleep( 3 );
     153           0 :             doc = xmlParseFile(filePath.native_file_string().c_str());
     154             :         }
     155             : 
     156           0 :         saveXhpForJar( doc, filePath );
     157             : 
     158           0 :         res = xsltApplyStylesheet(cur, doc, params);
     159           0 :         xmlFreeDoc(doc);
     160             :     }
     161           0 :     return res;
     162             : }
     163             : 
     164             : // returns a node representing the whole stuff compiled for the current
     165             : // application.
     166           0 : xmlNodePtr HelpCompiler::clone(xmlNodePtr node, const std::string& appl)
     167             : {
     168           0 :     xmlNodePtr root = xmlCopyNode(node, 2);
     169           0 :     if (node->xmlChildrenNode)
     170             :     {
     171           0 :         xmlNodePtr list = node->xmlChildrenNode;
     172           0 :         while (list)
     173             :         {
     174           0 :             if (strcmp((const char*)list->name, "switchinline") == 0 || strcmp((const char*)list->name, "switch") == 0)
     175             :             {
     176           0 :                 std::string tmp="";
     177           0 :                 if (strcmp((const char*)xmlGetProp(list, (xmlChar*)"select"), "sys"))
     178             :                 {
     179           0 :                     tmp = gui;
     180             :                 }
     181           0 :                 if (strcmp((const char*)xmlGetProp(list, (xmlChar*)"select"), "appl"))
     182             :                 {
     183           0 :                     tmp = appl;
     184             :                 }
     185           0 :                 if (tmp.compare("") != 0)
     186             :                 {
     187           0 :                     bool isCase=false;
     188           0 :                     xmlNodePtr caseList=list->xmlChildrenNode;
     189           0 :                     while (caseList)
     190             :                     {
     191           0 :                         xmlChar *select = xmlGetProp(caseList, (xmlChar*)"select");
     192           0 :                         if (select)
     193             :                         {
     194           0 :                             if (!strcmp((const char*)select, tmp.c_str()) && !isCase)
     195             :                             {
     196           0 :                                 isCase=true;
     197           0 :                                 xmlNodePtr clp = caseList->xmlChildrenNode;
     198           0 :                                 while (clp)
     199             :                                 {
     200           0 :                                     xmlAddChild(root, clone(clp, appl));
     201           0 :                                     clp = clp->next;
     202             :                                 }
     203             :                             }
     204           0 :                             xmlFree(select);
     205             :                         }
     206             :                         else
     207             :                         {
     208           0 :                             if ((strcmp((const char*)caseList->name, "defaultinline") != 0) && (strcmp((const char*)caseList->name, "default") != 0))
     209             :                             {
     210           0 :                                 xmlAddChild(root, clone(caseList, appl));
     211             :                             }
     212             :                             else
     213             :                             {
     214           0 :                                 if (!isCase)
     215             :                                 {
     216           0 :                                     xmlNodePtr clp = caseList->xmlChildrenNode;
     217           0 :                                     while (clp)
     218             :                                     {
     219           0 :                                         xmlAddChild(root, clone(clp, appl));
     220           0 :                                         clp = clp->next;
     221             :                                     }
     222             :                                 }
     223             :                             }
     224             :                         }
     225           0 :                         caseList = caseList->next;
     226             :                     }
     227           0 :                 }
     228             :             }
     229             :             else
     230             :             {
     231           0 :                 xmlAddChild(root, clone(list, appl));
     232             :             }
     233           0 :             list = list->next;
     234             :         }
     235             :     }
     236           0 :     return root;
     237             : }
     238             : 
     239           0 : class myparser
     240             : {
     241             : public:
     242             :     std::string documentId;
     243             :     std::string fileName;
     244             :     std::string title;
     245             :     HashSet *hidlist;
     246             :     Hashtable *keywords;
     247             :     Stringtable *helptexts;
     248             : private:
     249             :     HashSet extendedHelpText;
     250             : public:
     251           0 :     myparser(const std::string &indocumentId, const std::string &infileName,
     252             :         const std::string &intitle) : documentId(indocumentId), fileName(infileName),
     253           0 :         title(intitle)
     254             :     {
     255           0 :         hidlist = new HashSet;
     256           0 :         keywords = new Hashtable;
     257           0 :         helptexts = new Stringtable;
     258           0 :     }
     259             :     void traverse( xmlNodePtr parentNode );
     260             : private:
     261             :     std::string module;
     262             :     std::string dump(xmlNodePtr node);
     263             : };
     264             : 
     265           0 : std::string myparser::dump(xmlNodePtr node)
     266             : {
     267           0 :     std::string app;
     268           0 :     if (node->xmlChildrenNode)
     269             :     {
     270           0 :         xmlNodePtr list = node->xmlChildrenNode;
     271           0 :         while (list)
     272             :         {
     273           0 :             app += dump(list);
     274           0 :             list = list->next;
     275             :         }
     276             :     }
     277           0 :     if (xmlNodeIsText(node))
     278             :     {
     279           0 :         xmlChar *pContent = xmlNodeGetContent(node);
     280           0 :         app += std::string((const char*)pContent);
     281           0 :         xmlFree(pContent);
     282             :     }
     283           0 :     return app;
     284             : }
     285             : 
     286           0 : void trim(std::string& str)
     287             : {
     288           0 :     std::string::size_type pos = str.find_last_not_of(' ');
     289           0 :     if(pos != std::string::npos)
     290             :     {
     291           0 :         str.erase(pos + 1);
     292           0 :         pos = str.find_first_not_of(' ');
     293           0 :         if(pos != std::string::npos)
     294           0 :             str.erase(0, pos);
     295             :     }
     296             :     else
     297           0 :         str.erase(str.begin(), str.end());
     298           0 : }
     299             : 
     300           0 : void myparser::traverse( xmlNodePtr parentNode )
     301             : {
     302             :     // traverse all nodes that belong to the parent
     303             :     xmlNodePtr test ;
     304           0 :     for (test = parentNode->xmlChildrenNode; test; test = test->next)
     305             :     {
     306           0 :         if (fileName.empty() && !strcmp((const char*)test->name, "filename"))
     307             :         {
     308           0 :             xmlNodePtr node = test->xmlChildrenNode;
     309           0 :             if (xmlNodeIsText(node))
     310             :             {
     311           0 :                 xmlChar *pContent = xmlNodeGetContent(node);
     312           0 :                 fileName = std::string((const char*)pContent);
     313           0 :                 xmlFree(pContent);
     314             :             }
     315             :         }
     316           0 :         else if (title.empty() && !strcmp((const char*)test->name, "title"))
     317             :         {
     318           0 :             title = dump(test);
     319           0 :             if (title.empty())
     320           0 :                 title = "<notitle>";
     321             :         }
     322           0 :         else if (!strcmp((const char*)test->name, "bookmark"))
     323             :         {
     324           0 :             xmlChar *branchxml = xmlGetProp(test, (const xmlChar*)"branch");
     325           0 :             xmlChar *idxml = xmlGetProp(test, (const xmlChar*)"id");
     326           0 :             std::string branch((const char*)branchxml);
     327           0 :             std::string anchor((const char*)idxml);
     328           0 :             xmlFree (branchxml);
     329           0 :             xmlFree (idxml);
     330             : 
     331           0 :             std::string hid;
     332             : 
     333           0 :             if (branch.find("hid") == 0)
     334             :             {
     335           0 :                 size_t index = branch.find('/');
     336           0 :                 if (index != std::string::npos)
     337             :                 {
     338           0 :                     hid = branch.substr(1 + index);
     339             :                     // one shall serve as a documentId
     340           0 :                     if (documentId.empty())
     341           0 :                         documentId = hid;
     342           0 :                     extendedHelpText.push_back(hid);
     343             :                     HCDBG(std::cerr << "hid pushback" << (anchor.empty() ? hid : hid + "#" + anchor) << std::endl);
     344           0 :                     hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor);
     345             :                 }
     346             :                 else
     347           0 :                     continue;
     348             :             }
     349           0 :             else if (branch.compare("index") == 0)
     350             :             {
     351           0 :                 LinkedList ll;
     352             : 
     353           0 :                 for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next)
     354             :                 {
     355           0 :                     if (strcmp((const char*)nd->name, "bookmark_value"))
     356           0 :                         continue;
     357             : 
     358           0 :                     std::string embedded;
     359           0 :                     xmlChar *embeddedxml = xmlGetProp(nd, (const xmlChar*)"embedded");
     360           0 :                     if (embeddedxml)
     361             :                     {
     362           0 :                         embedded = std::string((const char*)embeddedxml);
     363           0 :                         xmlFree (embeddedxml);
     364             :                         std::transform (embedded.begin(), embedded.end(),
     365           0 :                             embedded.begin(), tocharlower);
     366             :                     }
     367             : 
     368           0 :                     bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0;
     369           0 :                     if (isEmbedded)
     370           0 :                         continue;
     371             : 
     372           0 :                     std::string keyword = dump(nd);
     373           0 :                     size_t keywordSem = keyword.find(';');
     374           0 :                     if (keywordSem != std::string::npos)
     375             :                     {
     376             :                         std::string tmppre =
     377           0 :                                     keyword.substr(0,keywordSem);
     378           0 :                         trim(tmppre);
     379             :                         std::string tmppos =
     380           0 :                                     keyword.substr(1+keywordSem);
     381           0 :                         trim(tmppos);
     382           0 :                         keyword = tmppre + ";" + tmppos;
     383             :                     }
     384           0 :                     ll.push_back(keyword);
     385           0 :                 }
     386           0 :                 if (!ll.empty())
     387           0 :                     (*keywords)[anchor] = ll;
     388             :             }
     389           0 :             else if (branch.compare("contents") == 0)
     390             :             {
     391             :                 // currently not used
     392           0 :             }
     393             :         }
     394           0 :         else if (!strcmp((const char*)test->name, "ahelp"))
     395             :         {
     396           0 :             std::string text = dump(test);
     397           0 :             trim(text);
     398           0 :             std::string name;
     399             : 
     400           0 :             HashSet::const_iterator aEnd = extendedHelpText.end();
     401           0 :             for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd; ++iter)
     402             :             {
     403           0 :                 name = *iter;
     404           0 :                 (*helptexts)[name] = text;
     405             :             }
     406           0 :             extendedHelpText.clear();
     407             :         }
     408             :         // traverse children
     409           0 :         traverse(test);
     410             :     }
     411           0 : }
     412             : 
     413           0 : bool HelpCompiler::compile( void ) throw( HelpProcessingException )
     414             : {
     415             :     // we now have the jaroutputstream, which will contain the document.
     416             :     // now determine the document as a dom tree in variable docResolved
     417             : 
     418           0 :     xmlDocPtr docResolvedOrg = getSourceDocument(inputFile);
     419             : 
     420             :     // now add path to the document
     421             :     // resolve the dom
     422             : 
     423           0 :     if (!docResolvedOrg)
     424             :     {
     425           0 :         impl_sleep( 3 );
     426           0 :         docResolvedOrg = getSourceDocument(inputFile);
     427           0 :         if( !docResolvedOrg )
     428             :         {
     429           0 :             std::stringstream aStrStream;
     430           0 :             aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl;
     431           0 :             throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
     432             :         }
     433             :     }
     434             : 
     435           0 :     std::string documentId;
     436           0 :     std::string fileName;
     437           0 :     std::string title;
     438             :     // returns a clone of the document with switch-cases resolved
     439           0 :     std::string appl = module.substr(1);
     440           0 :     for (unsigned int i = 0; i < appl.length(); ++i)
     441             :     {
     442           0 :         appl[i]=toupper(appl[i]);
     443             :     }
     444           0 :     xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl);
     445           0 :     myparser aparser(documentId, fileName, title);
     446           0 :     aparser.traverse(docResolved);
     447           0 :     documentId = aparser.documentId;
     448           0 :     fileName = aparser.fileName;
     449           0 :     title = aparser.title;
     450             : 
     451             :     HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl);
     452             : 
     453           0 :     xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false);
     454           0 :     xmlDocSetRootElement(docResolvedDoc, docResolved);
     455             : 
     456           0 :     streamTable.dropappl();
     457           0 :     streamTable.appl_doc = docResolvedDoc;
     458           0 :     streamTable.appl_hidlist = aparser.hidlist;
     459           0 :     streamTable.appl_helptexts = aparser.helptexts;
     460           0 :     streamTable.appl_keywords = aparser.keywords;
     461             : 
     462           0 :     streamTable.document_id = documentId;
     463           0 :     streamTable.document_path = fileName;
     464           0 :     streamTable.document_title = title;
     465           0 :     std::string actMod = module;
     466             : 
     467           0 :     if ( !bExtensionMode && !fileName.empty())
     468             :     {
     469           0 :         if (fileName.find("/text/") == 0)
     470             :         {
     471           0 :             int len = strlen("/text/");
     472           0 :             actMod = fileName.substr(len);
     473           0 :             actMod = actMod.substr(0, actMod.find('/'));
     474             :         }
     475             :     }
     476           0 :     streamTable.document_module = actMod;
     477           0 :     xmlFreeDoc(docResolvedOrg);
     478           0 :     return true;
     479             : }
     480             : 
     481             : namespace fs
     482             : {
     483           0 :     rtl_TextEncoding getThreadTextEncoding( void )
     484             :     {
     485             :         static bool bNeedsInit = true;
     486             :         static rtl_TextEncoding nThreadTextEncoding;
     487           0 :         if( bNeedsInit )
     488             :         {
     489           0 :             bNeedsInit = false;
     490           0 :             nThreadTextEncoding = osl_getThreadTextEncoding();
     491             :         }
     492           0 :         return nThreadTextEncoding;
     493             :     }
     494             : 
     495           0 :     void create_directory(const fs::path indexDirName)
     496             :     {
     497             :         HCDBG(
     498             :             std::cerr << "creating " <<
     499             :             OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr()
     500             :             << std::endl
     501             :            );
     502           0 :         osl::Directory::createPath(indexDirName.data);
     503           0 :     }
     504             : 
     505           0 :     void copy(const fs::path &src, const fs::path &dest)
     506             :     {
     507           0 :         osl::File::copy(src.data, dest.data);
     508           0 :     }
     509         204 : }
     510             : 
     511             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10