fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / helpcompiler / source / HelpLinker.cxx
blobb2144fb5a37669bc841ce9fec72f05ca8badd53b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <HelpCompiler.hxx>
21 #include <HelpLinker.hxx>
23 #include <map>
25 #include <string.h>
26 #include <limits.h>
28 #include <libxslt/xslt.h>
29 #include <libxslt/xsltutils.h>
30 #include <libxslt/functions.h>
31 #include <libxslt/extensions.h>
33 #include <sal/main.h>
34 #include <sal/types.h>
35 #include <osl/time.h>
36 #include <rtl/bootstrap.hxx>
38 #include <expat.h>
39 #include <boost/scoped_array.hpp>
40 #include <boost/scoped_ptr.hpp>
42 IndexerPreProcessor::IndexerPreProcessor
43 ( const std::string& aModuleName, const fs::path& fsIndexBaseDir,
44 const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet )
45 : m_aModuleName( aModuleName )
46 , m_fsIndexBaseDir( fsIndexBaseDir )
48 m_fsCaptionFilesDirName = fsIndexBaseDir / "caption";
49 fs::create_directory( m_fsCaptionFilesDirName );
51 m_fsContentFilesDirName = fsIndexBaseDir / "content";
52 fs::create_directory( m_fsContentFilesDirName );
54 m_xsltStylesheetPtrCaption = xsltParseStylesheetFile
55 (reinterpret_cast<const xmlChar *>(idxCaptionStylesheet.native_file_string().c_str()));
56 m_xsltStylesheetPtrContent = xsltParseStylesheetFile
57 (reinterpret_cast<const xmlChar *>(idxContentStylesheet.native_file_string().c_str()));
60 IndexerPreProcessor::~IndexerPreProcessor()
62 if( m_xsltStylesheetPtrCaption )
63 xsltFreeStylesheet( m_xsltStylesheetPtrCaption );
64 if( m_xsltStylesheetPtrContent )
65 xsltFreeStylesheet( m_xsltStylesheetPtrContent );
68 std::string getEncodedPath( const std::string& Path )
70 OString aOStr_Path( Path.c_str() );
71 OUString aOUStr_Path( OStringToOUString
72 ( aOStr_Path, fs::getThreadTextEncoding() ) );
73 OUString aPathURL;
74 osl::File::getFileURLFromSystemPath( aOUStr_Path, aPathURL );
75 OString aOStr_PathURL( OUStringToOString
76 ( aPathURL, fs::getThreadTextEncoding() ) );
77 std::string aStdStr_PathURL( aOStr_PathURL.getStr() );
78 return aStdStr_PathURL;
81 void IndexerPreProcessor::processDocument
82 ( xmlDocPtr doc, const std::string &EncodedDocPath )
84 std::string aStdStr_EncodedDocPathURL = getEncodedPath( EncodedDocPath );
86 if( m_xsltStylesheetPtrCaption )
88 xmlDocPtr resCaption = xsltApplyStylesheet( m_xsltStylesheetPtrCaption, doc, NULL );
89 xmlNodePtr pResNodeCaption = resCaption->xmlChildrenNode;
90 if( pResNodeCaption )
92 fs::path fsCaptionPureTextFile_docURL = m_fsCaptionFilesDirName / aStdStr_EncodedDocPathURL;
93 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
94 FILE* pFile_docURL = _wfopen(
95 fsCaptionPureTextFile_docURL.native_file_string_w(), L"w" );
96 #else
97 FILE* pFile_docURL = fopen(
98 fsCaptionPureTextFile_docURL.native_file_string().c_str(), "w" );
99 #endif
100 if( pFile_docURL )
102 fprintf( pFile_docURL, "%s\n", pResNodeCaption->content );
103 fclose( pFile_docURL );
106 xmlFreeDoc(resCaption);
109 if( m_xsltStylesheetPtrContent )
111 xmlDocPtr resContent = xsltApplyStylesheet( m_xsltStylesheetPtrContent, doc, NULL );
112 xmlNodePtr pResNodeContent = resContent->xmlChildrenNode;
113 if( pResNodeContent )
115 fs::path fsContentPureTextFile_docURL = m_fsContentFilesDirName / aStdStr_EncodedDocPathURL;
116 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
117 FILE* pFile_docURL = _wfopen(
118 fsContentPureTextFile_docURL.native_file_string_w(), L"w" );
119 #else
120 FILE* pFile_docURL = fopen(
121 fsContentPureTextFile_docURL.native_file_string().c_str(), "w" );
122 #endif
123 if( pFile_docURL )
125 fprintf( pFile_docURL, "%s\n", pResNodeContent->content );
126 fclose( pFile_docURL );
129 xmlFreeDoc(resContent);
133 struct Data
135 std::vector<std::string> _idList;
136 typedef std::vector<std::string>::const_iterator cIter;
138 void append(const std::string &id)
140 _idList.push_back(id);
143 std::string getString() const
145 std::string ret;
146 cIter aEnd = _idList.end();
147 for (cIter aIter = _idList.begin(); aIter != aEnd; ++aIter)
148 ret += *aIter + ";";
149 return ret;
153 void writeKeyValue_DBHelp( FILE* pFile, const std::string& aKeyStr, const std::string& aValueStr )
155 if( pFile == NULL )
156 return;
157 char cLF = 10;
158 unsigned int nKeyLen = aKeyStr.length();
159 unsigned int nValueLen = aValueStr.length();
160 fprintf( pFile, "%x ", nKeyLen );
161 if( nKeyLen > 0 )
163 if (fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile ) != nKeyLen)
164 fprintf(stderr, "fwrite to db failed\n");
166 if (fprintf( pFile, " %x ", nValueLen ) < 0)
167 fprintf(stderr, "fwrite to db failed\n");
168 if( nValueLen > 0 )
170 if (fwrite( aValueStr.c_str(), 1, nValueLen, pFile ) != nValueLen)
171 fprintf(stderr, "fwrite to db failed\n");
173 if (fprintf( pFile, "%c", cLF ) < 0)
174 fprintf(stderr, "fwrite to db failed\n");
177 class HelpKeyword
179 private:
180 typedef std::unordered_map<std::string, Data, pref_hash> DataHashtable;
181 DataHashtable _hash;
183 public:
184 void insert(const std::string &key, const std::string &id)
186 Data &data = _hash[key];
187 data.append(id);
190 void dump_DBHelp( const fs::path& rFileName )
192 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
193 FILE* pFile = _wfopen( rFileName.native_file_string_w(), L"wb" );
194 #else
195 FILE* pFile = fopen( rFileName.native_file_string().c_str(), "wb" );
196 #endif
197 if( pFile == NULL )
198 return;
200 DataHashtable::const_iterator aEnd = _hash.end();
201 for (DataHashtable::const_iterator aIter = _hash.begin(); aIter != aEnd; ++aIter)
202 writeKeyValue_DBHelp( pFile, aIter->first, aIter->second.getString() );
204 fclose( pFile );
208 namespace URLEncoder
210 static std::string encode(const std::string &rIn)
212 const char *good = "!$&'()*+,-.=@_";
213 static const char hex[17] = "0123456789ABCDEF";
215 std::string result;
216 for (size_t i=0; i < rIn.length(); ++i)
218 unsigned char c = rIn[i];
219 if (isalnum (c) || strchr (good, c))
220 result += c;
221 else {
222 result += '%';
223 result += hex[c >> 4];
224 result += hex[c & 0xf];
227 return result;
231 void HelpLinker::addBookmark( FILE* pFile_DBHelp, std::string thishid,
232 const std::string& fileB, const std::string& anchorB,
233 const std::string& jarfileB, const std::string& titleB)
235 HCDBG(std::cerr << "HelpLinker::addBookmark " << thishid << " " <<
236 fileB << " " << anchorB << " " << jarfileB << " " << titleB << std::endl);
238 thishid = URLEncoder::encode(thishid);
240 int fileLen = fileB.length();
241 if (!anchorB.empty())
242 fileLen += (1 + anchorB.length());
243 int dataLen = 1 + fileLen + 1 + jarfileB.length() + 1 + titleB.length();
245 std::vector<unsigned char> dataB(dataLen);
246 size_t i = 0;
247 dataB[i++] = static_cast<unsigned char>(fileLen);
248 for (size_t j = 0; j < fileB.length(); ++j)
249 dataB[i++] = static_cast<unsigned char>(fileB[j]);
250 if (!anchorB.empty())
252 dataB[i++] = '#';
253 for (size_t j = 0; j < anchorB.length(); ++j)
254 dataB[i++] = anchorB[j];
256 dataB[i++] = static_cast<unsigned char>(jarfileB.length());
257 for (size_t j = 0; j < jarfileB.length(); ++j)
258 dataB[i++] = jarfileB[j];
260 dataB[i++] = static_cast<unsigned char>(titleB.length());
261 for (size_t j = 0; j < titleB.length(); ++j)
262 dataB[i++] = titleB[j];
264 if( pFile_DBHelp != NULL )
266 std::string aValueStr( dataB.begin(), dataB.end() );
267 writeKeyValue_DBHelp( pFile_DBHelp, thishid, aValueStr );
271 void HelpLinker::initIndexerPreProcessor()
273 if( m_pIndexerPreProcessor )
274 delete m_pIndexerPreProcessor;
275 std::string mod = module;
276 std::transform (mod.begin(), mod.end(), mod.begin(), tocharlower);
277 m_pIndexerPreProcessor = new IndexerPreProcessor( mod, indexDirParentName,
278 idxCaptionStylesheet, idxContentStylesheet );
284 void HelpLinker::link() throw(HelpProcessingException, BasicCodeTagger::TaggerException)
287 if( bExtensionMode )
289 indexDirParentName = extensionDestination;
291 else
293 indexDirParentName = zipdir;
294 fs::create_directory(indexDirParentName);
297 std::string mod = module;
298 std::transform (mod.begin(), mod.end(), mod.begin(), tocharlower);
300 // do the work here
301 // continue with introduction of the overall process thing into the
302 // here all hzip files will be worked on
303 std::string appl = mod;
304 if (appl[0] == 's')
305 appl = appl.substr(1);
307 bool bUse_ = true;
308 if( !bExtensionMode )
309 bUse_ = false;
311 fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht")));
312 #ifdef WNT
313 //We need _wfopen to support long file paths on Windows XP
314 FILE* pFileHelpText_DBHelp = _wfopen
315 ( helpTextFileName_DBHelp.native_file_string_w(), L"wb" );
316 #else
318 FILE* pFileHelpText_DBHelp = fopen
319 ( helpTextFileName_DBHelp.native_file_string().c_str(), "wb" );
320 #endif
322 fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db")));
323 #ifdef WNT
324 //We need _wfopen to support long file paths on Windows XP
325 FILE* pFileDbBase_DBHelp = _wfopen
326 ( dbBaseFileName_DBHelp.native_file_string_w(), L"wb" );
327 #else
328 FILE* pFileDbBase_DBHelp = fopen
329 ( dbBaseFileName_DBHelp.native_file_string().c_str(), "wb" );
330 #endif
332 fs::path keyWordFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".key_" : ".key")));
334 HelpKeyword helpKeyword;
336 // catch HelpProcessingException to avoid locking data bases
339 bool bIndexForExtension = true;
340 // lastly, initialize the indexBuilder
341 if ( (!bExtensionMode || bIndexForExtension) && !helpFiles.empty())
342 initIndexerPreProcessor();
344 // here we start our loop over the hzip files.
345 HashSet::iterator end = helpFiles.end();
346 for (HashSet::iterator iter = helpFiles.begin(); iter != end; ++iter)
348 // process one file
349 // streamTable contains the streams in the hzip file
350 StreamTable streamTable;
351 const std::string &xhpFileName = *iter;
353 if (!bExtensionMode && xhpFileName.rfind(".xhp") != xhpFileName.length()-4)
355 // only work on .xhp - files
356 SAL_WARN("helpcompiler",
357 "ERROR: input list entry '"
358 << xhpFileName
359 << "' has the wrong extension (only files with extension .xhp are accepted)");
361 continue;
364 fs::path langsourceRoot(sourceRoot);
365 fs::path xhpFile;
367 if( bExtensionMode )
369 // langsourceRoot == sourceRoot for extensions
370 std::string xhpFileNameComplete( extensionPath );
371 xhpFileNameComplete.append( '/' + xhpFileName );
372 xhpFile = fs::path( xhpFileNameComplete );
374 else
376 langsourceRoot.append( "/" );
377 if ( m_bUseLangRoot )
378 langsourceRoot.append( lang + '/' );
379 xhpFile = fs::path(xhpFileName, fs::native);
382 HelpCompiler hc( streamTable, xhpFile, langsourceRoot, zipdir,
383 compactStylesheet, embeddStylesheet, module, lang, bExtensionMode );
385 HCDBG(std::cerr << "before compile of " << xhpFileName << std::endl);
386 bool success = hc.compile();
387 HCDBG(std::cerr << "after compile of " << xhpFileName << std::endl);
389 if (!success && !bExtensionMode)
391 std::stringstream aStrStream;
392 aStrStream <<
393 "\nERROR: compiling help particle '"
394 << xhpFileName
395 << "' for language '"
396 << lang
397 << "' failed!";
398 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
401 if (!m_bCreateIndex)
402 continue;
404 std::string documentPath = streamTable.document_path;
405 if (documentPath.find("/") == 0)
406 documentPath = documentPath.substr(1);
408 std::string documentJarfile = streamTable.document_module + ".jar";
410 std::string documentTitle = streamTable.document_title;
411 if (documentTitle.empty())
412 documentTitle = "<notitle>";
414 const std::string& fileB = documentPath;
415 const std::string& jarfileB = documentJarfile;
416 std::string& titleB = documentTitle;
418 // add once this as its own id.
419 addBookmark( pFileDbBase_DBHelp, documentPath, fileB, std::string(), jarfileB, titleB);
421 const HashSet *hidlist = streamTable.appl_hidlist;
422 if (!hidlist)
423 hidlist = streamTable.default_hidlist;
424 if (hidlist && !hidlist->empty())
426 // now iterate over all elements of the hidlist
427 HashSet::const_iterator aEnd = hidlist->end();
428 for (HashSet::const_iterator hidListIter = hidlist->begin();
429 hidListIter != aEnd; ++hidListIter)
431 std::string thishid = *hidListIter;
433 std::string anchorB;
434 size_t index = thishid.rfind('#');
435 if (index != std::string::npos)
437 anchorB = thishid.substr(1 + index);
438 thishid = thishid.substr(0, index);
440 addBookmark( pFileDbBase_DBHelp, thishid, fileB, anchorB, jarfileB, titleB);
444 // now the keywords
445 const Hashtable *anchorToLL = streamTable.appl_keywords;
446 if (!anchorToLL)
447 anchorToLL = streamTable.default_keywords;
448 if (anchorToLL && !anchorToLL->empty())
450 std::string fakedHid = URLEncoder::encode(documentPath);
451 Hashtable::const_iterator aEnd = anchorToLL->end();
452 for (Hashtable::const_iterator enumer = anchorToLL->begin();
453 enumer != aEnd; ++enumer)
455 const std::string &anchor = enumer->first;
456 addBookmark(pFileDbBase_DBHelp, documentPath, fileB,
457 anchor, jarfileB, titleB);
458 std::string totalId = fakedHid + "#" + anchor;
459 // std::cerr << hzipFileName << std::endl;
460 const LinkedList& ll = enumer->second;
461 LinkedList::const_iterator aOtherEnd = ll.end();
462 for (LinkedList::const_iterator llIter = ll.begin();
463 llIter != aOtherEnd; ++llIter)
465 helpKeyword.insert(*llIter, totalId);
471 // and last the helptexts
472 const Stringtable *helpTextHash = streamTable.appl_helptexts;
473 if (!helpTextHash)
474 helpTextHash = streamTable.default_helptexts;
475 if (helpTextHash && !helpTextHash->empty())
477 Stringtable::const_iterator aEnd = helpTextHash->end();
478 for (Stringtable::const_iterator helpTextIter = helpTextHash->begin();
479 helpTextIter != aEnd; ++helpTextIter)
481 std::string helpTextId = helpTextIter->first;
482 const std::string& helpTextText = helpTextIter->second;
484 helpTextId = URLEncoder::encode(helpTextId);
486 if( pFileHelpText_DBHelp != NULL )
487 writeKeyValue_DBHelp( pFileHelpText_DBHelp, helpTextId, helpTextText );
491 //IndexerPreProcessor
492 if( !bExtensionMode || bIndexForExtension )
494 // now the indexing
495 xmlDocPtr document = streamTable.appl_doc;
496 if (!document)
497 document = streamTable.default_doc;
498 if (document)
500 std::string temp = module;
501 std::transform (temp.begin(), temp.end(), temp.begin(), tocharlower);
502 m_pIndexerPreProcessor->processDocument(document, URLEncoder::encode(documentPath) );
509 catch( const HelpProcessingException& )
511 // catch HelpProcessingException to avoid locking data bases
512 if( pFileHelpText_DBHelp != NULL )
513 fclose( pFileHelpText_DBHelp );
514 if( pFileDbBase_DBHelp != NULL )
515 fclose( pFileDbBase_DBHelp );
516 throw;
519 if( pFileHelpText_DBHelp != NULL )
520 fclose( pFileHelpText_DBHelp );
521 if( pFileDbBase_DBHelp != NULL )
522 fclose( pFileDbBase_DBHelp );
524 helpKeyword.dump_DBHelp( keyWordFileName_DBHelp);
526 if( !bExtensionMode )
528 // New index
529 Stringtable::iterator aEnd = additionalFiles.end();
530 for (Stringtable::iterator enumer = additionalFiles.begin(); enumer != aEnd;
531 ++enumer)
533 const std::string &additionalFileName = enumer->second;
534 const std::string &additionalFileKey = enumer->first;
536 fs::path fsAdditionalFileName( additionalFileName, fs::native );
537 HCDBG({
538 std::string aNativeStr = fsAdditionalFileName.native_file_string();
539 const char* pStr = aNativeStr.c_str();
540 std::cerr << pStr << std::endl;
543 fs::path fsTargetName( indexDirParentName / additionalFileKey );
545 fs::copy( fsAdditionalFileName, fsTargetName );
551 void HelpLinker::main( std::vector<std::string> &args,
552 std::string* pExtensionPath, std::string* pDestination,
553 const OUString* pOfficeHelpPath )
554 throw( HelpProcessingException )
556 bExtensionMode = false;
557 helpFiles.clear();
559 if ((!args.empty()) && args[0][0] == '@')
561 std::vector<std::string> stringList;
562 std::ifstream fileReader(args[0].substr(1).c_str());
564 while (fileReader)
566 std::string token;
567 fileReader >> token;
568 if (!token.empty())
569 stringList.push_back(token);
571 fileReader.close();
573 args = stringList;
576 size_t i = 0;
577 bool bSrcOption = false;
578 while (i < args.size())
580 if (args[i].compare("-extlangsrc") == 0)
582 ++i;
583 if (i >= args.size())
585 std::stringstream aStrStream;
586 aStrStream << "extension source missing" << std::endl;
587 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
589 extsource = args[i];
591 else if (args[i].compare("-extlangdest") == 0)
593 //If this argument is not provided then the location provided in -extsource will
594 //also be the destination
595 ++i;
596 if (i >= args.size())
598 std::stringstream aStrStream;
599 aStrStream << "extension destination missing" << std::endl;
600 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
602 extdestination = args[i];
604 else if (args[i].compare("-src") == 0)
606 ++i;
607 if (i >= args.size())
609 std::stringstream aStrStream;
610 aStrStream << "sourceroot missing" << std::endl;
611 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
613 bSrcOption = true;
614 sourceRoot = fs::path(args[i], fs::native);
616 else if (args[i].compare("-compact") == 0)
618 ++i;
619 if (i >= args.size())
621 std::stringstream aStrStream;
622 aStrStream << "compactStylesheet missing" << std::endl;
623 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
626 compactStylesheet = fs::path(args[i], fs::native);
628 else if (args[i].compare("-sty") == 0)
630 ++i;
631 if (i >= args.size())
633 std::stringstream aStrStream;
634 aStrStream << "embeddingStylesheet missing" << std::endl;
635 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
638 embeddStylesheet = fs::path(args[i], fs::native);
640 else if (args[i].compare("-zipdir") == 0)
642 ++i;
643 if (i >= args.size())
645 std::stringstream aStrStream;
646 aStrStream << "idxtemp missing" << std::endl;
647 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
650 zipdir = fs::path(args[i], fs::native);
652 else if (args[i].compare("-idxcaption") == 0)
654 ++i;
655 if (i >= args.size())
657 std::stringstream aStrStream;
658 aStrStream << "idxcaption stylesheet missing" << std::endl;
659 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
662 idxCaptionStylesheet = fs::path(args[i], fs::native);
664 else if (args[i].compare("-idxcontent") == 0)
666 ++i;
667 if (i >= args.size())
669 std::stringstream aStrStream;
670 aStrStream << "idxcontent stylesheet missing" << std::endl;
671 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
674 idxContentStylesheet = fs::path(args[i], fs::native);
676 else if (args[i].compare("-o") == 0)
678 ++i;
679 if (i >= args.size())
681 std::stringstream aStrStream;
682 aStrStream << "outputfilename missing" << std::endl;
683 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
686 outputFile = fs::path(args[i], fs::native);
688 else if (args[i].compare("-mod") == 0)
690 ++i;
691 if (i >= args.size())
693 std::stringstream aStrStream;
694 aStrStream << "module name missing" << std::endl;
695 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
698 module = args[i];
700 else if (args[i].compare("-lang") == 0)
702 ++i;
703 if (i >= args.size())
705 std::stringstream aStrStream;
706 aStrStream << "language name missing" << std::endl;
707 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
710 lang = args[i];
712 else if (args[i].compare("-hid") == 0)
714 ++i;
715 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, "obsolete -hid argument used" );
717 else if (args[i].compare("-add") == 0)
719 std::string addFile, addFileUnderPath;
720 ++i;
721 if (i >= args.size())
723 std::stringstream aStrStream;
724 aStrStream << "pathname missing" << std::endl;
725 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
728 addFileUnderPath = args[i];
729 ++i;
730 if (i >= args.size())
732 std::stringstream aStrStream;
733 aStrStream << "pathname missing" << std::endl;
734 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
736 addFile = args[i];
737 if (!addFileUnderPath.empty() && !addFile.empty())
738 additionalFiles[addFileUnderPath] = addFile;
740 else if (args[i].compare("-nolangroot") == 0)
741 m_bUseLangRoot = false;
742 else if (args[i].compare("-noindex") == 0)
743 m_bCreateIndex = false;
744 else
745 helpFiles.push_back(args[i]);
746 ++i;
749 //We can be called from the helplinker executable or the extension manager
750 //In the latter case extsource is not used.
751 if( (pExtensionPath && pExtensionPath->length() > 0 && pOfficeHelpPath)
752 || !extsource.empty())
754 bExtensionMode = true;
755 if (!extsource.empty())
757 //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
758 //should be NULL
759 sourceRoot = fs::path(extsource, fs::native);
760 extensionPath = sourceRoot.toUTF8();
762 if (extdestination.empty())
764 std::stringstream aStrStream;
765 aStrStream << "-extlangdest is missing" << std::endl;
766 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
768 else
770 //Convert from system path to file URL!!!
771 fs::path p(extdestination, fs::native);
772 extensionDestination = p.toUTF8();
775 else
776 { //called from extension manager
777 extensionPath = *pExtensionPath;
778 sourceRoot = fs::path(extensionPath);
779 extensionDestination = *pDestination;
781 //check if -src option was used. This option must not be used
782 //when extension help is compiled.
783 if (bSrcOption)
785 std::stringstream aStrStream;
786 aStrStream << "-src must not be used together with -extsource missing" << std::endl;
787 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
791 if (!bExtensionMode && zipdir.empty())
793 std::stringstream aStrStream;
794 aStrStream << "no index dir given" << std::endl;
795 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
798 if ( (!bExtensionMode && idxCaptionStylesheet.empty())
799 || (!extsource.empty() && idxCaptionStylesheet.empty()) )
801 //No extension mode and extension mode using commandline
802 //!extsource.empty indicates extension mode using commandline
803 // -idxcaption parameter is required
804 std::stringstream aStrStream;
805 aStrStream << "no index caption stylesheet given" << std::endl;
806 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
808 else if ( bExtensionMode && extsource.empty())
810 //This part is used when compileExtensionHelp is called from the extensions manager.
811 //If extension help is compiled using helplinker in the build process
812 OUString aIdxCaptionPathFileURL( *pOfficeHelpPath );
813 aIdxCaptionPathFileURL += "/idxcaption.xsl";
815 OString aOStr_IdxCaptionPathFileURL( OUStringToOString
816 ( aIdxCaptionPathFileURL, fs::getThreadTextEncoding() ) );
817 std::string aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL.getStr() );
819 idxCaptionStylesheet = fs::path( aStdStr_IdxCaptionPathFileURL );
822 if ( (!bExtensionMode && idxContentStylesheet.empty())
823 || (!extsource.empty() && idxContentStylesheet.empty()) )
825 //No extension mode and extension mode using commandline
826 //!extsource.empty indicates extension mode using commandline
827 // -idxcontent parameter is required
828 std::stringstream aStrStream;
829 aStrStream << "no index content stylesheet given" << std::endl;
830 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
832 else if ( bExtensionMode && extsource.empty())
834 //If extension help is compiled using helplinker in the build process
835 //then -idxcontent must be supplied
836 //This part is used when compileExtensionHelp is called from the extensions manager.
837 OUString aIdxContentPathFileURL( *pOfficeHelpPath );
838 aIdxContentPathFileURL += "/idxcontent.xsl";
840 OString aOStr_IdxContentPathFileURL( OUStringToOString
841 ( aIdxContentPathFileURL, fs::getThreadTextEncoding() ) );
842 std::string aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL.getStr() );
844 idxContentStylesheet = fs::path( aStdStr_IdxContentPathFileURL );
846 if (!bExtensionMode && embeddStylesheet.empty())
848 std::stringstream aStrStream;
849 aStrStream << "no embedding resolving file given" << std::endl;
850 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
852 if (sourceRoot.empty())
854 std::stringstream aStrStream;
855 aStrStream << "no sourceroot given" << std::endl;
856 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
858 if (!bExtensionMode && outputFile.empty())
860 std::stringstream aStrStream;
861 aStrStream << "no output file given" << std::endl;
862 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
864 if (module.empty())
866 std::stringstream aStrStream;
867 aStrStream << "module missing" << std::endl;
868 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
870 if (!bExtensionMode && lang.empty())
872 std::stringstream aStrStream;
873 aStrStream << "language missing" << std::endl;
874 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
876 link();
879 // Variable to set an exception in "C" StructuredXMLErrorFunction
880 static const HelpProcessingException* GpXMLParsingException = NULL;
882 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
884 (void)userData;
885 (void)error;
887 std::string aErrorMsg = error->message;
888 std::string aXMLParsingFile;
889 if( error->file != NULL )
890 aXMLParsingFile = error->file;
891 int nXMLParsingLine = error->line;
892 HelpProcessingException* pException = new HelpProcessingException( aErrorMsg, aXMLParsingFile, nXMLParsingLine );
893 GpXMLParsingException = pException;
895 // Reset error handler
896 xmlSetStructuredErrorFunc( NULL, NULL );
899 HelpProcessingErrorInfo& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException& e )
901 m_eErrorClass = e.m_eErrorClass;
902 OString tmpErrorMsg( e.m_aErrorMsg.c_str() );
903 m_aErrorMsg = OStringToOUString( tmpErrorMsg, fs::getThreadTextEncoding() );
904 OString tmpXMLParsingFile( e.m_aXMLParsingFile.c_str() );
905 m_aXMLParsingFile = OStringToOUString( tmpXMLParsingFile, fs::getThreadTextEncoding() );
906 m_nXMLParsingLine = e.m_nXMLParsingLine;
907 return *this;
911 // Returns true in case of success, false in case of error
912 bool compileExtensionHelp
914 const OUString& aOfficeHelpPath,
915 const OUString& aExtensionName,
916 const OUString& aExtensionLanguageRoot,
917 sal_Int32 nXhpFileCount, const OUString* pXhpFiles,
918 const OUString& aDestination,
919 HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo
922 bool bSuccess = true;
924 std::vector<std::string> args;
925 args.reserve(nXhpFileCount + 2);
926 args.push_back(std::string("-mod"));
927 OString aOExtensionName = OUStringToOString( aExtensionName, fs::getThreadTextEncoding() );
928 args.push_back(std::string(aOExtensionName.getStr()));
930 for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
932 OUString aXhpFile = pXhpFiles[iXhp];
934 OString aOXhpFile = OUStringToOString( aXhpFile, fs::getThreadTextEncoding() );
935 args.push_back(std::string(aOXhpFile.getStr()));
938 OString aOExtensionLanguageRoot = OUStringToOString( aExtensionLanguageRoot, fs::getThreadTextEncoding() );
939 const char* pExtensionPath = aOExtensionLanguageRoot.getStr();
940 std::string aStdStrExtensionPath = pExtensionPath;
941 OString aODestination = OUStringToOString(aDestination, fs::getThreadTextEncoding());
942 const char* pDestination = aODestination.getStr();
943 std::string aStdStrDestination = pDestination;
945 // Set error handler
946 xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction );
949 boost::scoped_ptr<HelpLinker> pHelpLinker(new HelpLinker());
950 pHelpLinker->main( args, &aStdStrExtensionPath, &aStdStrDestination, &aOfficeHelpPath );
952 catch( const HelpProcessingException& e )
954 if( GpXMLParsingException != NULL )
956 o_rHelpProcessingErrorInfo = *GpXMLParsingException;
957 delete GpXMLParsingException;
958 GpXMLParsingException = NULL;
960 else
962 o_rHelpProcessingErrorInfo = e;
964 bSuccess = false;
966 // Reset error handler
967 xmlSetStructuredErrorFunc( NULL, NULL );
969 // i83624: Tree files
970 // The following basically checks if the help.tree is well formed XML.
971 // Apparently there have been cases when translations contained
972 // non-well-formed XML in the past.
973 OUString aTreeFileURL = aExtensionLanguageRoot + "/help.tree";
974 osl::DirectoryItem aTreeFileItem;
975 osl::FileBase::RC rcGet = osl::DirectoryItem::get( aTreeFileURL, aTreeFileItem );
976 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize );
977 if( rcGet == osl::FileBase::E_None &&
978 aTreeFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None &&
979 aFileStatus.isValid( osl_FileStatus_Mask_FileSize ) )
981 sal_uInt64 ret, len = aFileStatus.getFileSize();
982 boost::scoped_array<char> s(new char[ int(len) ]); // the buffer to hold the installed files
983 osl::File aFile( aTreeFileURL );
984 aFile.open( osl_File_OpenFlag_Read );
985 aFile.read( s.get(), len, ret );
986 aFile.close();
988 XML_Parser parser = XML_ParserCreate( 0 );
989 XML_Status parsed = XML_Parse( parser, s.get(), int( len ), true );
991 if (XML_STATUS_ERROR == parsed)
993 XML_Error nError = XML_GetErrorCode( parser );
994 o_rHelpProcessingErrorInfo.m_eErrorClass = HELPPROCESSING_XMLPARSING_ERROR;
995 o_rHelpProcessingErrorInfo.m_aErrorMsg = OUString::createFromAscii( XML_ErrorString( nError ) );;
996 o_rHelpProcessingErrorInfo.m_aXMLParsingFile = aTreeFileURL;
997 // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
998 bSuccess = false;
1001 XML_ParserFree( parser );
1004 return bSuccess;
1007 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */