1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
28 #include <libxslt/transform.h>
30 #include <sal/types.h>
31 #include <o3tl/char16_t2wchar_t.hxx>
32 #include <sal/log.hxx>
38 FILE* fopen_impl(const fs::path
& rPath
, const char* szMode
)
40 #ifdef _WIN32 //We need _wfopen to support long file paths on Windows XP
41 return _wfopen(rPath
.native_file_string_w().c_str(), o3tl::toW(OUString::createFromAscii(szMode
).getStr()));
43 return fopen(rPath
.native_file_string().c_str(), szMode
);
48 IndexerPreProcessor::IndexerPreProcessor
49 ( const fs::path
& fsIndexBaseDir
,
50 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
)
52 m_fsCaptionFilesDirName
= fsIndexBaseDir
/ "caption";
53 fs::create_directory( m_fsCaptionFilesDirName
);
55 m_fsContentFilesDirName
= fsIndexBaseDir
/ "content";
56 fs::create_directory( m_fsContentFilesDirName
);
58 m_xsltStylesheetPtrCaption
= xsltParseStylesheetFile
59 (reinterpret_cast<const xmlChar
*>(idxCaptionStylesheet
.native_file_string().c_str()));
60 m_xsltStylesheetPtrContent
= xsltParseStylesheetFile
61 (reinterpret_cast<const xmlChar
*>(idxContentStylesheet
.native_file_string().c_str()));
64 IndexerPreProcessor::~IndexerPreProcessor()
66 if( m_xsltStylesheetPtrCaption
)
67 xsltFreeStylesheet( m_xsltStylesheetPtrCaption
);
68 if( m_xsltStylesheetPtrContent
)
69 xsltFreeStylesheet( m_xsltStylesheetPtrContent
);
72 static std::string
getEncodedPath( const std::string
& Path
)
74 OString
aOStr_Path( Path
.c_str() );
75 OUString
aOUStr_Path( OStringToOUString
76 ( aOStr_Path
, fs::getThreadTextEncoding() ) );
78 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
79 OString
aOStr_PathURL( OUStringToOString
80 ( aPathURL
, fs::getThreadTextEncoding() ) );
81 std::string
aStdStr_PathURL( aOStr_PathURL
.getStr() );
82 return aStdStr_PathURL
;
85 void IndexerPreProcessor::processDocument
86 ( xmlDocPtr doc
, const std::string
&EncodedDocPath
)
88 std::string aStdStr_EncodedDocPathURL
= getEncodedPath( EncodedDocPath
);
90 if( m_xsltStylesheetPtrCaption
)
92 xmlDocPtr resCaption
= xsltApplyStylesheet( m_xsltStylesheetPtrCaption
, doc
, nullptr );
93 xmlNodePtr pResNodeCaption
= resCaption
->xmlChildrenNode
;
96 fs::path fsCaptionPureTextFile_docURL
= m_fsCaptionFilesDirName
/ aStdStr_EncodedDocPathURL
;
97 FILE* pFile_docURL
= fopen_impl( fsCaptionPureTextFile_docURL
, "w" );
100 fprintf( pFile_docURL
, "%s\n", pResNodeCaption
->content
);
101 fclose( pFile_docURL
);
104 xmlFreeDoc(resCaption
);
107 if( m_xsltStylesheetPtrContent
)
109 xmlDocPtr resContent
= xsltApplyStylesheet( m_xsltStylesheetPtrContent
, doc
, nullptr );
110 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
111 if( pResNodeContent
)
113 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
114 FILE* pFile_docURL
= fopen_impl( fsContentPureTextFile_docURL
, "w" );
117 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
118 fclose( pFile_docURL
);
121 xmlFreeDoc(resContent
);
127 std::vector
<std::string
> _idList
;
129 void append(const std::string
&id
)
131 _idList
.push_back(id
);
134 std::string
getString() const
137 for (auto const& elem
: _idList
)
143 static void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
145 if( pFile
== nullptr )
148 unsigned int nKeyLen
= aKeyStr
.length();
149 unsigned int nValueLen
= aValueStr
.length();
150 fprintf( pFile
, "%x ", nKeyLen
);
153 if (fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
) != nKeyLen
)
154 fprintf(stderr
, "fwrite to db failed\n");
156 if (fprintf( pFile
, " %x ", nValueLen
) < 0)
157 fprintf(stderr
, "fwrite to db failed\n");
160 if (fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
) != nValueLen
)
161 fprintf(stderr
, "fwrite to db failed\n");
163 if (fprintf( pFile
, "%c", cLF
) < 0)
164 fprintf(stderr
, "fwrite to db failed\n");
170 typedef std::unordered_map
<std::string
, Data
> DataHashtable
;
174 void insert(const std::string
&key
, const std::string
&id
)
176 Data
&data
= _hash
[key
];
180 void dump_DBHelp( const fs::path
& rFileName
)
182 FILE* pFile
= fopen_impl( rFileName
, "wb" );
183 if( pFile
== nullptr )
186 for (auto const& elem
: _hash
)
187 writeKeyValue_DBHelp( pFile
, elem
.first
, elem
.second
.getString() );
195 static std::string
encode(const std::string
&rIn
)
197 const char * const good
= "!$&'()*+,-.=@_";
198 static const char hex
[17] = "0123456789ABCDEF";
203 if (rtl::isAsciiAlphanumeric (static_cast<unsigned char>(c
))
209 result
+= hex
[static_cast<unsigned char>(c
) >> 4];
210 result
+= hex
[c
& 0xf];
217 void HelpLinker::addBookmark( FILE* pFile_DBHelp
, std::string thishid
,
218 const std::string
& fileB
, const std::string
& anchorB
,
219 const std::string
& jarfileB
, const std::string
& titleB
)
221 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
222 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
224 thishid
= URLEncoder::encode(thishid
);
226 int fileLen
= fileB
.length();
227 if (!anchorB
.empty())
228 fileLen
+= (1 + anchorB
.length());
229 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
231 std::vector
<unsigned char> dataB(dataLen
);
233 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
235 dataB
[i
++] = static_cast<unsigned char>(j
);
236 if (!anchorB
.empty())
239 for (char j
: anchorB
)
242 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
243 for (char j
: jarfileB
)
246 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
247 for (char j
: titleB
)
250 if( pFile_DBHelp
!= nullptr )
252 std::string
aValueStr( dataB
.begin(), dataB
.end() );
253 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
257 void HelpLinker::initIndexerPreProcessor()
259 m_pIndexerPreProcessor
.reset( new IndexerPreProcessor( indexDirParentName
,
260 idxCaptionStylesheet
, idxContentStylesheet
) );
263 void HelpLinker::link()
268 indexDirParentName
= extensionDestination
;
272 indexDirParentName
= zipdir
;
273 fs::create_directory(indexDirParentName
);
276 std::string mod
= module
;
277 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
280 // continue with introduction of the overall process thing into the
281 // here all hzip files will be worked on
283 if( !bExtensionMode
)
286 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
287 FILE* pFileHelpText_DBHelp
= fopen_impl( helpTextFileName_DBHelp
, "wb" );
289 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
290 FILE* pFileDbBase_DBHelp
= fopen_impl( dbBaseFileName_DBHelp
, "wb" );
292 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
294 HelpKeyword helpKeyword
;
296 // catch HelpProcessingException to avoid locking data bases
299 bool bIndexForExtension
= true;
300 // lastly, initialize the indexBuilder
301 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
302 initIndexerPreProcessor();
304 // here we start our loop over the hzip files.
305 for (auto const& helpFile
: helpFiles
)
308 // streamTable contains the streams in the hzip file
309 StreamTable streamTable
;
310 const std::string
&xhpFileName
= helpFile
;
312 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
314 // only work on .xhp - files
315 SAL_WARN("helpcompiler",
316 "ERROR: input list entry '"
318 << "' has the wrong extension (only files with extension .xhp are accepted)");
323 fs::path
langsourceRoot(sourceRoot
);
328 // langsourceRoot == sourceRoot for extensions
329 std::string
xhpFileNameComplete( extensionPath
);
330 xhpFileNameComplete
.append( '/' + xhpFileName
);
331 xhpFile
= fs::path( xhpFileNameComplete
);
335 langsourceRoot
.append( "/" );
336 if ( m_bUseLangRoot
)
337 langsourceRoot
.append( lang
+ '/' );
338 xhpFile
= fs::path(xhpFileName
, fs::native
);
341 HelpCompiler
hc( streamTable
, xhpFile
, langsourceRoot
, zipdir
,
342 compactStylesheet
, embeddStylesheet
, module
, lang
, bExtensionMode
);
344 HCDBG(std::cerr
<< "before compile of " << xhpFileName
<< std::endl
);
346 HCDBG(std::cerr
<< "after compile of " << xhpFileName
<< std::endl
);
351 std::string documentPath
= streamTable
.document_path
;
352 if (documentPath
.compare(0, 1, "/") == 0)
353 documentPath
= documentPath
.substr(1);
355 std::string documentJarfile
= streamTable
.document_module
+ ".jar";
357 std::string documentTitle
= streamTable
.document_title
;
358 if (documentTitle
.empty())
359 documentTitle
= "<notitle>";
361 const std::string
& fileB
= documentPath
;
362 const std::string
& jarfileB
= documentJarfile
;
363 std::string
& titleB
= documentTitle
;
365 // add once this as its own id.
366 addBookmark( pFileDbBase_DBHelp
, documentPath
, fileB
, std::string(), jarfileB
, titleB
);
368 const std::vector
<std::string
> *hidlist
= streamTable
.appl_hidlist
.get();
371 // now iterate over all elements of the hidlist
372 for (auto & elem
: *hidlist
)
374 std::string thishid
= elem
;
377 size_t index
= thishid
.rfind('#');
378 if (index
!= std::string::npos
)
380 anchorB
= thishid
.substr(1 + index
);
381 thishid
= thishid
.substr(0, index
);
383 addBookmark( pFileDbBase_DBHelp
, thishid
, fileB
, anchorB
, jarfileB
, titleB
);
388 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
.get();
389 if (anchorToLL
&& !anchorToLL
->empty())
391 std::string fakedHid
= URLEncoder::encode(documentPath
);
392 for (auto const& elemAnchor
: *anchorToLL
)
394 const std::string
&anchor
= elemAnchor
.first
;
395 addBookmark(pFileDbBase_DBHelp
, documentPath
, fileB
,
396 anchor
, jarfileB
, titleB
);
397 std::string totalId
= fakedHid
+ "#" + anchor
;
398 // std::cerr << hzipFileName << std::endl;
399 const LinkedList
& ll
= elemAnchor
.second
;
400 for (auto const& elem
: ll
)
402 helpKeyword
.insert(elem
, totalId
);
408 // and last the helptexts
409 const Stringtable
*helpTextHash
= streamTable
.appl_helptexts
.get();
412 for (auto const& elem
: *helpTextHash
)
414 std::string helpTextId
= elem
.first
;
415 const std::string
& helpTextText
= elem
.second
;
417 helpTextId
= URLEncoder::encode(helpTextId
);
419 if( pFileHelpText_DBHelp
!= nullptr )
420 writeKeyValue_DBHelp( pFileHelpText_DBHelp
, helpTextId
, helpTextText
);
424 //IndexerPreProcessor
425 if( !bExtensionMode
|| bIndexForExtension
)
428 xmlDocPtr document
= streamTable
.appl_doc
;
431 std::string temp
= module
;
432 std::transform (temp
.begin(), temp
.end(), temp
.begin(), tocharlower
);
433 m_pIndexerPreProcessor
->processDocument(document
, URLEncoder::encode(documentPath
) );
440 catch( const HelpProcessingException
& )
442 // catch HelpProcessingException to avoid locking data bases
443 if( pFileHelpText_DBHelp
!= nullptr )
444 fclose( pFileHelpText_DBHelp
);
445 if( pFileDbBase_DBHelp
!= nullptr )
446 fclose( pFileDbBase_DBHelp
);
450 if( pFileHelpText_DBHelp
!= nullptr )
451 fclose( pFileHelpText_DBHelp
);
452 if( pFileDbBase_DBHelp
!= nullptr )
453 fclose( pFileDbBase_DBHelp
);
455 helpKeyword
.dump_DBHelp( keyWordFileName_DBHelp
);
457 if( !bExtensionMode
)
460 for (auto const& additionalFile
: additionalFiles
)
462 const std::string
&additionalFileName
= additionalFile
.second
;
463 const std::string
&additionalFileKey
= additionalFile
.first
;
465 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
467 std::string aNativeStr
= fsAdditionalFileName
.native_file_string();
468 const char* pStr
= aNativeStr
.c_str();
469 std::cerr
<< pStr
<< std::endl
;
472 fs::path
fsTargetName( indexDirParentName
/ additionalFileKey
);
474 fs::copy( fsAdditionalFileName
, fsTargetName
);
480 void HelpLinker::main( std::vector
<std::string
> &args
,
481 std::string
const * pExtensionPath
, std::string
const * pDestination
,
482 const OUString
* pOfficeHelpPath
)
484 bExtensionMode
= false;
487 if ((!args
.empty()) && args
[0][0] == '@')
489 std::vector
<std::string
> stringList
;
490 std::ifstream
fileReader(args
[0].substr(1).c_str());
497 stringList
.push_back(token
);
505 bool bSrcOption
= false;
506 while (i
< args
.size())
508 if (args
[i
].compare("-extlangsrc") == 0)
511 if (i
>= args
.size())
513 std::stringstream aStrStream
;
514 aStrStream
<< "extension source missing" << std::endl
;
515 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
519 else if (args
[i
].compare("-extlangdest") == 0)
521 //If this argument is not provided then the location provided in -extsource will
522 //also be the destination
524 if (i
>= args
.size())
526 std::stringstream aStrStream
;
527 aStrStream
<< "extension destination missing" << std::endl
;
528 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
530 extdestination
= args
[i
];
532 else if (args
[i
].compare("-src") == 0)
535 if (i
>= args
.size())
537 std::stringstream aStrStream
;
538 aStrStream
<< "sourceroot missing" << std::endl
;
539 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
542 sourceRoot
= fs::path(args
[i
], fs::native
);
544 else if (args
[i
].compare("-compact") == 0)
547 if (i
>= args
.size())
549 std::stringstream aStrStream
;
550 aStrStream
<< "compactStylesheet missing" << std::endl
;
551 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
554 compactStylesheet
= fs::path(args
[i
], fs::native
);
556 else if (args
[i
].compare("-sty") == 0)
559 if (i
>= args
.size())
561 std::stringstream aStrStream
;
562 aStrStream
<< "embeddingStylesheet missing" << std::endl
;
563 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
566 embeddStylesheet
= fs::path(args
[i
], fs::native
);
568 else if (args
[i
].compare("-zipdir") == 0)
571 if (i
>= args
.size())
573 std::stringstream aStrStream
;
574 aStrStream
<< "idxtemp missing" << std::endl
;
575 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
578 zipdir
= fs::path(args
[i
], fs::native
);
580 else if (args
[i
].compare("-idxcaption") == 0)
583 if (i
>= args
.size())
585 std::stringstream aStrStream
;
586 aStrStream
<< "idxcaption stylesheet missing" << std::endl
;
587 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
590 idxCaptionStylesheet
= fs::path(args
[i
], fs::native
);
592 else if (args
[i
].compare("-idxcontent") == 0)
595 if (i
>= args
.size())
597 std::stringstream aStrStream
;
598 aStrStream
<< "idxcontent stylesheet missing" << std::endl
;
599 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
602 idxContentStylesheet
= fs::path(args
[i
], fs::native
);
604 else if (args
[i
].compare("-o") == 0)
607 if (i
>= args
.size())
609 std::stringstream aStrStream
;
610 aStrStream
<< "outputfilename missing" << std::endl
;
611 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
614 outputFile
= fs::path(args
[i
], fs::native
);
616 else if (args
[i
].compare("-mod") == 0)
619 if (i
>= args
.size())
621 std::stringstream aStrStream
;
622 aStrStream
<< "module name missing" << std::endl
;
623 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
628 else if (args
[i
].compare("-lang") == 0)
631 if (i
>= args
.size())
633 std::stringstream aStrStream
;
634 aStrStream
<< "language name missing" << std::endl
;
635 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
640 else if (args
[i
].compare("-hid") == 0)
643 throw HelpProcessingException( HelpProcessingErrorClass::General
, "obsolete -hid argument used" );
645 else if (args
[i
].compare("-add") == 0)
647 std::string addFile
, addFileUnderPath
;
649 if (i
>= args
.size())
651 std::stringstream aStrStream
;
652 aStrStream
<< "pathname missing" << std::endl
;
653 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
656 addFileUnderPath
= args
[i
];
658 if (i
>= args
.size())
660 std::stringstream aStrStream
;
661 aStrStream
<< "pathname missing" << std::endl
;
662 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
665 if (!addFileUnderPath
.empty() && !addFile
.empty())
666 additionalFiles
[addFileUnderPath
] = addFile
;
668 else if (args
[i
].compare("-nolangroot") == 0)
669 m_bUseLangRoot
= false;
670 else if (args
[i
].compare("-noindex") == 0)
671 m_bCreateIndex
= false;
673 helpFiles
.push_back(args
[i
]);
677 //We can be called from the helplinker executable or the extension manager
678 //In the latter case extsource is not used.
679 if( (pExtensionPath
&& pExtensionPath
->length() > 0 && pOfficeHelpPath
)
680 || !extsource
.empty())
682 bExtensionMode
= true;
683 if (!extsource
.empty())
685 //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
687 sourceRoot
= fs::path(extsource
, fs::native
);
688 extensionPath
= sourceRoot
.toUTF8();
690 if (extdestination
.empty())
692 std::stringstream aStrStream
;
693 aStrStream
<< "-extlangdest is missing" << std::endl
;
694 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
698 //Convert from system path to file URL!!!
699 fs::path
p(extdestination
, fs::native
);
700 extensionDestination
= p
.toUTF8();
704 { //called from extension manager
705 extensionPath
= *pExtensionPath
;
706 sourceRoot
= fs::path(extensionPath
);
707 extensionDestination
= *pDestination
;
709 //check if -src option was used. This option must not be used
710 //when extension help is compiled.
713 std::stringstream aStrStream
;
714 aStrStream
<< "-src must not be used together with -extsource missing" << std::endl
;
715 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
719 if (!bExtensionMode
&& zipdir
.empty())
721 std::stringstream aStrStream
;
722 aStrStream
<< "no index dir given" << std::endl
;
723 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
726 if ( (!bExtensionMode
&& idxCaptionStylesheet
.empty())
727 || (!extsource
.empty() && idxCaptionStylesheet
.empty()) )
729 //No extension mode and extension mode using commandline
730 //!extsource.empty indicates extension mode using commandline
731 // -idxcaption parameter is required
732 std::stringstream aStrStream
;
733 aStrStream
<< "no index caption stylesheet given" << std::endl
;
734 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
736 else if ( bExtensionMode
&& extsource
.empty())
738 //This part is used when compileExtensionHelp is called from the extensions manager.
739 //If extension help is compiled using helplinker in the build process
740 OUString aIdxCaptionPathFileURL
= *pOfficeHelpPath
+ "/idxcaption.xsl";
742 OString
aOStr_IdxCaptionPathFileURL( OUStringToOString
743 ( aIdxCaptionPathFileURL
, fs::getThreadTextEncoding() ) );
744 std::string
aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL
.getStr() );
746 idxCaptionStylesheet
= fs::path( aStdStr_IdxCaptionPathFileURL
);
749 if ( (!bExtensionMode
&& idxContentStylesheet
.empty())
750 || (!extsource
.empty() && idxContentStylesheet
.empty()) )
752 //No extension mode and extension mode using commandline
753 //!extsource.empty indicates extension mode using commandline
754 // -idxcontent parameter is required
755 std::stringstream aStrStream
;
756 aStrStream
<< "no index content stylesheet given" << std::endl
;
757 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
759 else if ( bExtensionMode
&& extsource
.empty())
761 //If extension help is compiled using helplinker in the build process
762 //then -idxcontent must be supplied
763 //This part is used when compileExtensionHelp is called from the extensions manager.
764 OUString aIdxContentPathFileURL
= *pOfficeHelpPath
+ "/idxcontent.xsl";
766 OString
aOStr_IdxContentPathFileURL( OUStringToOString
767 ( aIdxContentPathFileURL
, fs::getThreadTextEncoding() ) );
768 std::string
aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL
.getStr() );
770 idxContentStylesheet
= fs::path( aStdStr_IdxContentPathFileURL
);
772 if (!bExtensionMode
&& embeddStylesheet
.empty())
774 std::stringstream aStrStream
;
775 aStrStream
<< "no embedding resolving file given" << std::endl
;
776 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
778 if (sourceRoot
.empty())
780 std::stringstream aStrStream
;
781 aStrStream
<< "no sourceroot given" << std::endl
;
782 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
784 if (!bExtensionMode
&& outputFile
.empty())
786 std::stringstream aStrStream
;
787 aStrStream
<< "no output file given" << std::endl
;
788 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
792 std::stringstream aStrStream
;
793 aStrStream
<< "module missing" << std::endl
;
794 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
796 if (!bExtensionMode
&& lang
.empty())
798 std::stringstream aStrStream
;
799 aStrStream
<< "language missing" << std::endl
;
800 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
805 // Variable to set an exception in "C" StructuredXMLErrorFunction
806 static const HelpProcessingException
* GpXMLParsingException
= nullptr;
810 static void StructuredXMLErrorFunction(SAL_UNUSED_PARAMETER
void *, xmlErrorPtr error
)
812 std::string aErrorMsg
= error
->message
;
813 std::string aXMLParsingFile
;
814 if( error
->file
!= nullptr )
815 aXMLParsingFile
= error
->file
;
816 int nXMLParsingLine
= error
->line
;
817 HelpProcessingException
* pException
= new HelpProcessingException( aErrorMsg
, aXMLParsingFile
, nXMLParsingLine
);
818 GpXMLParsingException
= pException
;
820 // Reset error handler
821 xmlSetStructuredErrorFunc( nullptr, nullptr );
826 HelpProcessingErrorInfo
& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException
& e
)
828 m_eErrorClass
= e
.m_eErrorClass
;
829 OString
tmpErrorMsg( e
.m_aErrorMsg
.c_str() );
830 m_aErrorMsg
= OStringToOUString( tmpErrorMsg
, fs::getThreadTextEncoding() );
831 OString
tmpXMLParsingFile( e
.m_aXMLParsingFile
.c_str() );
832 m_aXMLParsingFile
= OStringToOUString( tmpXMLParsingFile
, fs::getThreadTextEncoding() );
833 m_nXMLParsingLine
= e
.m_nXMLParsingLine
;
838 // Returns true in case of success, false in case of error
839 bool compileExtensionHelp
841 const OUString
& aOfficeHelpPath
,
842 const OUString
& aExtensionName
,
843 const OUString
& aExtensionLanguageRoot
,
844 sal_Int32 nXhpFileCount
, const OUString
* pXhpFiles
,
845 const OUString
& aDestination
,
846 HelpProcessingErrorInfo
& o_rHelpProcessingErrorInfo
849 bool bSuccess
= true;
851 std::vector
<std::string
> args
;
852 args
.reserve(nXhpFileCount
+ 2);
853 args
.push_back(std::string("-mod"));
854 OString aOExtensionName
= OUStringToOString( aExtensionName
, fs::getThreadTextEncoding() );
855 args
.push_back(std::string(aOExtensionName
.getStr()));
857 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
859 OUString aXhpFile
= pXhpFiles
[iXhp
];
861 OString aOXhpFile
= OUStringToOString( aXhpFile
, fs::getThreadTextEncoding() );
862 args
.push_back(std::string(aOXhpFile
.getStr()));
865 OString aOExtensionLanguageRoot
= OUStringToOString( aExtensionLanguageRoot
, fs::getThreadTextEncoding() );
866 const char* pExtensionPath
= aOExtensionLanguageRoot
.getStr();
867 std::string aStdStrExtensionPath
= pExtensionPath
;
868 OString aODestination
= OUStringToOString(aDestination
, fs::getThreadTextEncoding());
869 const char* pDestination
= aODestination
.getStr();
870 std::string aStdStrDestination
= pDestination
;
873 xmlSetStructuredErrorFunc( nullptr, StructuredXMLErrorFunction
);
876 std::unique_ptr
<HelpLinker
> pHelpLinker(new HelpLinker());
877 pHelpLinker
->main( args
, &aStdStrExtensionPath
, &aStdStrDestination
, &aOfficeHelpPath
);
879 catch( const HelpProcessingException
& e
)
881 if( GpXMLParsingException
!= nullptr )
883 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
884 delete GpXMLParsingException
;
885 GpXMLParsingException
= nullptr;
889 o_rHelpProcessingErrorInfo
= e
;
893 // Reset error handler
894 xmlSetStructuredErrorFunc( nullptr, nullptr );
896 // i83624: Tree files
897 // The following basically checks if the help.tree is well formed XML.
898 // Apparently there have been cases when translations contained
899 // non-well-formed XML in the past.
900 OUString aTreeFileURL
= aExtensionLanguageRoot
+ "/help.tree";
901 osl::DirectoryItem aTreeFileItem
;
902 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
903 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileSize
);
904 if( rcGet
== osl::FileBase::E_None
&&
905 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
906 aFileStatus
.isValid( osl_FileStatus_Mask_FileSize
) )
908 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
909 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
910 osl::File
aFile( aTreeFileURL
);
911 (void)aFile
.open( osl_File_OpenFlag_Read
);
912 aFile
.read( s
.get(), len
, ret
);
915 XML_Parser parser
= XML_ParserCreate( nullptr );
916 XML_Status parsed
= XML_Parse( parser
, s
.get(), int( len
), true );
918 if (XML_STATUS_ERROR
== parsed
)
920 XML_Error nError
= XML_GetErrorCode( parser
);
921 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HelpProcessingErrorClass::XmlParsing
;
922 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= OUString::createFromAscii( XML_ErrorString( nError
) );
923 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
924 // CRASHES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
928 XML_ParserFree( parser
);
934 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */