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
, osl_getThreadTextEncoding() ) );
78 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
79 OString
aOStr_PathURL( OUStringToOString
80 ( aPathURL
, osl_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
)
110 xmlDocPtr resContent
= xsltApplyStylesheet( m_xsltStylesheetPtrContent
, doc
, nullptr );
111 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
112 if( pResNodeContent
)
114 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
115 FILE* pFile_docURL
= fopen_impl( fsContentPureTextFile_docURL
, "w" );
118 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
119 fclose( pFile_docURL
);
122 xmlFreeDoc(resContent
);
129 std::vector
<std::string
> _idList
;
131 void append(const std::string
&id
)
133 _idList
.push_back(id
);
136 std::string
getString() const
139 for (auto const& elem
: _idList
)
147 static void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
149 if( pFile
== nullptr )
152 unsigned int nKeyLen
= aKeyStr
.length();
153 unsigned int nValueLen
= aValueStr
.length();
154 fprintf( pFile
, "%x ", nKeyLen
);
157 if (fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
) != nKeyLen
)
158 fprintf(stderr
, "fwrite to db failed\n");
160 if (fprintf( pFile
, " %x ", nValueLen
) < 0)
161 fprintf(stderr
, "fwrite to db failed\n");
164 if (fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
) != nValueLen
)
165 fprintf(stderr
, "fwrite to db failed\n");
167 if (fprintf( pFile
, "%c", cLF
) < 0)
168 fprintf(stderr
, "fwrite to db failed\n");
176 typedef std::unordered_map
<std::string
, Data
> DataHashtable
;
180 void insert(const std::string
&key
, const std::string
&id
)
182 Data
&data
= _hash
[key
];
186 void dump_DBHelp( const fs::path
& rFileName
)
188 FILE* pFile
= fopen_impl( rFileName
, "wb" );
189 if( pFile
== nullptr )
192 for (auto const& elem
: _hash
)
193 writeKeyValue_DBHelp( pFile
, elem
.first
, elem
.second
.getString() );
203 static std::string
encode(const std::string
&rIn
)
205 const char * const good
= "!$&'()*+,-.=@_";
206 static const char hex
[17] = "0123456789ABCDEF";
211 if (rtl::isAsciiAlphanumeric (static_cast<unsigned char>(c
))
217 result
+= hex
[static_cast<unsigned char>(c
) >> 4];
218 result
+= hex
[c
& 0xf];
225 void HelpLinker::addBookmark( FILE* pFile_DBHelp
, std::string thishid
,
226 const std::string
& fileB
, const std::string
& anchorB
,
227 const std::string
& jarfileB
, const std::string
& titleB
)
229 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
230 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
232 thishid
= URLEncoder::encode(thishid
);
234 int fileLen
= fileB
.length();
235 if (!anchorB
.empty())
236 fileLen
+= (1 + anchorB
.length());
237 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
239 std::vector
<unsigned char> dataB(dataLen
);
241 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
243 dataB
[i
++] = static_cast<unsigned char>(j
);
244 if (!anchorB
.empty())
247 for (char j
: anchorB
)
250 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
251 for (char j
: jarfileB
)
254 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
255 for (char j
: titleB
)
258 if( pFile_DBHelp
!= nullptr )
260 std::string
aValueStr( dataB
.begin(), dataB
.end() );
261 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
265 void HelpLinker::initIndexerPreProcessor()
267 m_pIndexerPreProcessor
.reset( new IndexerPreProcessor( indexDirParentName
,
268 idxCaptionStylesheet
, idxContentStylesheet
) );
271 void HelpLinker::link()
276 indexDirParentName
= extensionDestination
;
280 indexDirParentName
= zipdir
;
281 fs::create_directory(indexDirParentName
);
284 std::string mod
= module
;
285 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
288 // continue with introduction of the overall process thing into the
289 // here all hzip files will be worked on
291 if( !bExtensionMode
)
294 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
295 FILE* pFileHelpText_DBHelp
= fopen_impl( helpTextFileName_DBHelp
, "wb" );
297 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
298 FILE* pFileDbBase_DBHelp
= fopen_impl( dbBaseFileName_DBHelp
, "wb" );
300 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
302 HelpKeyword helpKeyword
;
304 // catch HelpProcessingException to avoid locking data bases
307 bool bIndexForExtension
= true;
308 // lastly, initialize the indexBuilder
309 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
310 initIndexerPreProcessor();
312 // here we start our loop over the hzip files.
313 for (auto const& helpFile
: helpFiles
)
316 // streamTable contains the streams in the hzip file
317 StreamTable streamTable
;
318 const std::string
&xhpFileName
= helpFile
;
320 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
322 // only work on .xhp - files
323 SAL_WARN("helpcompiler",
324 "ERROR: input list entry '"
326 << "' has the wrong extension (only files with extension .xhp are accepted)");
331 fs::path
langsourceRoot(sourceRoot
);
336 // langsourceRoot == sourceRoot for extensions
337 std::string
xhpFileNameComplete( extensionPath
);
338 xhpFileNameComplete
.append( '/' + xhpFileName
);
339 xhpFile
= fs::path( xhpFileNameComplete
);
343 langsourceRoot
.append( "/" );
344 if ( m_bUseLangRoot
)
345 langsourceRoot
.append( lang
+ '/' );
346 xhpFile
= fs::path(xhpFileName
, fs::native
);
349 HelpCompiler
hc( streamTable
, xhpFile
, langsourceRoot
, zipdir
,
350 compactStylesheet
, embeddStylesheet
, module
, lang
, bExtensionMode
);
352 HCDBG(std::cerr
<< "before compile of " << xhpFileName
<< std::endl
);
354 HCDBG(std::cerr
<< "after compile of " << xhpFileName
<< std::endl
);
359 std::string documentPath
= streamTable
.document_path
;
360 if (documentPath
.compare(0, 1, "/") == 0)
361 documentPath
= documentPath
.substr(1);
363 std::string documentJarfile
= streamTable
.document_module
+ ".jar";
365 std::string documentTitle
= streamTable
.document_title
;
366 if (documentTitle
.empty())
367 documentTitle
= "<notitle>";
369 const std::string
& fileB
= documentPath
;
370 const std::string
& jarfileB
= documentJarfile
;
371 std::string
& titleB
= documentTitle
;
373 // add once this as its own id.
374 addBookmark( pFileDbBase_DBHelp
, documentPath
, fileB
, std::string(), jarfileB
, titleB
);
376 const std::vector
<std::string
> *hidlist
= streamTable
.appl_hidlist
.get();
379 // now iterate over all elements of the hidlist
380 for (auto & elem
: *hidlist
)
382 std::string thishid
= elem
;
385 size_t index
= thishid
.rfind('#');
386 if (index
!= std::string::npos
)
388 anchorB
= thishid
.substr(1 + index
);
389 thishid
= thishid
.substr(0, index
);
391 addBookmark( pFileDbBase_DBHelp
, thishid
, fileB
, anchorB
, jarfileB
, titleB
);
396 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
.get();
397 if (anchorToLL
&& !anchorToLL
->empty())
399 std::string fakedHid
= URLEncoder::encode(documentPath
);
400 for (auto const& elemAnchor
: *anchorToLL
)
402 const std::string
&anchor
= elemAnchor
.first
;
403 addBookmark(pFileDbBase_DBHelp
, documentPath
, fileB
,
404 anchor
, jarfileB
, titleB
);
405 std::string totalId
= fakedHid
+ "#" + anchor
;
406 // std::cerr << hzipFileName << std::endl;
407 const LinkedList
& ll
= elemAnchor
.second
;
408 for (auto const& elem
: ll
)
410 helpKeyword
.insert(elem
, totalId
);
416 // and last the helptexts
417 const Stringtable
*helpTextHash
= streamTable
.appl_helptexts
.get();
420 for (auto const& elem
: *helpTextHash
)
422 std::string helpTextId
= elem
.first
;
423 const std::string
& helpTextText
= elem
.second
;
425 helpTextId
= URLEncoder::encode(helpTextId
);
427 if( pFileHelpText_DBHelp
!= nullptr )
428 writeKeyValue_DBHelp( pFileHelpText_DBHelp
, helpTextId
, helpTextText
);
432 //IndexerPreProcessor
433 if( !bExtensionMode
|| bIndexForExtension
)
436 xmlDocPtr document
= streamTable
.appl_doc
;
439 std::string temp
= module
;
440 std::transform (temp
.begin(), temp
.end(), temp
.begin(), tocharlower
);
441 m_pIndexerPreProcessor
->processDocument(document
, URLEncoder::encode(documentPath
) );
448 catch( const HelpProcessingException
& )
450 // catch HelpProcessingException to avoid locking data bases
451 if( pFileHelpText_DBHelp
!= nullptr )
452 fclose( pFileHelpText_DBHelp
);
453 if( pFileDbBase_DBHelp
!= nullptr )
454 fclose( pFileDbBase_DBHelp
);
458 if( pFileHelpText_DBHelp
!= nullptr )
459 fclose( pFileHelpText_DBHelp
);
460 if( pFileDbBase_DBHelp
!= nullptr )
461 fclose( pFileDbBase_DBHelp
);
463 helpKeyword
.dump_DBHelp( keyWordFileName_DBHelp
);
469 for (auto const& additionalFile
: additionalFiles
)
471 const std::string
&additionalFileName
= additionalFile
.second
;
472 const std::string
&additionalFileKey
= additionalFile
.first
;
474 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
476 std::string aNativeStr
= fsAdditionalFileName
.native_file_string();
477 const char* pStr
= aNativeStr
.c_str();
478 std::cerr
<< pStr
<< std::endl
;
481 fs::path
fsTargetName( indexDirParentName
/ additionalFileKey
);
483 fs::copy( fsAdditionalFileName
, fsTargetName
);
488 void HelpLinker::main( std::vector
<std::string
> &args
,
489 std::string
const * pExtensionPath
, std::string
const * pDestination
,
490 const OUString
* pOfficeHelpPath
)
492 bExtensionMode
= false;
495 if ((!args
.empty()) && args
[0][0] == '@')
497 std::vector
<std::string
> stringList
;
498 std::ifstream
fileReader(args
[0].substr(1).c_str());
505 stringList
.push_back(token
);
513 bool bSrcOption
= false;
514 while (i
< args
.size())
516 if (args
[i
].compare("-extlangsrc") == 0)
519 if (i
>= args
.size())
521 std::stringstream aStrStream
;
522 aStrStream
<< "extension source missing" << std::endl
;
523 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
527 else if (args
[i
].compare("-extlangdest") == 0)
529 //If this argument is not provided then the location provided in -extsource will
530 //also be the destination
532 if (i
>= args
.size())
534 std::stringstream aStrStream
;
535 aStrStream
<< "extension destination missing" << std::endl
;
536 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
538 extdestination
= args
[i
];
540 else if (args
[i
].compare("-src") == 0)
543 if (i
>= args
.size())
545 std::stringstream aStrStream
;
546 aStrStream
<< "sourceroot missing" << std::endl
;
547 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
550 sourceRoot
= fs::path(args
[i
], fs::native
);
552 else if (args
[i
].compare("-compact") == 0)
555 if (i
>= args
.size())
557 std::stringstream aStrStream
;
558 aStrStream
<< "compactStylesheet missing" << std::endl
;
559 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
562 compactStylesheet
= fs::path(args
[i
], fs::native
);
564 else if (args
[i
].compare("-sty") == 0)
567 if (i
>= args
.size())
569 std::stringstream aStrStream
;
570 aStrStream
<< "embeddingStylesheet missing" << std::endl
;
571 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
574 embeddStylesheet
= fs::path(args
[i
], fs::native
);
576 else if (args
[i
].compare("-zipdir") == 0)
579 if (i
>= args
.size())
581 std::stringstream aStrStream
;
582 aStrStream
<< "idxtemp missing" << std::endl
;
583 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
586 zipdir
= fs::path(args
[i
], fs::native
);
588 else if (args
[i
].compare("-idxcaption") == 0)
591 if (i
>= args
.size())
593 std::stringstream aStrStream
;
594 aStrStream
<< "idxcaption stylesheet missing" << std::endl
;
595 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
598 idxCaptionStylesheet
= fs::path(args
[i
], fs::native
);
600 else if (args
[i
].compare("-idxcontent") == 0)
603 if (i
>= args
.size())
605 std::stringstream aStrStream
;
606 aStrStream
<< "idxcontent stylesheet missing" << std::endl
;
607 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
610 idxContentStylesheet
= fs::path(args
[i
], fs::native
);
612 else if (args
[i
].compare("-o") == 0)
615 if (i
>= args
.size())
617 std::stringstream aStrStream
;
618 aStrStream
<< "outputfilename missing" << std::endl
;
619 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
622 outputFile
= fs::path(args
[i
], fs::native
);
624 else if (args
[i
].compare("-mod") == 0)
627 if (i
>= args
.size())
629 std::stringstream aStrStream
;
630 aStrStream
<< "module name missing" << std::endl
;
631 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
636 else if (args
[i
].compare("-lang") == 0)
639 if (i
>= args
.size())
641 std::stringstream aStrStream
;
642 aStrStream
<< "language name missing" << std::endl
;
643 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
648 else if (args
[i
].compare("-hid") == 0)
651 throw HelpProcessingException( HelpProcessingErrorClass::General
, "obsolete -hid argument used" );
653 else if (args
[i
].compare("-add") == 0)
655 std::string addFile
, addFileUnderPath
;
657 if (i
>= args
.size())
659 std::stringstream aStrStream
;
660 aStrStream
<< "pathname missing" << std::endl
;
661 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
664 addFileUnderPath
= args
[i
];
666 if (i
>= args
.size())
668 std::stringstream aStrStream
;
669 aStrStream
<< "pathname missing" << std::endl
;
670 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
673 if (!addFileUnderPath
.empty() && !addFile
.empty())
674 additionalFiles
[addFileUnderPath
] = addFile
;
676 else if (args
[i
].compare("-nolangroot") == 0)
677 m_bUseLangRoot
= false;
678 else if (args
[i
].compare("-noindex") == 0)
679 m_bCreateIndex
= false;
681 helpFiles
.push_back(args
[i
]);
685 //We can be called from the helplinker executable or the extension manager
686 //In the latter case extsource is not used.
687 if( (pExtensionPath
&& pExtensionPath
->length() > 0 && pOfficeHelpPath
)
688 || !extsource
.empty())
690 bExtensionMode
= true;
691 if (!extsource
.empty())
693 //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
695 sourceRoot
= fs::path(extsource
, fs::native
);
696 extensionPath
= sourceRoot
.toUTF8();
698 if (extdestination
.empty())
700 std::stringstream aStrStream
;
701 aStrStream
<< "-extlangdest is missing" << std::endl
;
702 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
706 //Convert from system path to file URL!!!
707 fs::path
p(extdestination
, fs::native
);
708 extensionDestination
= p
.toUTF8();
712 { //called from extension manager
713 extensionPath
= *pExtensionPath
;
714 sourceRoot
= fs::path(extensionPath
);
715 extensionDestination
= *pDestination
;
717 //check if -src option was used. This option must not be used
718 //when extension help is compiled.
721 std::stringstream aStrStream
;
722 aStrStream
<< "-src must not be used together with -extsource missing" << std::endl
;
723 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
727 if (!bExtensionMode
&& zipdir
.empty())
729 std::stringstream aStrStream
;
730 aStrStream
<< "no index dir given" << std::endl
;
731 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
734 if ( (!bExtensionMode
&& idxCaptionStylesheet
.empty())
735 || (!extsource
.empty() && idxCaptionStylesheet
.empty()) )
737 //No extension mode and extension mode using commandline
738 //!extsource.empty indicates extension mode using commandline
739 // -idxcaption parameter is required
740 std::stringstream aStrStream
;
741 aStrStream
<< "no index caption stylesheet given" << std::endl
;
742 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
744 else if ( bExtensionMode
&& extsource
.empty())
746 //This part is used when compileExtensionHelp is called from the extensions manager.
747 //If extension help is compiled using helplinker in the build process
748 OUString aIdxCaptionPathFileURL
= *pOfficeHelpPath
+ "/idxcaption.xsl";
750 OString
aOStr_IdxCaptionPathFileURL( OUStringToOString
751 ( aIdxCaptionPathFileURL
, osl_getThreadTextEncoding() ) );
752 std::string
aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL
.getStr() );
754 idxCaptionStylesheet
= fs::path( aStdStr_IdxCaptionPathFileURL
);
757 if ( (!bExtensionMode
&& idxContentStylesheet
.empty())
758 || (!extsource
.empty() && idxContentStylesheet
.empty()) )
760 //No extension mode and extension mode using commandline
761 //!extsource.empty indicates extension mode using commandline
762 // -idxcontent parameter is required
763 std::stringstream aStrStream
;
764 aStrStream
<< "no index content stylesheet given" << std::endl
;
765 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
767 else if ( bExtensionMode
&& extsource
.empty())
769 //If extension help is compiled using helplinker in the build process
770 //then -idxcontent must be supplied
771 //This part is used when compileExtensionHelp is called from the extensions manager.
772 OUString aIdxContentPathFileURL
= *pOfficeHelpPath
+ "/idxcontent.xsl";
774 OString
aOStr_IdxContentPathFileURL( OUStringToOString
775 ( aIdxContentPathFileURL
, osl_getThreadTextEncoding() ) );
776 std::string
aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL
.getStr() );
778 idxContentStylesheet
= fs::path( aStdStr_IdxContentPathFileURL
);
780 if (!bExtensionMode
&& embeddStylesheet
.empty())
782 std::stringstream aStrStream
;
783 aStrStream
<< "no embedding resolving file given" << std::endl
;
784 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
786 if (sourceRoot
.empty())
788 std::stringstream aStrStream
;
789 aStrStream
<< "no sourceroot given" << std::endl
;
790 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
792 if (!bExtensionMode
&& outputFile
.empty())
794 std::stringstream aStrStream
;
795 aStrStream
<< "no output file given" << std::endl
;
796 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
800 std::stringstream aStrStream
;
801 aStrStream
<< "module missing" << std::endl
;
802 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
804 if (!bExtensionMode
&& lang
.empty())
806 std::stringstream aStrStream
;
807 aStrStream
<< "language missing" << std::endl
;
808 throw HelpProcessingException( HelpProcessingErrorClass::General
, aStrStream
.str() );
813 // Variable to set an exception in "C" StructuredXMLErrorFunction
814 static const HelpProcessingException
* GpXMLParsingException
= nullptr;
818 static void StructuredXMLErrorFunction(SAL_UNUSED_PARAMETER
void *, xmlErrorPtr error
)
820 std::string aErrorMsg
= error
->message
;
821 std::string aXMLParsingFile
;
822 if( error
->file
!= nullptr )
823 aXMLParsingFile
= error
->file
;
824 int nXMLParsingLine
= error
->line
;
825 HelpProcessingException
* pException
= new HelpProcessingException( aErrorMsg
, aXMLParsingFile
, nXMLParsingLine
);
826 GpXMLParsingException
= pException
;
828 // Reset error handler
829 xmlSetStructuredErrorFunc( nullptr, nullptr );
834 HelpProcessingErrorInfo
& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException
& e
)
836 m_eErrorClass
= e
.m_eErrorClass
;
837 OString
tmpErrorMsg( e
.m_aErrorMsg
.c_str() );
838 m_aErrorMsg
= OStringToOUString( tmpErrorMsg
, osl_getThreadTextEncoding() );
839 OString
tmpXMLParsingFile( e
.m_aXMLParsingFile
.c_str() );
840 m_aXMLParsingFile
= OStringToOUString( tmpXMLParsingFile
, osl_getThreadTextEncoding() );
841 m_nXMLParsingLine
= e
.m_nXMLParsingLine
;
846 // Returns true in case of success, false in case of error
847 bool compileExtensionHelp
849 const OUString
& aOfficeHelpPath
,
850 const OUString
& aExtensionName
,
851 const OUString
& aExtensionLanguageRoot
,
852 sal_Int32 nXhpFileCount
, const OUString
* pXhpFiles
,
853 const OUString
& aDestination
,
854 HelpProcessingErrorInfo
& o_rHelpProcessingErrorInfo
857 bool bSuccess
= true;
859 std::vector
<std::string
> args
;
860 args
.reserve(nXhpFileCount
+ 2);
861 args
.push_back(std::string("-mod"));
862 OString aOExtensionName
= OUStringToOString( aExtensionName
, osl_getThreadTextEncoding() );
863 args
.push_back(std::string(aOExtensionName
.getStr()));
865 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
867 OUString aXhpFile
= pXhpFiles
[iXhp
];
869 OString aOXhpFile
= OUStringToOString( aXhpFile
, osl_getThreadTextEncoding() );
870 args
.push_back(std::string(aOXhpFile
.getStr()));
873 OString aOExtensionLanguageRoot
= OUStringToOString( aExtensionLanguageRoot
, osl_getThreadTextEncoding() );
874 const char* pExtensionPath
= aOExtensionLanguageRoot
.getStr();
875 std::string aStdStrExtensionPath
= pExtensionPath
;
876 OString aODestination
= OUStringToOString(aDestination
, osl_getThreadTextEncoding());
877 const char* pDestination
= aODestination
.getStr();
878 std::string aStdStrDestination
= pDestination
;
881 xmlSetStructuredErrorFunc( nullptr, StructuredXMLErrorFunction
);
884 std::unique_ptr
<HelpLinker
> pHelpLinker(new HelpLinker());
885 pHelpLinker
->main( args
, &aStdStrExtensionPath
, &aStdStrDestination
, &aOfficeHelpPath
);
887 catch( const HelpProcessingException
& e
)
889 if( GpXMLParsingException
!= nullptr )
891 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
892 delete GpXMLParsingException
;
893 GpXMLParsingException
= nullptr;
897 o_rHelpProcessingErrorInfo
= e
;
901 // Reset error handler
902 xmlSetStructuredErrorFunc( nullptr, nullptr );
904 // i83624: Tree files
905 // The following basically checks if the help.tree is well formed XML.
906 // Apparently there have been cases when translations contained
907 // non-well-formed XML in the past.
908 OUString aTreeFileURL
= aExtensionLanguageRoot
+ "/help.tree";
909 osl::DirectoryItem aTreeFileItem
;
910 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
911 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileSize
);
912 if( rcGet
== osl::FileBase::E_None
&&
913 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
914 aFileStatus
.isValid( osl_FileStatus_Mask_FileSize
) )
916 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
917 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
918 osl::File
aFile( aTreeFileURL
);
919 (void)aFile
.open( osl_File_OpenFlag_Read
);
920 aFile
.read( s
.get(), len
, ret
);
923 XML_Parser parser
= XML_ParserCreate( nullptr );
924 XML_Status parsed
= XML_Parse( parser
, s
.get(), int( len
), true );
926 if (XML_STATUS_ERROR
== parsed
)
928 XML_Error nError
= XML_GetErrorCode( parser
);
929 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HelpProcessingErrorClass::XmlParsing
;
930 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= OUString::createFromAscii( XML_ErrorString( nError
) );
931 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
932 // CRASHES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
936 XML_ParserFree( parser
);
942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */