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/xslt.h>
29 #include <libxslt/xsltutils.h>
30 #include <libxslt/functions.h>
31 #include <libxslt/extensions.h>
34 #include <sal/types.h>
36 #include <rtl/bootstrap.hxx>
41 IndexerPreProcessor::IndexerPreProcessor
42 ( const fs::path
& fsIndexBaseDir
,
43 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
)
45 m_fsCaptionFilesDirName
= fsIndexBaseDir
/ "caption";
46 fs::create_directory( m_fsCaptionFilesDirName
);
48 m_fsContentFilesDirName
= fsIndexBaseDir
/ "content";
49 fs::create_directory( m_fsContentFilesDirName
);
51 m_xsltStylesheetPtrCaption
= xsltParseStylesheetFile
52 (reinterpret_cast<const xmlChar
*>(idxCaptionStylesheet
.native_file_string().c_str()));
53 m_xsltStylesheetPtrContent
= xsltParseStylesheetFile
54 (reinterpret_cast<const xmlChar
*>(idxContentStylesheet
.native_file_string().c_str()));
57 IndexerPreProcessor::~IndexerPreProcessor()
59 if( m_xsltStylesheetPtrCaption
)
60 xsltFreeStylesheet( m_xsltStylesheetPtrCaption
);
61 if( m_xsltStylesheetPtrContent
)
62 xsltFreeStylesheet( m_xsltStylesheetPtrContent
);
65 std::string
getEncodedPath( const std::string
& Path
)
67 OString
aOStr_Path( Path
.c_str() );
68 OUString
aOUStr_Path( OStringToOUString
69 ( aOStr_Path
, fs::getThreadTextEncoding() ) );
71 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
72 OString
aOStr_PathURL( OUStringToOString
73 ( aPathURL
, fs::getThreadTextEncoding() ) );
74 std::string
aStdStr_PathURL( aOStr_PathURL
.getStr() );
75 return aStdStr_PathURL
;
78 void IndexerPreProcessor::processDocument
79 ( xmlDocPtr doc
, const std::string
&EncodedDocPath
)
81 std::string aStdStr_EncodedDocPathURL
= getEncodedPath( EncodedDocPath
);
83 if( m_xsltStylesheetPtrCaption
)
85 xmlDocPtr resCaption
= xsltApplyStylesheet( m_xsltStylesheetPtrCaption
, doc
, nullptr );
86 xmlNodePtr pResNodeCaption
= resCaption
->xmlChildrenNode
;
89 fs::path fsCaptionPureTextFile_docURL
= m_fsCaptionFilesDirName
/ aStdStr_EncodedDocPathURL
;
90 #ifdef _WIN32 //We need _wfopen to support long file paths on Windows XP
91 FILE* pFile_docURL
= _wfopen(
92 fsCaptionPureTextFile_docURL
.native_file_string_w(), L
"w" );
94 FILE* pFile_docURL
= fopen(
95 fsCaptionPureTextFile_docURL
.native_file_string().c_str(), "w" );
99 fprintf( pFile_docURL
, "%s\n", pResNodeCaption
->content
);
100 fclose( pFile_docURL
);
103 xmlFreeDoc(resCaption
);
106 if( m_xsltStylesheetPtrContent
)
108 xmlDocPtr resContent
= xsltApplyStylesheet( m_xsltStylesheetPtrContent
, doc
, nullptr );
109 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
110 if( pResNodeContent
)
112 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
113 #ifdef _WIN32 //We need _wfopen to support long file paths on Windows XP
114 FILE* pFile_docURL
= _wfopen(
115 fsContentPureTextFile_docURL
.native_file_string_w(), L
"w" );
117 FILE* pFile_docURL
= fopen(
118 fsContentPureTextFile_docURL
.native_file_string().c_str(), "w" );
122 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
123 fclose( pFile_docURL
);
126 xmlFreeDoc(resContent
);
132 std::vector
<std::string
> _idList
;
133 typedef std::vector
<std::string
>::const_iterator cIter
;
135 void append(const std::string
&id
)
137 _idList
.push_back(id
);
140 std::string
getString() const
143 cIter aEnd
= _idList
.end();
144 for (cIter aIter
= _idList
.begin(); aIter
!= aEnd
; ++aIter
)
150 void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
152 if( pFile
== nullptr )
155 unsigned int nKeyLen
= aKeyStr
.length();
156 unsigned int nValueLen
= aValueStr
.length();
157 fprintf( pFile
, "%x ", nKeyLen
);
160 if (fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
) != nKeyLen
)
161 fprintf(stderr
, "fwrite to db failed\n");
163 if (fprintf( pFile
, " %x ", nValueLen
) < 0)
164 fprintf(stderr
, "fwrite to db failed\n");
167 if (fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
) != nValueLen
)
168 fprintf(stderr
, "fwrite to db failed\n");
170 if (fprintf( pFile
, "%c", cLF
) < 0)
171 fprintf(stderr
, "fwrite to db failed\n");
177 typedef std::unordered_map
<std::string
, Data
, pref_hash
> DataHashtable
;
181 void insert(const std::string
&key
, const std::string
&id
)
183 Data
&data
= _hash
[key
];
187 void dump_DBHelp( const fs::path
& rFileName
)
189 #ifdef _WIN32 //We need _wfopen to support long file paths on Windows XP
190 FILE* pFile
= _wfopen( rFileName
.native_file_string_w(), L
"wb" );
192 FILE* pFile
= fopen( rFileName
.native_file_string().c_str(), "wb" );
194 if( pFile
== nullptr )
197 DataHashtable::const_iterator aEnd
= _hash
.end();
198 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
199 writeKeyValue_DBHelp( pFile
, aIter
->first
, aIter
->second
.getString() );
207 static std::string
encode(const std::string
&rIn
)
209 const char *good
= "!$&'()*+,-.=@_";
210 static const char hex
[17] = "0123456789ABCDEF";
215 if (isalnum (c
) || strchr (good
, c
))
219 result
+= hex
[c
>> 4];
220 result
+= hex
[c
& 0xf];
227 void HelpLinker::addBookmark( FILE* pFile_DBHelp
, std::string thishid
,
228 const std::string
& fileB
, const std::string
& anchorB
,
229 const std::string
& jarfileB
, const std::string
& titleB
)
231 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
232 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
234 thishid
= URLEncoder::encode(thishid
);
236 int fileLen
= fileB
.length();
237 if (!anchorB
.empty())
238 fileLen
+= (1 + anchorB
.length());
239 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
241 std::vector
<unsigned char> dataB(dataLen
);
243 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
245 dataB
[i
++] = static_cast<unsigned char>(j
);
246 if (!anchorB
.empty())
249 for (char j
: anchorB
)
252 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
253 for (char j
: jarfileB
)
256 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
257 for (char j
: titleB
)
260 if( pFile_DBHelp
!= nullptr )
262 std::string
aValueStr( dataB
.begin(), dataB
.end() );
263 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
267 void HelpLinker::initIndexerPreProcessor()
269 delete m_pIndexerPreProcessor
;
270 m_pIndexerPreProcessor
= new IndexerPreProcessor( indexDirParentName
,
271 idxCaptionStylesheet
, idxContentStylesheet
);
277 void HelpLinker::link() throw(HelpProcessingException
, BasicCodeTagger::TaggerException
, std::exception
)
282 indexDirParentName
= extensionDestination
;
286 indexDirParentName
= zipdir
;
287 fs::create_directory(indexDirParentName
);
290 std::string mod
= module
;
291 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
294 // continue with introduction of the overall process thing into the
295 // here all hzip files will be worked on
296 std::string appl
= mod
;
298 appl
= appl
.substr(1);
301 if( !bExtensionMode
)
304 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
306 //We need _wfopen to support long file paths on Windows XP
307 FILE* pFileHelpText_DBHelp
= _wfopen
308 ( helpTextFileName_DBHelp
.native_file_string_w(), L
"wb" );
311 FILE* pFileHelpText_DBHelp
= fopen
312 ( helpTextFileName_DBHelp
.native_file_string().c_str(), "wb" );
315 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
317 //We need _wfopen to support long file paths on Windows XP
318 FILE* pFileDbBase_DBHelp
= _wfopen
319 ( dbBaseFileName_DBHelp
.native_file_string_w(), L
"wb" );
321 FILE* pFileDbBase_DBHelp
= fopen
322 ( dbBaseFileName_DBHelp
.native_file_string().c_str(), "wb" );
325 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
327 HelpKeyword helpKeyword
;
329 // catch HelpProcessingException to avoid locking data bases
332 bool bIndexForExtension
= true;
333 // lastly, initialize the indexBuilder
334 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
335 initIndexerPreProcessor();
337 // here we start our loop over the hzip files.
338 HashSet::iterator end
= helpFiles
.end();
339 for (HashSet::iterator iter
= helpFiles
.begin(); iter
!= end
; ++iter
)
342 // streamTable contains the streams in the hzip file
343 StreamTable streamTable
;
344 const std::string
&xhpFileName
= *iter
;
346 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
348 // only work on .xhp - files
349 SAL_WARN("helpcompiler",
350 "ERROR: input list entry '"
352 << "' has the wrong extension (only files with extension .xhp are accepted)");
357 fs::path
langsourceRoot(sourceRoot
);
362 // langsourceRoot == sourceRoot for extensions
363 std::string
xhpFileNameComplete( extensionPath
);
364 xhpFileNameComplete
.append( '/' + xhpFileName
);
365 xhpFile
= fs::path( xhpFileNameComplete
);
369 langsourceRoot
.append( "/" );
370 if ( m_bUseLangRoot
)
371 langsourceRoot
.append( lang
+ '/' );
372 xhpFile
= fs::path(xhpFileName
, fs::native
);
375 HelpCompiler
hc( streamTable
, xhpFile
, langsourceRoot
, zipdir
,
376 compactStylesheet
, embeddStylesheet
, module
, lang
, bExtensionMode
);
378 HCDBG(std::cerr
<< "before compile of " << xhpFileName
<< std::endl
);
379 bool success
= hc
.compile();
380 HCDBG(std::cerr
<< "after compile of " << xhpFileName
<< std::endl
);
382 if (!success
&& !bExtensionMode
)
384 std::stringstream aStrStream
;
386 "\nERROR: compiling help particle '"
388 << "' for language '"
391 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
397 std::string documentPath
= streamTable
.document_path
;
398 if (documentPath
.compare(0, 1, "/") == 0)
399 documentPath
= documentPath
.substr(1);
401 std::string documentJarfile
= streamTable
.document_module
+ ".jar";
403 std::string documentTitle
= streamTable
.document_title
;
404 if (documentTitle
.empty())
405 documentTitle
= "<notitle>";
407 const std::string
& fileB
= documentPath
;
408 const std::string
& jarfileB
= documentJarfile
;
409 std::string
& titleB
= documentTitle
;
411 // add once this as its own id.
412 addBookmark( pFileDbBase_DBHelp
, documentPath
, fileB
, std::string(), jarfileB
, titleB
);
414 const HashSet
*hidlist
= streamTable
.appl_hidlist
;
416 hidlist
= streamTable
.default_hidlist
;
417 if (hidlist
&& !hidlist
->empty())
419 // now iterate over all elements of the hidlist
420 HashSet::const_iterator aEnd
= hidlist
->end();
421 for (HashSet::const_iterator hidListIter
= hidlist
->begin();
422 hidListIter
!= aEnd
; ++hidListIter
)
424 std::string thishid
= *hidListIter
;
427 size_t index
= thishid
.rfind('#');
428 if (index
!= std::string::npos
)
430 anchorB
= thishid
.substr(1 + index
);
431 thishid
= thishid
.substr(0, index
);
433 addBookmark( pFileDbBase_DBHelp
, thishid
, fileB
, anchorB
, jarfileB
, titleB
);
438 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
;
440 anchorToLL
= streamTable
.default_keywords
;
441 if (anchorToLL
&& !anchorToLL
->empty())
443 std::string fakedHid
= URLEncoder::encode(documentPath
);
444 Hashtable::const_iterator aEnd
= anchorToLL
->end();
445 for (Hashtable::const_iterator enumer
= anchorToLL
->begin();
446 enumer
!= aEnd
; ++enumer
)
448 const std::string
&anchor
= enumer
->first
;
449 addBookmark(pFileDbBase_DBHelp
, documentPath
, fileB
,
450 anchor
, jarfileB
, titleB
);
451 std::string totalId
= fakedHid
+ "#" + anchor
;
452 // std::cerr << hzipFileName << std::endl;
453 const LinkedList
& ll
= enumer
->second
;
454 LinkedList::const_iterator aOtherEnd
= ll
.end();
455 for (LinkedList::const_iterator llIter
= ll
.begin();
456 llIter
!= aOtherEnd
; ++llIter
)
458 helpKeyword
.insert(*llIter
, totalId
);
464 // and last the helptexts
465 const Stringtable
*helpTextHash
= streamTable
.appl_helptexts
;
467 helpTextHash
= streamTable
.default_helptexts
;
468 if (helpTextHash
&& !helpTextHash
->empty())
470 Stringtable::const_iterator aEnd
= helpTextHash
->end();
471 for (Stringtable::const_iterator helpTextIter
= helpTextHash
->begin();
472 helpTextIter
!= aEnd
; ++helpTextIter
)
474 std::string helpTextId
= helpTextIter
->first
;
475 const std::string
& helpTextText
= helpTextIter
->second
;
477 helpTextId
= URLEncoder::encode(helpTextId
);
479 if( pFileHelpText_DBHelp
!= nullptr )
480 writeKeyValue_DBHelp( pFileHelpText_DBHelp
, helpTextId
, helpTextText
);
484 //IndexerPreProcessor
485 if( !bExtensionMode
|| bIndexForExtension
)
488 xmlDocPtr document
= streamTable
.appl_doc
;
490 document
= streamTable
.default_doc
;
493 std::string temp
= module
;
494 std::transform (temp
.begin(), temp
.end(), temp
.begin(), tocharlower
);
495 m_pIndexerPreProcessor
->processDocument(document
, URLEncoder::encode(documentPath
) );
502 catch( const HelpProcessingException
& )
504 // catch HelpProcessingException to avoid locking data bases
505 if( pFileHelpText_DBHelp
!= nullptr )
506 fclose( pFileHelpText_DBHelp
);
507 if( pFileDbBase_DBHelp
!= nullptr )
508 fclose( pFileDbBase_DBHelp
);
512 if( pFileHelpText_DBHelp
!= nullptr )
513 fclose( pFileHelpText_DBHelp
);
514 if( pFileDbBase_DBHelp
!= nullptr )
515 fclose( pFileDbBase_DBHelp
);
517 helpKeyword
.dump_DBHelp( keyWordFileName_DBHelp
);
519 if( !bExtensionMode
)
522 Stringtable::iterator aEnd
= additionalFiles
.end();
523 for (Stringtable::iterator enumer
= additionalFiles
.begin(); enumer
!= aEnd
;
526 const std::string
&additionalFileName
= enumer
->second
;
527 const std::string
&additionalFileKey
= enumer
->first
;
529 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
531 std::string aNativeStr
= fsAdditionalFileName
.native_file_string();
532 const char* pStr
= aNativeStr
.c_str();
533 std::cerr
<< pStr
<< std::endl
;
536 fs::path
fsTargetName( indexDirParentName
/ additionalFileKey
);
538 fs::copy( fsAdditionalFileName
, fsTargetName
);
544 void HelpLinker::main( std::vector
<std::string
> &args
,
545 std::string
* pExtensionPath
, std::string
* pDestination
,
546 const OUString
* pOfficeHelpPath
)
547 throw( HelpProcessingException
, std::exception
)
549 bExtensionMode
= false;
552 if ((!args
.empty()) && args
[0][0] == '@')
554 std::vector
<std::string
> stringList
;
555 std::ifstream
fileReader(args
[0].substr(1).c_str());
562 stringList
.push_back(token
);
570 bool bSrcOption
= false;
571 while (i
< args
.size())
573 if (args
[i
].compare("-extlangsrc") == 0)
576 if (i
>= args
.size())
578 std::stringstream aStrStream
;
579 aStrStream
<< "extension source missing" << std::endl
;
580 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
584 else if (args
[i
].compare("-extlangdest") == 0)
586 //If this argument is not provided then the location provided in -extsource will
587 //also be the destination
589 if (i
>= args
.size())
591 std::stringstream aStrStream
;
592 aStrStream
<< "extension destination missing" << std::endl
;
593 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
595 extdestination
= args
[i
];
597 else if (args
[i
].compare("-src") == 0)
600 if (i
>= args
.size())
602 std::stringstream aStrStream
;
603 aStrStream
<< "sourceroot missing" << std::endl
;
604 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
607 sourceRoot
= fs::path(args
[i
], fs::native
);
609 else if (args
[i
].compare("-compact") == 0)
612 if (i
>= args
.size())
614 std::stringstream aStrStream
;
615 aStrStream
<< "compactStylesheet missing" << std::endl
;
616 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
619 compactStylesheet
= fs::path(args
[i
], fs::native
);
621 else if (args
[i
].compare("-sty") == 0)
624 if (i
>= args
.size())
626 std::stringstream aStrStream
;
627 aStrStream
<< "embeddingStylesheet missing" << std::endl
;
628 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
631 embeddStylesheet
= fs::path(args
[i
], fs::native
);
633 else if (args
[i
].compare("-zipdir") == 0)
636 if (i
>= args
.size())
638 std::stringstream aStrStream
;
639 aStrStream
<< "idxtemp missing" << std::endl
;
640 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
643 zipdir
= fs::path(args
[i
], fs::native
);
645 else if (args
[i
].compare("-idxcaption") == 0)
648 if (i
>= args
.size())
650 std::stringstream aStrStream
;
651 aStrStream
<< "idxcaption stylesheet missing" << std::endl
;
652 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
655 idxCaptionStylesheet
= fs::path(args
[i
], fs::native
);
657 else if (args
[i
].compare("-idxcontent") == 0)
660 if (i
>= args
.size())
662 std::stringstream aStrStream
;
663 aStrStream
<< "idxcontent stylesheet missing" << std::endl
;
664 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
667 idxContentStylesheet
= fs::path(args
[i
], fs::native
);
669 else if (args
[i
].compare("-o") == 0)
672 if (i
>= args
.size())
674 std::stringstream aStrStream
;
675 aStrStream
<< "outputfilename missing" << std::endl
;
676 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
679 outputFile
= fs::path(args
[i
], fs::native
);
681 else if (args
[i
].compare("-mod") == 0)
684 if (i
>= args
.size())
686 std::stringstream aStrStream
;
687 aStrStream
<< "module name missing" << std::endl
;
688 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
693 else if (args
[i
].compare("-lang") == 0)
696 if (i
>= args
.size())
698 std::stringstream aStrStream
;
699 aStrStream
<< "language name missing" << std::endl
;
700 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
705 else if (args
[i
].compare("-hid") == 0)
708 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, "obsolete -hid argument used" );
710 else if (args
[i
].compare("-add") == 0)
712 std::string addFile
, addFileUnderPath
;
714 if (i
>= args
.size())
716 std::stringstream aStrStream
;
717 aStrStream
<< "pathname missing" << std::endl
;
718 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
721 addFileUnderPath
= args
[i
];
723 if (i
>= args
.size())
725 std::stringstream aStrStream
;
726 aStrStream
<< "pathname missing" << std::endl
;
727 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
730 if (!addFileUnderPath
.empty() && !addFile
.empty())
731 additionalFiles
[addFileUnderPath
] = addFile
;
733 else if (args
[i
].compare("-nolangroot") == 0)
734 m_bUseLangRoot
= false;
735 else if (args
[i
].compare("-noindex") == 0)
736 m_bCreateIndex
= false;
738 helpFiles
.push_back(args
[i
]);
742 //We can be called from the helplinker executable or the extension manager
743 //In the latter case extsource is not used.
744 if( (pExtensionPath
&& pExtensionPath
->length() > 0 && pOfficeHelpPath
)
745 || !extsource
.empty())
747 bExtensionMode
= true;
748 if (!extsource
.empty())
750 //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
752 sourceRoot
= fs::path(extsource
, fs::native
);
753 extensionPath
= sourceRoot
.toUTF8();
755 if (extdestination
.empty())
757 std::stringstream aStrStream
;
758 aStrStream
<< "-extlangdest is missing" << std::endl
;
759 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
763 //Convert from system path to file URL!!!
764 fs::path
p(extdestination
, fs::native
);
765 extensionDestination
= p
.toUTF8();
769 { //called from extension manager
770 extensionPath
= *pExtensionPath
;
771 sourceRoot
= fs::path(extensionPath
);
772 extensionDestination
= *pDestination
;
774 //check if -src option was used. This option must not be used
775 //when extension help is compiled.
778 std::stringstream aStrStream
;
779 aStrStream
<< "-src must not be used together with -extsource missing" << std::endl
;
780 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
784 if (!bExtensionMode
&& zipdir
.empty())
786 std::stringstream aStrStream
;
787 aStrStream
<< "no index dir given" << std::endl
;
788 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
791 if ( (!bExtensionMode
&& idxCaptionStylesheet
.empty())
792 || (!extsource
.empty() && idxCaptionStylesheet
.empty()) )
794 //No extension mode and extension mode using commandline
795 //!extsource.empty indicates extension mode using commandline
796 // -idxcaption parameter is required
797 std::stringstream aStrStream
;
798 aStrStream
<< "no index caption stylesheet given" << std::endl
;
799 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
801 else if ( bExtensionMode
&& extsource
.empty())
803 //This part is used when compileExtensionHelp is called from the extensions manager.
804 //If extension help is compiled using helplinker in the build process
805 OUString
aIdxCaptionPathFileURL( *pOfficeHelpPath
);
806 aIdxCaptionPathFileURL
+= "/idxcaption.xsl";
808 OString
aOStr_IdxCaptionPathFileURL( OUStringToOString
809 ( aIdxCaptionPathFileURL
, fs::getThreadTextEncoding() ) );
810 std::string
aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL
.getStr() );
812 idxCaptionStylesheet
= fs::path( aStdStr_IdxCaptionPathFileURL
);
815 if ( (!bExtensionMode
&& idxContentStylesheet
.empty())
816 || (!extsource
.empty() && idxContentStylesheet
.empty()) )
818 //No extension mode and extension mode using commandline
819 //!extsource.empty indicates extension mode using commandline
820 // -idxcontent parameter is required
821 std::stringstream aStrStream
;
822 aStrStream
<< "no index content stylesheet given" << std::endl
;
823 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
825 else if ( bExtensionMode
&& extsource
.empty())
827 //If extension help is compiled using helplinker in the build process
828 //then -idxcontent must be supplied
829 //This part is used when compileExtensionHelp is called from the extensions manager.
830 OUString
aIdxContentPathFileURL( *pOfficeHelpPath
);
831 aIdxContentPathFileURL
+= "/idxcontent.xsl";
833 OString
aOStr_IdxContentPathFileURL( OUStringToOString
834 ( aIdxContentPathFileURL
, fs::getThreadTextEncoding() ) );
835 std::string
aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL
.getStr() );
837 idxContentStylesheet
= fs::path( aStdStr_IdxContentPathFileURL
);
839 if (!bExtensionMode
&& embeddStylesheet
.empty())
841 std::stringstream aStrStream
;
842 aStrStream
<< "no embedding resolving file given" << std::endl
;
843 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
845 if (sourceRoot
.empty())
847 std::stringstream aStrStream
;
848 aStrStream
<< "no sourceroot given" << std::endl
;
849 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
851 if (!bExtensionMode
&& outputFile
.empty())
853 std::stringstream aStrStream
;
854 aStrStream
<< "no output file given" << std::endl
;
855 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
859 std::stringstream aStrStream
;
860 aStrStream
<< "module missing" << std::endl
;
861 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
863 if (!bExtensionMode
&& lang
.empty())
865 std::stringstream aStrStream
;
866 aStrStream
<< "language missing" << std::endl
;
867 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
872 // Variable to set an exception in "C" StructuredXMLErrorFunction
873 static const HelpProcessingException
* GpXMLParsingException
= nullptr;
875 extern "C" void StructuredXMLErrorFunction(void *userData
, xmlErrorPtr error
)
880 std::string aErrorMsg
= error
->message
;
881 std::string aXMLParsingFile
;
882 if( error
->file
!= nullptr )
883 aXMLParsingFile
= error
->file
;
884 int nXMLParsingLine
= error
->line
;
885 HelpProcessingException
* pException
= new HelpProcessingException( aErrorMsg
, aXMLParsingFile
, nXMLParsingLine
);
886 GpXMLParsingException
= pException
;
888 // Reset error handler
889 xmlSetStructuredErrorFunc( nullptr, nullptr );
892 HelpProcessingErrorInfo
& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException
& e
)
894 m_eErrorClass
= e
.m_eErrorClass
;
895 OString
tmpErrorMsg( e
.m_aErrorMsg
.c_str() );
896 m_aErrorMsg
= OStringToOUString( tmpErrorMsg
, fs::getThreadTextEncoding() );
897 OString
tmpXMLParsingFile( e
.m_aXMLParsingFile
.c_str() );
898 m_aXMLParsingFile
= OStringToOUString( tmpXMLParsingFile
, fs::getThreadTextEncoding() );
899 m_nXMLParsingLine
= e
.m_nXMLParsingLine
;
904 // Returns true in case of success, false in case of error
905 bool compileExtensionHelp
907 const OUString
& aOfficeHelpPath
,
908 const OUString
& aExtensionName
,
909 const OUString
& aExtensionLanguageRoot
,
910 sal_Int32 nXhpFileCount
, const OUString
* pXhpFiles
,
911 const OUString
& aDestination
,
912 HelpProcessingErrorInfo
& o_rHelpProcessingErrorInfo
915 bool bSuccess
= true;
917 std::vector
<std::string
> args
;
918 args
.reserve(nXhpFileCount
+ 2);
919 args
.push_back(std::string("-mod"));
920 OString aOExtensionName
= OUStringToOString( aExtensionName
, fs::getThreadTextEncoding() );
921 args
.push_back(std::string(aOExtensionName
.getStr()));
923 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
925 OUString aXhpFile
= pXhpFiles
[iXhp
];
927 OString aOXhpFile
= OUStringToOString( aXhpFile
, fs::getThreadTextEncoding() );
928 args
.push_back(std::string(aOXhpFile
.getStr()));
931 OString aOExtensionLanguageRoot
= OUStringToOString( aExtensionLanguageRoot
, fs::getThreadTextEncoding() );
932 const char* pExtensionPath
= aOExtensionLanguageRoot
.getStr();
933 std::string aStdStrExtensionPath
= pExtensionPath
;
934 OString aODestination
= OUStringToOString(aDestination
, fs::getThreadTextEncoding());
935 const char* pDestination
= aODestination
.getStr();
936 std::string aStdStrDestination
= pDestination
;
939 xmlSetStructuredErrorFunc( nullptr, StructuredXMLErrorFunction
);
942 std::unique_ptr
<HelpLinker
> pHelpLinker(new HelpLinker());
943 pHelpLinker
->main( args
, &aStdStrExtensionPath
, &aStdStrDestination
, &aOfficeHelpPath
);
945 catch( const HelpProcessingException
& e
)
947 if( GpXMLParsingException
!= nullptr )
949 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
950 delete GpXMLParsingException
;
951 GpXMLParsingException
= nullptr;
955 o_rHelpProcessingErrorInfo
= e
;
959 // Reset error handler
960 xmlSetStructuredErrorFunc( nullptr, nullptr );
962 // i83624: Tree files
963 // The following basically checks if the help.tree is well formed XML.
964 // Apparently there have been cases when translations contained
965 // non-well-formed XML in the past.
966 OUString aTreeFileURL
= aExtensionLanguageRoot
+ "/help.tree";
967 osl::DirectoryItem aTreeFileItem
;
968 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
969 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileSize
);
970 if( rcGet
== osl::FileBase::E_None
&&
971 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
972 aFileStatus
.isValid( osl_FileStatus_Mask_FileSize
) )
974 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
975 std::unique_ptr
<char[]> s(new char[ int(len
) ]); // the buffer to hold the installed files
976 osl::File
aFile( aTreeFileURL
);
977 aFile
.open( osl_File_OpenFlag_Read
);
978 aFile
.read( s
.get(), len
, ret
);
981 XML_Parser parser
= XML_ParserCreate( nullptr );
982 XML_Status parsed
= XML_Parse( parser
, s
.get(), int( len
), true );
984 if (XML_STATUS_ERROR
== parsed
)
986 XML_Error nError
= XML_GetErrorCode( parser
);
987 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HELPPROCESSING_XMLPARSING_ERROR
;
988 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= OUString::createFromAscii( XML_ErrorString( nError
) );
989 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
990 // CRASHES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
994 XML_ParserFree( parser
);
1000 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */