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>
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() ) );
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
;
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" );
97 FILE* pFile_docURL
= fopen(
98 fsCaptionPureTextFile_docURL
.native_file_string().c_str(), "w" );
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" );
120 FILE* pFile_docURL
= fopen(
121 fsContentPureTextFile_docURL
.native_file_string().c_str(), "w" );
125 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
126 fclose( pFile_docURL
);
129 xmlFreeDoc(resContent
);
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
146 cIter aEnd
= _idList
.end();
147 for (cIter aIter
= _idList
.begin(); aIter
!= aEnd
; ++aIter
)
153 void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
158 unsigned int nKeyLen
= aKeyStr
.length();
159 unsigned int nValueLen
= aValueStr
.length();
160 fprintf( pFile
, "%x ", nKeyLen
);
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");
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");
180 typedef std::unordered_map
<std::string
, Data
, pref_hash
> DataHashtable
;
184 void insert(const std::string
&key
, const std::string
&id
)
186 Data
&data
= _hash
[key
];
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" );
195 FILE* pFile
= fopen( rFileName
.native_file_string().c_str(), "wb" );
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() );
210 static std::string
encode(const std::string
&rIn
)
212 const char *good
= "!$&'()*+,-.=@_";
213 static const char hex
[17] = "0123456789ABCDEF";
216 for (size_t i
=0; i
< rIn
.length(); ++i
)
218 unsigned char c
= rIn
[i
];
219 if (isalnum (c
) || strchr (good
, c
))
223 result
+= hex
[c
>> 4];
224 result
+= hex
[c
& 0xf];
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
);
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())
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
)
289 indexDirParentName
= extensionDestination
;
293 indexDirParentName
= zipdir
;
294 fs::create_directory(indexDirParentName
);
297 std::string mod
= module
;
298 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
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
;
305 appl
= appl
.substr(1);
308 if( !bExtensionMode
)
311 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
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" );
318 FILE* pFileHelpText_DBHelp
= fopen
319 ( helpTextFileName_DBHelp
.native_file_string().c_str(), "wb" );
322 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
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" );
328 FILE* pFileDbBase_DBHelp
= fopen
329 ( dbBaseFileName_DBHelp
.native_file_string().c_str(), "wb" );
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
)
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 '"
359 << "' has the wrong extension (only files with extension .xhp are accepted)");
364 fs::path
langsourceRoot(sourceRoot
);
369 // langsourceRoot == sourceRoot for extensions
370 std::string
xhpFileNameComplete( extensionPath
);
371 xhpFileNameComplete
.append( '/' + xhpFileName
);
372 xhpFile
= fs::path( xhpFileNameComplete
);
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
;
393 "\nERROR: compiling help particle '"
395 << "' for language '"
398 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
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
;
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
;
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
);
445 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
;
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
;
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
)
495 xmlDocPtr document
= streamTable
.appl_doc
;
497 document
= streamTable
.default_doc
;
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
);
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
)
529 Stringtable::iterator aEnd
= additionalFiles
.end();
530 for (Stringtable::iterator enumer
= additionalFiles
.begin(); enumer
!= aEnd
;
533 const std::string
&additionalFileName
= enumer
->second
;
534 const std::string
&additionalFileKey
= enumer
->first
;
536 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
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;
559 if ((!args
.empty()) && args
[0][0] == '@')
561 std::vector
<std::string
> stringList
;
562 std::ifstream
fileReader(args
[0].substr(1).c_str());
569 stringList
.push_back(token
);
577 bool bSrcOption
= false;
578 while (i
< args
.size())
580 if (args
[i
].compare("-extlangsrc") == 0)
583 if (i
>= args
.size())
585 std::stringstream aStrStream
;
586 aStrStream
<< "extension source missing" << std::endl
;
587 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
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
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)
607 if (i
>= args
.size())
609 std::stringstream aStrStream
;
610 aStrStream
<< "sourceroot missing" << std::endl
;
611 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
614 sourceRoot
= fs::path(args
[i
], fs::native
);
616 else if (args
[i
].compare("-compact") == 0)
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)
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)
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)
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)
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)
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)
691 if (i
>= args
.size())
693 std::stringstream aStrStream
;
694 aStrStream
<< "module name missing" << std::endl
;
695 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
700 else if (args
[i
].compare("-lang") == 0)
703 if (i
>= args
.size())
705 std::stringstream aStrStream
;
706 aStrStream
<< "language name missing" << std::endl
;
707 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
712 else if (args
[i
].compare("-hid") == 0)
715 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, "obsolete -hid argument used" );
717 else if (args
[i
].compare("-add") == 0)
719 std::string addFile
, addFileUnderPath
;
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
];
730 if (i
>= args
.size())
732 std::stringstream aStrStream
;
733 aStrStream
<< "pathname missing" << std::endl
;
734 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
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;
745 helpFiles
.push_back(args
[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
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() );
770 //Convert from system path to file URL!!!
771 fs::path
p(extdestination
, fs::native
);
772 extensionDestination
= p
.toUTF8();
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.
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() );
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() );
879 // Variable to set an exception in "C" StructuredXMLErrorFunction
880 static const HelpProcessingException
* GpXMLParsingException
= NULL
;
882 extern "C" void StructuredXMLErrorFunction(void *userData
, xmlErrorPtr 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
;
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
;
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
;
962 o_rHelpProcessingErrorInfo
= e
;
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
);
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 );
1001 XML_ParserFree( parser
);
1007 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */