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>
40 IndexerPreProcessor::IndexerPreProcessor
41 ( const std::string
& aModuleName
, const fs::path
& fsIndexBaseDir
,
42 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
)
43 : m_aModuleName( aModuleName
)
44 , m_fsIndexBaseDir( fsIndexBaseDir
)
46 m_fsCaptionFilesDirName
= fsIndexBaseDir
/ "caption";
47 fs::create_directory( m_fsCaptionFilesDirName
);
49 m_fsContentFilesDirName
= fsIndexBaseDir
/ "content";
50 fs::create_directory( m_fsContentFilesDirName
);
52 m_xsltStylesheetPtrCaption
= xsltParseStylesheetFile
53 ((const xmlChar
*)idxCaptionStylesheet
.native_file_string().c_str());
54 m_xsltStylesheetPtrContent
= xsltParseStylesheetFile
55 ((const xmlChar
*)idxContentStylesheet
.native_file_string().c_str());
58 IndexerPreProcessor::~IndexerPreProcessor()
60 if( m_xsltStylesheetPtrCaption
)
61 xsltFreeStylesheet( m_xsltStylesheetPtrCaption
);
62 if( m_xsltStylesheetPtrContent
)
63 xsltFreeStylesheet( m_xsltStylesheetPtrContent
);
66 std::string
getEncodedPath( const std::string
& Path
)
68 OString
aOStr_Path( Path
.c_str() );
69 OUString
aOUStr_Path( OStringToOUString
70 ( aOStr_Path
, fs::getThreadTextEncoding() ) );
72 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
73 OString
aOStr_PathURL( OUStringToOString
74 ( aPathURL
, fs::getThreadTextEncoding() ) );
75 std::string
aStdStr_PathURL( aOStr_PathURL
.getStr() );
76 return aStdStr_PathURL
;
79 void IndexerPreProcessor::processDocument
80 ( xmlDocPtr doc
, const std::string
&EncodedDocPath
)
82 std::string aStdStr_EncodedDocPathURL
= getEncodedPath( EncodedDocPath
);
84 if( m_xsltStylesheetPtrCaption
)
86 xmlDocPtr resCaption
= xsltApplyStylesheet( m_xsltStylesheetPtrCaption
, doc
, NULL
);
87 xmlNodePtr pResNodeCaption
= resCaption
->xmlChildrenNode
;
90 fs::path fsCaptionPureTextFile_docURL
= m_fsCaptionFilesDirName
/ aStdStr_EncodedDocPathURL
;
91 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
92 FILE* pFile_docURL
= _wfopen(
93 fsCaptionPureTextFile_docURL
.native_file_string_w(), L
"w" );
95 FILE* pFile_docURL
= fopen(
96 fsCaptionPureTextFile_docURL
.native_file_string().c_str(), "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
, NULL
);
110 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
111 if( pResNodeContent
)
113 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
114 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
115 FILE* pFile_docURL
= _wfopen(
116 fsContentPureTextFile_docURL
.native_file_string_w(), L
"w" );
118 FILE* pFile_docURL
= fopen(
119 fsContentPureTextFile_docURL
.native_file_string().c_str(), "w" );
123 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
124 fclose( pFile_docURL
);
127 xmlFreeDoc(resContent
);
133 std::vector
<std::string
> _idList
;
134 typedef std::vector
<std::string
>::const_iterator cIter
;
136 void append(const std::string
&id
)
138 _idList
.push_back(id
);
141 std::string
getString() const
144 cIter aEnd
= _idList
.end();
145 for (cIter aIter
= _idList
.begin(); aIter
!= aEnd
; ++aIter
)
151 void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
156 unsigned int nKeyLen
= aKeyStr
.length();
157 unsigned int nValueLen
= aValueStr
.length();
158 fprintf( pFile
, "%x ", nKeyLen
);
161 if (fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
) != nKeyLen
)
162 fprintf(stderr
, "fwrite to db failed\n");
164 if (fprintf( pFile
, " %x ", nValueLen
) < 0)
165 fprintf(stderr
, "fwrite to db failed\n");
168 if (fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
) != nValueLen
)
169 fprintf(stderr
, "fwrite to db failed\n");
171 if (fprintf( pFile
, "%c", cLF
) < 0)
172 fprintf(stderr
, "fwrite to db failed\n");
178 typedef boost::unordered_map
<std::string
, Data
, pref_hash
> DataHashtable
;
182 void insert(const std::string
&key
, const std::string
&id
)
184 Data
&data
= _hash
[key
];
188 void dump_DBHelp( const fs::path
& rFileName
)
190 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
191 FILE* pFile
= _wfopen( rFileName
.native_file_string_w(), L
"wb" );
193 FILE* pFile
= fopen( rFileName
.native_file_string().c_str(), "wb" );
198 DataHashtable::const_iterator aEnd
= _hash
.end();
199 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
200 writeKeyValue_DBHelp( pFile
, aIter
->first
, aIter
->second
.getString() );
208 static std::string
encode(const std::string
&rIn
)
210 const char *good
= "!$&'()*+,-.=@_";
211 static const char hex
[17] = "0123456789ABCDEF";
214 for (size_t i
=0; i
< rIn
.length(); ++i
)
216 unsigned char c
= rIn
[i
];
217 if (isalnum (c
) || strchr (good
, c
))
221 result
+= hex
[c
>> 4];
222 result
+= hex
[c
& 0xf];
229 void HelpLinker::addBookmark( FILE* pFile_DBHelp
, std::string thishid
,
230 const std::string
& fileB
, const std::string
& anchorB
,
231 const std::string
& jarfileB
, const std::string
& titleB
)
233 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
234 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
236 thishid
= URLEncoder::encode(thishid
);
238 int fileLen
= fileB
.length();
239 if (!anchorB
.empty())
240 fileLen
+= (1 + anchorB
.length());
241 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
243 std::vector
<unsigned char> dataB(dataLen
);
245 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
246 for (size_t j
= 0; j
< fileB
.length(); ++j
)
247 dataB
[i
++] = static_cast<unsigned char>(fileB
[j
]);
248 if (!anchorB
.empty())
251 for (size_t j
= 0; j
< anchorB
.length(); ++j
)
252 dataB
[i
++] = anchorB
[j
];
254 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
255 for (size_t j
= 0; j
< jarfileB
.length(); ++j
)
256 dataB
[i
++] = jarfileB
[j
];
258 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
259 for (size_t j
= 0; j
< titleB
.length(); ++j
)
260 dataB
[i
++] = titleB
[j
];
262 if( pFile_DBHelp
!= NULL
)
264 std::string
aValueStr( dataB
.begin(), dataB
.end() );
265 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
269 void HelpLinker::initIndexerPreProcessor()
271 if( m_pIndexerPreProcessor
)
272 delete m_pIndexerPreProcessor
;
273 std::string mod
= module
;
274 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
275 m_pIndexerPreProcessor
= new IndexerPreProcessor( mod
, indexDirParentName
,
276 idxCaptionStylesheet
, idxContentStylesheet
);
282 void HelpLinker::link() throw( HelpProcessingException
)
284 bool bIndexForExtension
= true;
288 indexDirParentName
= extensionDestination
;
292 indexDirParentName
= zipdir
;
293 fs::create_directory(indexDirParentName
);
296 std::string mod
= module
;
297 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
300 // continue with introduction of the overall process thing into the
301 // here all hzip files will be worked on
302 std::string appl
= mod
;
304 appl
= appl
.substr(1);
307 if( !bExtensionMode
)
310 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
312 //We need _wfopen to support long file paths on Windows XP
313 FILE* pFileHelpText_DBHelp
= _wfopen
314 ( helpTextFileName_DBHelp
.native_file_string_w(), L
"wb" );
317 FILE* pFileHelpText_DBHelp
= fopen
318 ( helpTextFileName_DBHelp
.native_file_string().c_str(), "wb" );
321 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
323 //We need _wfopen to support long file paths on Windows XP
324 FILE* pFileDbBase_DBHelp
= _wfopen
325 ( dbBaseFileName_DBHelp
.native_file_string_w(), L
"wb" );
327 FILE* pFileDbBase_DBHelp
= fopen
328 ( dbBaseFileName_DBHelp
.native_file_string().c_str(), "wb" );
331 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
333 HelpKeyword helpKeyword
;
335 // catch HelpProcessingException to avoid locking data bases
339 // lastly, initialize the indexBuilder
340 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
341 initIndexerPreProcessor();
343 // here we start our loop over the hzip files.
344 HashSet::iterator end
= helpFiles
.end();
345 for (HashSet::iterator iter
= helpFiles
.begin(); iter
!= end
; ++iter
)
348 // streamTable contains the streams in the hzip file
349 StreamTable streamTable
;
350 const std::string
&xhpFileName
= *iter
;
352 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
354 // only work on .xhp - files
355 SAL_WARN("helpcompiler",
356 "ERROR: input list entry '"
358 << "' has the wrong extension (only files with extension .xhp "
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
) );
506 } // while loop over hzip files ending
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 paramter 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
+= OUString("/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 paramter 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
+= OUString("/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 HELPLINKER_DLLPUBLIC
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 HelpLinker
* pHelpLinker
= new HelpLinker();
950 pHelpLinker
->main( args
, &aStdStrExtensionPath
, &aStdStrDestination
, &aOfficeHelpPath
);
953 catch( const HelpProcessingException
& e
)
955 if( GpXMLParsingException
!= NULL
)
957 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
958 delete GpXMLParsingException
;
959 GpXMLParsingException
= NULL
;
963 o_rHelpProcessingErrorInfo
= e
;
967 // Reset error handler
968 xmlSetStructuredErrorFunc( NULL
, NULL
);
970 // i83624: Tree files
971 // The following basically checks if the help.tree is well formed XML.
972 // Apparently there have been cases when translations contained
973 // non-well-formed XML in the past.
974 OUString aTreeFileURL
= aExtensionLanguageRoot
;
975 aTreeFileURL
+= OUString("/help.tree");
976 osl::DirectoryItem aTreeFileItem
;
977 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
978 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileSize
);
979 if( rcGet
== osl::FileBase::E_None
&&
980 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
981 aFileStatus
.isValid( osl_FileStatus_Mask_FileSize
) )
983 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
984 char* s
= new char[ int(len
) ]; // the buffer to hold the installed files
985 osl::File
aFile( aTreeFileURL
);
986 aFile
.open( osl_File_OpenFlag_Read
);
987 aFile
.read( s
, len
, ret
);
990 XML_Parser parser
= XML_ParserCreate( 0 );
991 XML_Status parsed
= XML_Parse( parser
, s
, int( len
), true );
993 if (XML_STATUS_ERROR
== parsed
)
995 XML_Error nError
= XML_GetErrorCode( parser
);
996 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HELPPROCESSING_XMLPARSING_ERROR
;
997 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= OUString::createFromAscii( XML_ErrorString( nError
) );;
998 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
999 // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
1003 XML_ParserFree( parser
);
1010 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */