LCOV - code coverage report
Current view: top level - helpcompiler/source - HelpCompiler.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 264 0.4 %
Date: 2015-06-13 12:38:46 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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<const char*>(list->name), "switchinline") == 0 || strcmp(reinterpret_cast<const char*>(list->name), "switch") == 0)
     175             :             {
     176           0 :                 std::string tmp="";
     177           0 :                 xmlChar * prop = xmlGetProp(list, reinterpret_cast<xmlChar const *>("select"));
     178           0 :                 if (prop != 0)
     179             :                 {
     180           0 :                     if (strcmp(reinterpret_cast<char *>(prop), "sys") == 0)
     181             :                     {
     182           0 :                         tmp = gui;
     183             :                     }
     184           0 :                     else if (strcmp(reinterpret_cast<char *>(prop), "appl") == 0)
     185             :                     {
     186           0 :                         tmp = appl;
     187             :                     }
     188           0 :                     xmlFree(prop);
     189             :                 }
     190           0 :                 if (tmp.compare("") != 0)
     191             :                 {
     192           0 :                     bool isCase=false;
     193           0 :                     xmlNodePtr caseList=list->xmlChildrenNode;
     194           0 :                     while (caseList)
     195             :                     {
     196           0 :                         xmlChar *select = xmlGetProp(caseList, reinterpret_cast<xmlChar const *>("select"));
     197           0 :                         if (select)
     198             :                         {
     199           0 :                             if (!strcmp(reinterpret_cast<char*>(select), tmp.c_str()) && !isCase)
     200             :                             {
     201           0 :                                 isCase=true;
     202           0 :                                 xmlNodePtr clp = caseList->xmlChildrenNode;
     203           0 :                                 while (clp)
     204             :                                 {
     205           0 :                                     xmlAddChild(root, clone(clp, appl));
     206           0 :                                     clp = clp->next;
     207             :                                 }
     208             :                             }
     209           0 :                             xmlFree(select);
     210             :                         }
     211             :                         else
     212             :                         {
     213           0 :                             if ((strcmp(reinterpret_cast<const char*>(caseList->name), "defaultinline") != 0) && (strcmp(reinterpret_cast<const char*>(caseList->name), "default") != 0))
     214             :                             {
     215           0 :                                 xmlAddChild(root, clone(caseList, appl));
     216             :                             }
     217             :                             else
     218             :                             {
     219           0 :                                 if (!isCase)
     220             :                                 {
     221           0 :                                     xmlNodePtr clp = caseList->xmlChildrenNode;
     222           0 :                                     while (clp)
     223             :                                     {
     224           0 :                                         xmlAddChild(root, clone(clp, appl));
     225           0 :                                         clp = clp->next;
     226             :                                     }
     227             :                                 }
     228             :                             }
     229             :                         }
     230           0 :                         caseList = caseList->next;
     231             :                     }
     232           0 :                 }
     233             :             }
     234             :             else
     235             :             {
     236           0 :                 xmlAddChild(root, clone(list, appl));
     237             :             }
     238           0 :             list = list->next;
     239             :         }
     240             :     }
     241           0 :     return root;
     242             : }
     243             : 
     244           0 : class myparser
     245             : {
     246             : public:
     247             :     std::string documentId;
     248             :     std::string fileName;
     249             :     std::string title;
     250             :     std::unique_ptr<HashSet> hidlist;
     251             :     std::unique_ptr<Hashtable> keywords;
     252             :     std::unique_ptr<Stringtable> helptexts;
     253             : private:
     254             :     HashSet extendedHelpText;
     255             : public:
     256           0 :     myparser(const std::string &indocumentId, const std::string &infileName,
     257             :         const std::string &intitle) : documentId(indocumentId), fileName(infileName),
     258           0 :         title(intitle)
     259             :     {
     260           0 :         hidlist.reset(new HashSet);
     261           0 :         keywords.reset(new Hashtable);
     262           0 :         helptexts.reset(new Stringtable);
     263           0 :     }
     264             :     void traverse( xmlNodePtr parentNode );
     265             : private:
     266             :     std::string module;
     267             :     std::string dump(xmlNodePtr node);
     268             : };
     269             : 
     270           0 : std::string myparser::dump(xmlNodePtr node)
     271             : {
     272           0 :     std::string app;
     273           0 :     if (node->xmlChildrenNode)
     274             :     {
     275           0 :         xmlNodePtr list = node->xmlChildrenNode;
     276           0 :         while (list)
     277             :         {
     278           0 :             app += dump(list);
     279           0 :             list = list->next;
     280             :         }
     281             :     }
     282           0 :     if (xmlNodeIsText(node))
     283             :     {
     284           0 :         xmlChar *pContent = xmlNodeGetContent(node);
     285           0 :         app += std::string(reinterpret_cast<char*>(pContent));
     286           0 :         xmlFree(pContent);
     287             :     }
     288           0 :     return app;
     289             : }
     290             : 
     291           0 : void trim(std::string& str)
     292             : {
     293           0 :     std::string::size_type pos = str.find_last_not_of(' ');
     294           0 :     if(pos != std::string::npos)
     295             :     {
     296           0 :         str.erase(pos + 1);
     297           0 :         pos = str.find_first_not_of(' ');
     298           0 :         if(pos != std::string::npos)
     299           0 :             str.erase(0, pos);
     300             :     }
     301             :     else
     302           0 :         str.erase(str.begin(), str.end());
     303           0 : }
     304             : 
     305           0 : void myparser::traverse( xmlNodePtr parentNode )
     306             : {
     307             :     // traverse all nodes that belong to the parent
     308             :     xmlNodePtr test ;
     309           0 :     for (test = parentNode->xmlChildrenNode; test; test = test->next)
     310             :     {
     311           0 :         if (fileName.empty() && !strcmp(reinterpret_cast<const char*>(test->name), "filename"))
     312             :         {
     313           0 :             xmlNodePtr node = test->xmlChildrenNode;
     314           0 :             if (xmlNodeIsText(node))
     315             :             {
     316           0 :                 xmlChar *pContent = xmlNodeGetContent(node);
     317           0 :                 fileName = std::string(reinterpret_cast<char*>(pContent));
     318           0 :                 xmlFree(pContent);
     319             :             }
     320             :         }
     321           0 :         else if (title.empty() && !strcmp(reinterpret_cast<const char*>(test->name), "title"))
     322             :         {
     323           0 :             title = dump(test);
     324           0 :             if (title.empty())
     325           0 :                 title = "<notitle>";
     326             :         }
     327           0 :         else if (!strcmp(reinterpret_cast<const char*>(test->name), "bookmark"))
     328             :         {
     329           0 :             xmlChar *branchxml = xmlGetProp(test, reinterpret_cast<const xmlChar*>("branch"));
     330           0 :             xmlChar *idxml = xmlGetProp(test, reinterpret_cast<const xmlChar*>("id"));
     331           0 :             std::string branch(reinterpret_cast<char*>(branchxml));
     332           0 :             std::string anchor(reinterpret_cast<char*>(idxml));
     333           0 :             xmlFree (branchxml);
     334           0 :             xmlFree (idxml);
     335             : 
     336           0 :             std::string hid;
     337             : 
     338           0 :             if (branch.find("hid") == 0)
     339             :             {
     340           0 :                 size_t index = branch.find('/');
     341           0 :                 if (index != std::string::npos)
     342             :                 {
     343           0 :                     hid = branch.substr(1 + index);
     344             :                     // one shall serve as a documentId
     345           0 :                     if (documentId.empty())
     346           0 :                         documentId = hid;
     347           0 :                     extendedHelpText.push_back(hid);
     348             :                     HCDBG(std::cerr << "hid pushback" << (anchor.empty() ? hid : hid + "#" + anchor) << std::endl);
     349           0 :                     hidlist->push_back( anchor.empty() ? hid : hid + "#" + anchor);
     350             :                 }
     351             :                 else
     352           0 :                     continue;
     353             :             }
     354           0 :             else if (branch.compare("index") == 0)
     355             :             {
     356           0 :                 LinkedList ll;
     357             : 
     358           0 :                 for (xmlNodePtr nd = test->xmlChildrenNode; nd; nd = nd->next)
     359             :                 {
     360           0 :                     if (strcmp(reinterpret_cast<const char*>(nd->name), "bookmark_value"))
     361           0 :                         continue;
     362             : 
     363           0 :                     std::string embedded;
     364           0 :                     xmlChar *embeddedxml = xmlGetProp(nd, reinterpret_cast<const xmlChar*>("embedded"));
     365           0 :                     if (embeddedxml)
     366             :                     {
     367           0 :                         embedded = std::string(reinterpret_cast<char*>(embeddedxml));
     368           0 :                         xmlFree (embeddedxml);
     369             :                         std::transform (embedded.begin(), embedded.end(),
     370           0 :                             embedded.begin(), tocharlower);
     371             :                     }
     372             : 
     373           0 :                     bool isEmbedded = !embedded.empty() && embedded.compare("true") == 0;
     374           0 :                     if (isEmbedded)
     375           0 :                         continue;
     376             : 
     377           0 :                     std::string keyword = dump(nd);
     378           0 :                     size_t keywordSem = keyword.find(';');
     379           0 :                     if (keywordSem != std::string::npos)
     380             :                     {
     381             :                         std::string tmppre =
     382           0 :                                     keyword.substr(0,keywordSem);
     383           0 :                         trim(tmppre);
     384             :                         std::string tmppos =
     385           0 :                                     keyword.substr(1+keywordSem);
     386           0 :                         trim(tmppos);
     387           0 :                         keyword = tmppre + ";" + tmppos;
     388             :                     }
     389           0 :                     ll.push_back(keyword);
     390           0 :                 }
     391           0 :                 if (!ll.empty())
     392           0 :                     (*keywords)[anchor] = ll;
     393             :             }
     394           0 :             else if (branch.compare("contents") == 0)
     395             :             {
     396             :                 // currently not used
     397           0 :             }
     398             :         }
     399           0 :         else if (!strcmp(reinterpret_cast<const char*>(test->name), "ahelp"))
     400             :         {
     401             :             //tool-tip
     402           0 :             std::string text = dump(test);
     403           0 :             std::replace(text.begin(), text.end(), '\n', ' ');
     404           0 :             trim(text);
     405             : 
     406             :             //tool-tip target
     407           0 :             std::string hidstr(".");  //. == previous seen hid bookmarks
     408           0 :             xmlChar *hid = xmlGetProp(test, reinterpret_cast<const xmlChar*>("hid"));
     409           0 :             if (hid)
     410             :             {
     411           0 :                 hidstr = std::string(reinterpret_cast<char*>(hid));
     412           0 :                 xmlFree (hid);
     413             :             }
     414             : 
     415           0 :             if (hidstr != "." && !hidstr.empty())  //simple case of explicitly named target
     416             :             {
     417             :                 assert(!hidstr.empty());
     418           0 :                 (*helptexts)[hidstr] = text;
     419             :             }
     420             :             else //apply to list of "current" hids determined by recent bookmarks that have hid in their branch
     421             :             {
     422             :                 //TODO: make these asserts and flush out all our broken help ids
     423             :                 SAL_WARN_IF(hidstr.empty(), "helpcompiler", "hid='' for text:" << text);
     424             :                 SAL_WARN_IF(!hidstr.empty() && extendedHelpText.empty(), "helpcompiler", "hid='.' with no hid bookmark branches for text:" << text);
     425           0 :                 HashSet::const_iterator aEnd = extendedHelpText.end();
     426           0 :                 for (HashSet::const_iterator iter = extendedHelpText.begin(); iter != aEnd; ++iter)
     427             :                 {
     428           0 :                     std::string name = *iter;
     429           0 :                     (*helptexts)[name] = text;
     430           0 :                 }
     431             :             }
     432           0 :             extendedHelpText.clear();
     433             :         }
     434             :         // traverse children
     435           0 :         traverse(test);
     436             :     }
     437           0 : }
     438             : 
     439           0 : bool HelpCompiler::compile()
     440             :     throw (HelpProcessingException, BasicCodeTagger::TaggerException)
     441             : {
     442             :     // we now have the jaroutputstream, which will contain the document.
     443             :     // now determine the document as a dom tree in variable docResolved
     444             : 
     445           0 :     xmlDocPtr docResolvedOrg = getSourceDocument(inputFile);
     446             : 
     447             :     // now add path to the document
     448             :     // resolve the dom
     449             : 
     450           0 :     if (!docResolvedOrg)
     451             :     {
     452           0 :         impl_sleep( 3 );
     453           0 :         docResolvedOrg = getSourceDocument(inputFile);
     454           0 :         if( !docResolvedOrg )
     455             :         {
     456           0 :             std::stringstream aStrStream;
     457           0 :             aStrStream << "ERROR: file not existing: " << inputFile.native_file_string().c_str() << std::endl;
     458           0 :             throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
     459             :         }
     460             :     }
     461             : 
     462           0 :     std::string documentId;
     463           0 :     std::string fileName;
     464           0 :     std::string title;
     465             :     // returns a clone of the document with switch-cases resolved
     466           0 :     std::string appl = module.substr(1);
     467           0 :     for (size_t i = 0; i < appl.length(); ++i)
     468             :     {
     469           0 :         appl[i]=toupper(appl[i]);
     470             :     }
     471           0 :     xmlNodePtr docResolved = clone(xmlDocGetRootElement(docResolvedOrg), appl);
     472           0 :     myparser aparser(documentId, fileName, title);
     473           0 :     aparser.traverse(docResolved);
     474           0 :     documentId = aparser.documentId;
     475           0 :     fileName = aparser.fileName;
     476           0 :     title = aparser.title;
     477             : 
     478             :     HCDBG(std::cerr << documentId << " : " << fileName << " : " << title << std::endl);
     479             : 
     480           0 :     xmlDocPtr docResolvedDoc = xmlCopyDoc(docResolvedOrg, false);
     481           0 :     xmlDocSetRootElement(docResolvedDoc, docResolved);
     482             : 
     483           0 :     streamTable.dropappl();
     484           0 :     streamTable.appl_doc = docResolvedDoc;
     485           0 :     streamTable.appl_hidlist = aparser.hidlist.release();
     486           0 :     streamTable.appl_helptexts = aparser.helptexts.release();
     487           0 :     streamTable.appl_keywords = aparser.keywords.release();
     488             : 
     489           0 :     streamTable.document_id = documentId;
     490           0 :     streamTable.document_path = fileName;
     491           0 :     streamTable.document_title = title;
     492           0 :     std::string actMod = module;
     493             : 
     494           0 :     if ( !bExtensionMode && !fileName.empty())
     495             :     {
     496           0 :         if (fileName.find("/text/") == 0)
     497             :         {
     498           0 :             int len = strlen("/text/");
     499           0 :             actMod = fileName.substr(len);
     500           0 :             actMod = actMod.substr(0, actMod.find('/'));
     501             :         }
     502             :     }
     503           0 :     streamTable.document_module = actMod;
     504           0 :     xmlFreeDoc(docResolvedOrg);
     505           0 :     return true;
     506             : }
     507             : 
     508             : namespace fs
     509             : {
     510           0 :     rtl_TextEncoding getThreadTextEncoding()
     511             :     {
     512             :         static bool bNeedsInit = true;
     513             :         static rtl_TextEncoding nThreadTextEncoding;
     514           0 :         if( bNeedsInit )
     515             :         {
     516           0 :             bNeedsInit = false;
     517           0 :             nThreadTextEncoding = osl_getThreadTextEncoding();
     518             :         }
     519           0 :         return nThreadTextEncoding;
     520             :     }
     521             : 
     522           0 :     void create_directory(const fs::path& indexDirName)
     523             :     {
     524             :         HCDBG(
     525             :             std::cerr << "creating " <<
     526             :             OUStringToOString(indexDirName.data, RTL_TEXTENCODING_UTF8).getStr()
     527             :             << std::endl
     528             :            );
     529           0 :         osl::Directory::createPath(indexDirName.data);
     530           0 :     }
     531             : 
     532           0 :     void copy(const fs::path &src, const fs::path &dest)
     533             :     {
     534           0 :         osl::File::copy(src.data, dest.data);
     535           0 :     }
     536         336 : }
     537             : 
     538             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11