1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include "HelpCompiler.hxx"
30 #include "l10ntools/HelpLinker.hxx"
37 #include <libxslt/xslt.h>
38 #include <libxslt/xsltutils.h>
39 #include <libxslt/functions.h>
40 #include <libxslt/extensions.h>
43 #include <sal/types.h>
45 #include <rtl/bootstrap.hxx>
61 IndexerPreProcessor::IndexerPreProcessor
62 ( const std::string
& aModuleName
, const fs::path
& fsIndexBaseDir
,
63 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
)
64 : m_aModuleName( aModuleName
)
65 , m_fsIndexBaseDir( fsIndexBaseDir
)
67 m_fsCaptionFilesDirName
= fsIndexBaseDir
/ "caption";
68 fs::create_directory( m_fsCaptionFilesDirName
);
70 m_fsContentFilesDirName
= fsIndexBaseDir
/ "content";
71 fs::create_directory( m_fsContentFilesDirName
);
73 m_xsltStylesheetPtrCaption
= xsltParseStylesheetFile
74 ((const xmlChar
*)idxCaptionStylesheet
.native_file_string().c_str());
75 m_xsltStylesheetPtrContent
= xsltParseStylesheetFile
76 ((const xmlChar
*)idxContentStylesheet
.native_file_string().c_str());
79 IndexerPreProcessor::~IndexerPreProcessor()
81 if( m_xsltStylesheetPtrCaption
)
82 xsltFreeStylesheet( m_xsltStylesheetPtrCaption
);
83 if( m_xsltStylesheetPtrContent
)
84 xsltFreeStylesheet( m_xsltStylesheetPtrContent
);
87 std::string
getEncodedPath( const std::string
& Path
)
89 rtl::OString
aOStr_Path( Path
.c_str() );
90 rtl::OUString
aOUStr_Path( rtl::OStringToOUString
91 ( aOStr_Path
, fs::getThreadTextEncoding() ) );
92 rtl::OUString aPathURL
;
93 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
94 rtl::OString
aOStr_PathURL( rtl::OUStringToOString
95 ( aPathURL
, fs::getThreadTextEncoding() ) );
96 std::string
aStdStr_PathURL( aOStr_PathURL
.getStr() );
97 return aStdStr_PathURL
;
100 void IndexerPreProcessor::processDocument
101 ( xmlDocPtr doc
, const std::string
&EncodedDocPath
)
103 std::string aStdStr_EncodedDocPathURL
= getEncodedPath( EncodedDocPath
);
105 if( m_xsltStylesheetPtrCaption
)
107 xmlDocPtr resCaption
= xsltApplyStylesheet( m_xsltStylesheetPtrCaption
, doc
, NULL
);
108 xmlNodePtr pResNodeCaption
= resCaption
->xmlChildrenNode
;
109 if( pResNodeCaption
)
111 fs::path fsCaptionPureTextFile_docURL
= m_fsCaptionFilesDirName
/ aStdStr_EncodedDocPathURL
;
112 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
113 FILE* pFile_docURL
= _wfopen(
114 fsCaptionPureTextFile_docURL
.native_file_string_w(), L
"w" );
116 FILE* pFile_docURL
= fopen(
117 fsCaptionPureTextFile_docURL
.native_file_string().c_str(), "w" );
121 fprintf( pFile_docURL
, "%s\n", pResNodeCaption
->content
);
122 fclose( pFile_docURL
);
125 xmlFreeDoc(resCaption
);
128 if( m_xsltStylesheetPtrContent
)
130 xmlDocPtr resContent
= xsltApplyStylesheet( m_xsltStylesheetPtrContent
, doc
, NULL
);
131 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
132 if( pResNodeContent
)
134 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
135 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
136 FILE* pFile_docURL
= _wfopen(
137 fsContentPureTextFile_docURL
.native_file_string_w(), L
"w" );
139 FILE* pFile_docURL
= fopen(
140 fsContentPureTextFile_docURL
.native_file_string().c_str(), "w" );
144 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
145 fclose( pFile_docURL
);
148 xmlFreeDoc(resContent
);
154 std::vector
<std::string
> _idList
;
155 typedef std::vector
<std::string
>::const_iterator cIter
;
157 void append(const std::string
&id
)
159 _idList
.push_back(id
);
162 std::string
getString() const
165 cIter aEnd
= _idList
.end();
166 for (cIter aIter
= _idList
.begin(); aIter
!= aEnd
; ++aIter
)
172 void writeKeyValue_DBHelp( FILE* pFile
, const std::string
& aKeyStr
, const std::string
& aValueStr
)
177 unsigned int nKeyLen
= aKeyStr
.length();
178 unsigned int nValueLen
= aValueStr
.length();
179 fprintf( pFile
, "%x ", nKeyLen
);
182 if (fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
) != nKeyLen
)
183 fprintf(stderr
, "fwrite to db failed\n");
185 if (fprintf( pFile
, " %x ", nValueLen
) < 0)
186 fprintf(stderr
, "fwrite to db failed\n");
189 if (fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
) != nValueLen
)
190 fprintf(stderr
, "fwrite to db failed\n");
192 if (fprintf( pFile
, "%c", cLF
) < 0)
193 fprintf(stderr
, "fwrite to db failed\n");
199 typedef boost::unordered_map
<std::string
, Data
, pref_hash
> DataHashtable
;
203 void insert(const std::string
&key
, const std::string
&id
)
205 Data
&data
= _hash
[key
];
211 DataHashtable::const_iterator aEnd
= _hash
.end();
212 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
214 const std::string
&keystr
= aIter
->first
;
216 memset(&key
, 0, sizeof(key
));
217 key
.data
= const_cast<char*>(keystr
.c_str());
218 key
.size
= keystr
.length();
220 const Data
&data
= aIter
->second
;
221 std::string str
= data
.getString();
223 memset(&value
, 0, sizeof(value
));
224 value
.data
= const_cast<char*>(str
.c_str());
225 value
.size
= str
.length();
227 table
->put(table
, NULL
, &key
, &value
, 0);
231 void dump_DBHelp( const fs::path
& rFileName
)
233 #ifdef WNT //We need _wfopen to support long file paths on Windows XP
234 FILE* pFile
= _wfopen( rFileName
.native_file_string_w(), L
"wb" );
236 FILE* pFile
= fopen( rFileName
.native_file_string().c_str(), "wb" );
241 DataHashtable::const_iterator aEnd
= _hash
.end();
242 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
243 writeKeyValue_DBHelp( pFile
, aIter
->first
, aIter
->second
.getString() );
251 static std::string
encode(const std::string
&rIn
)
253 const char *good
= "!$&'()*+,-.=@_";
254 static const char hex
[17] = "0123456789ABCDEF";
257 for (size_t i
=0; i
< rIn
.length(); ++i
)
259 unsigned char c
= rIn
[i
];
260 if (isalnum (c
) || strchr (good
, c
))
264 result
+= hex
[c
>> 4];
265 result
+= hex
[c
& 0xf];
272 void HelpLinker::addBookmark( DB
* dbBase
, FILE* pFile_DBHelp
, std::string thishid
,
273 const std::string
& fileB
, const std::string
& anchorB
,
274 const std::string
& jarfileB
, const std::string
& titleB
)
276 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
277 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
279 thishid
= URLEncoder::encode(thishid
);
282 memset(&key
, 0, sizeof(key
));
283 key
.data
= const_cast<char*>(thishid
.c_str());
284 key
.size
= thishid
.length();
286 int fileLen
= fileB
.length();
287 if (!anchorB
.empty())
288 fileLen
+= (1 + anchorB
.length());
289 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
291 std::vector
<unsigned char> dataB(dataLen
);
293 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
294 for (size_t j
= 0; j
< fileB
.length(); ++j
)
295 dataB
[i
++] = static_cast<unsigned char>(fileB
[j
]);
296 if (!anchorB
.empty())
299 for (size_t j
= 0; j
< anchorB
.length(); ++j
)
300 dataB
[i
++] = anchorB
[j
];
302 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
303 for (size_t j
= 0; j
< jarfileB
.length(); ++j
)
304 dataB
[i
++] = jarfileB
[j
];
306 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
307 for (size_t j
= 0; j
< titleB
.length(); ++j
)
308 dataB
[i
++] = titleB
[j
];
311 memset(&data
, 0, sizeof(data
));
312 data
.data
= &dataB
[0];
313 data
.size
= dataB
.size();
316 dbBase
->put(dbBase
, NULL
, &key
, &data
, 0);
318 if( pFile_DBHelp
!= NULL
)
320 std::string
aValueStr( dataB
.begin(), dataB
.end() );
321 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
325 void HelpLinker::initIndexerPreProcessor()
327 if( m_pIndexerPreProcessor
)
328 delete m_pIndexerPreProcessor
;
329 std::string mod
= module
;
330 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
331 m_pIndexerPreProcessor
= new IndexerPreProcessor( mod
, indexDirParentName
,
332 idxCaptionStylesheet
, idxContentStylesheet
);
338 void HelpLinker::link() throw( HelpProcessingException
)
340 bool bIndexForExtension
= true;
344 indexDirParentName
= extensionDestination
;
348 indexDirParentName
= zipdir
;
349 fs::create_directory(indexDirParentName
);
353 std::cerr
<< "will not delete tmpdir of " << indexDirParentName
.native_file_string().c_str() << std::endl
;
356 std::string mod
= module
;
357 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tocharlower
);
360 // continue with introduction of the overall process thing into the
361 // here all hzip files will be worked on
362 std::string appl
= mod
;
364 appl
= appl
.substr(1);
368 if( !bExtensionMode
)
374 fs::path
helpTextFileName(indexDirParentName
/ (mod
+ ".ht"));
375 db_create(&helpText
,0,0);
376 helpText
->open(helpText
, NULL
, helpTextFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
377 DB_CREATE
| DB_TRUNCATE
, 0644);
380 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
382 //We need _wfopen to support long file paths on Windows XP
383 FILE* pFileHelpText_DBHelp
= _wfopen
384 ( helpTextFileName_DBHelp
.native_file_string_w(), L
"wb" );
387 FILE* pFileHelpText_DBHelp
= fopen
388 ( helpTextFileName_DBHelp
.native_file_string().c_str(), "wb" );
392 fs::path
dbBaseFileName(indexDirParentName
/ (mod
+ ".db"));
393 db_create(&dbBase
,0,0);
394 dbBase
->open(dbBase
, NULL
, dbBaseFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
395 DB_CREATE
| DB_TRUNCATE
, 0644);
398 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
400 //We need _wfopen to support long file paths on Windows XP
401 FILE* pFileDbBase_DBHelp
= _wfopen
402 ( dbBaseFileName_DBHelp
.native_file_string_w(), L
"wb" );
404 FILE* pFileDbBase_DBHelp
= fopen
405 ( dbBaseFileName_DBHelp
.native_file_string().c_str(), "wb" );
410 fs::path
keyWordFileName(indexDirParentName
/ (mod
+ ".key"));
411 db_create(&keyWord
,0,0);
412 keyWord
->open(keyWord
, NULL
, keyWordFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
413 DB_CREATE
| DB_TRUNCATE
, 0644);
416 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
418 HelpKeyword helpKeyword
;
420 // catch HelpProcessingException to avoid locking data bases
424 // lastly, initialize the indexBuilder
425 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
426 initIndexerPreProcessor();
428 // here we start our loop over the hzip files.
429 HashSet::iterator end
= helpFiles
.end();
430 for (HashSet::iterator iter
= helpFiles
.begin(); iter
!= end
; ++iter
)
433 // streamTable contains the streams in the hzip file
434 StreamTable streamTable
;
435 const std::string
&xhpFileName
= *iter
;
437 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
439 // only work on .xhp - files
440 SAL_WARN("l10ntools",
441 "ERROR: input list entry '"
443 << "' has the wrong extension (only files with extension .xhp "
449 fs::path
langsourceRoot(sourceRoot
);
454 // langsourceRoot == sourceRoot for extensions
455 std::string
xhpFileNameComplete( extensionPath
);
456 xhpFileNameComplete
.append( '/' + xhpFileName
);
457 xhpFile
= fs::path( xhpFileNameComplete
);
461 langsourceRoot
.append('/' + lang
+ '/');
462 xhpFile
= fs::path(xhpFileName
, fs::native
);
465 HelpCompiler
hc( streamTable
, xhpFile
, langsourceRoot
,
466 embeddStylesheet
, module
, lang
, bExtensionMode
);
468 HCDBG(std::cerr
<< "before compile of " << xhpFileName
<< std::endl
);
469 bool success
= hc
.compile();
470 HCDBG(std::cerr
<< "after compile of " << xhpFileName
<< std::endl
);
472 if (!success
&& !bExtensionMode
)
474 std::stringstream aStrStream
;
476 "\nERROR: compiling help particle '"
478 << "' for language '"
481 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
484 std::string documentPath
= streamTable
.document_path
;
485 if (documentPath
.find("/") == 0)
486 documentPath
= documentPath
.substr(1);
488 std::string documentJarfile
= streamTable
.document_module
+ ".jar";
490 std::string documentTitle
= streamTable
.document_title
;
491 if (documentTitle
.empty())
492 documentTitle
= "<notitle>";
494 const std::string
& fileB
= documentPath
;
495 const std::string
& jarfileB
= documentJarfile
;
496 std::string
& titleB
= documentTitle
;
498 // add once this as its own id.
499 addBookmark(dbBase
, pFileDbBase_DBHelp
, documentPath
, fileB
, std::string(), jarfileB
, titleB
);
501 // first the database *.db
502 // ByteArrayInputStream bais = null;
503 // ObjectInputStream ois = null;
505 const HashSet
*hidlist
= streamTable
.appl_hidlist
;
507 hidlist
= streamTable
.default_hidlist
;
508 if (hidlist
&& !hidlist
->empty())
510 // now iterate over all elements of the hidlist
511 HashSet::const_iterator aEnd
= hidlist
->end();
512 for (HashSet::const_iterator hidListIter
= hidlist
->begin();
513 hidListIter
!= aEnd
; ++hidListIter
)
515 std::string thishid
= *hidListIter
;
518 size_t index
= thishid
.rfind('#');
519 if (index
!= std::string::npos
)
521 anchorB
= thishid
.substr(1 + index
);
522 thishid
= thishid
.substr(0, index
);
524 addBookmark(dbBase
, pFileDbBase_DBHelp
, thishid
, fileB
, anchorB
, jarfileB
, titleB
);
529 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
;
531 anchorToLL
= streamTable
.default_keywords
;
532 if (anchorToLL
&& !anchorToLL
->empty())
534 std::string fakedHid
= URLEncoder::encode(documentPath
);
535 Hashtable::const_iterator aEnd
= anchorToLL
->end();
536 for (Hashtable::const_iterator enumer
= anchorToLL
->begin();
537 enumer
!= aEnd
; ++enumer
)
539 const std::string
&anchor
= enumer
->first
;
540 addBookmark(dbBase
, pFileDbBase_DBHelp
, documentPath
, fileB
,
541 anchor
, jarfileB
, titleB
);
542 std::string totalId
= fakedHid
+ "#" + anchor
;
543 // std::cerr << hzipFileName << std::endl;
544 const LinkedList
& ll
= enumer
->second
;
545 LinkedList::const_iterator aOtherEnd
= ll
.end();
546 for (LinkedList::const_iterator llIter
= ll
.begin();
547 llIter
!= aOtherEnd
; ++llIter
)
549 helpKeyword
.insert(*llIter
, totalId
);
555 // and last the helptexts
556 const Stringtable
*helpTextHash
= streamTable
.appl_helptexts
;
558 helpTextHash
= streamTable
.default_helptexts
;
559 if (helpTextHash
&& !helpTextHash
->empty())
561 Stringtable::const_iterator aEnd
= helpTextHash
->end();
562 for (Stringtable::const_iterator helpTextIter
= helpTextHash
->begin();
563 helpTextIter
!= aEnd
; ++helpTextIter
)
565 std::string helpTextId
= helpTextIter
->first
;
566 const std::string
& helpTextText
= helpTextIter
->second
;
568 helpTextId
= URLEncoder::encode(helpTextId
);
571 memset(&keyDbt
, 0, sizeof(keyDbt
));
572 keyDbt
.data
= const_cast<char*>(helpTextId
.c_str());
573 keyDbt
.size
= helpTextId
.length();
576 memset(&textDbt
, 0, sizeof(textDbt
));
577 textDbt
.data
= const_cast<char*>(helpTextText
.c_str());
578 textDbt
.size
= helpTextText
.length();
580 if( helpText
!= NULL
)
581 helpText
->put(helpText
, NULL
, &keyDbt
, &textDbt
, 0);
583 if( pFileHelpText_DBHelp
!= NULL
)
584 writeKeyValue_DBHelp( pFileHelpText_DBHelp
, helpTextId
, helpTextText
);
588 //IndexerPreProcessor
589 if( !bExtensionMode
|| bIndexForExtension
)
592 xmlDocPtr document
= streamTable
.appl_doc
;
594 document
= streamTable
.default_doc
;
597 std::string temp
= module
;
598 std::transform (temp
.begin(), temp
.end(), temp
.begin(), tocharlower
);
599 m_pIndexerPreProcessor
->processDocument(document
, URLEncoder::encode(documentPath
) );
603 } // while loop over hzip files ending
606 catch( const HelpProcessingException
& )
608 // catch HelpProcessingException to avoid locking data bases
610 helpText
->close(helpText
, 0);
611 dbBase
->close(dbBase
, 0);
612 keyWord
->close(keyWord
, 0);
614 if( pFileHelpText_DBHelp
!= NULL
)
615 fclose( pFileHelpText_DBHelp
);
616 if( pFileDbBase_DBHelp
!= NULL
)
617 fclose( pFileDbBase_DBHelp
);
622 helpText
->close(helpText
, 0);
623 dbBase
->close(dbBase
, 0);
624 helpKeyword
.dump(keyWord
);
625 keyWord
->close(keyWord
, 0);
627 if( pFileHelpText_DBHelp
!= NULL
)
628 fclose( pFileHelpText_DBHelp
);
629 if( pFileDbBase_DBHelp
!= NULL
)
630 fclose( pFileDbBase_DBHelp
);
632 helpKeyword
.dump_DBHelp( keyWordFileName_DBHelp
);
634 if( !bExtensionMode
)
637 Stringtable::iterator aEnd
= additionalFiles
.end();
638 for (Stringtable::iterator enumer
= additionalFiles
.begin(); enumer
!= aEnd
;
641 const std::string
&additionalFileName
= enumer
->second
;
642 const std::string
&additionalFileKey
= enumer
->first
;
644 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
645 std::string aNativeStr
= fsAdditionalFileName
.native_file_string();
646 HCDBG(const char* pStr
= aNativeStr
.c_str(); std::cerr
<< pStr
<< std::endl
);
648 fs::path
fsTargetName( indexDirParentName
/ additionalFileKey
);
650 fs::copy( fsAdditionalFileName
, fsTargetName
);
656 void HelpLinker::main( std::vector
<std::string
> &args
,
657 std::string
* pExtensionPath
, std::string
* pDestination
,
658 const rtl::OUString
* pOfficeHelpPath
)
659 throw( HelpProcessingException
)
661 bExtensionMode
= false;
664 if ((!args
.empty()) && args
[0][0] == '@')
666 std::vector
<std::string
> stringList
;
667 std::ifstream
fileReader(args
[0].substr(1).c_str());
674 stringList
.push_back(token
);
682 bool bSrcOption
= false;
683 while (i
< args
.size())
685 if (args
[i
].compare("-extlangsrc") == 0)
688 if (i
>= args
.size())
690 std::stringstream aStrStream
;
691 aStrStream
<< "extension source missing" << std::endl
;
692 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
696 else if (args
[i
].compare("-extlangdest") == 0)
698 //If this argument is not provided then the location provided in -extsource will
699 //also be the destination
701 if (i
>= args
.size())
703 std::stringstream aStrStream
;
704 aStrStream
<< "extension destination missing" << std::endl
;
705 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
707 extdestination
= args
[i
];
709 else if (args
[i
].compare("-src") == 0)
712 if (i
>= args
.size())
714 std::stringstream aStrStream
;
715 aStrStream
<< "sourceroot missing" << std::endl
;
716 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
719 sourceRoot
= fs::path(args
[i
], fs::native
);
721 else if (args
[i
].compare("-sty") == 0)
724 if (i
>= args
.size())
726 std::stringstream aStrStream
;
727 aStrStream
<< "embeddingStylesheet missing" << std::endl
;
728 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
731 embeddStylesheet
= fs::path(args
[i
], fs::native
);
733 else if (args
[i
].compare("-zipdir") == 0)
736 if (i
>= args
.size())
738 std::stringstream aStrStream
;
739 aStrStream
<< "idxtemp missing" << std::endl
;
740 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
743 zipdir
= fs::path(args
[i
], fs::native
);
745 else if (args
[i
].compare("-idxcaption") == 0)
748 if (i
>= args
.size())
750 std::stringstream aStrStream
;
751 aStrStream
<< "idxcaption stylesheet missing" << std::endl
;
752 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
755 idxCaptionStylesheet
= fs::path(args
[i
], fs::native
);
757 else if (args
[i
].compare("-idxcontent") == 0)
760 if (i
>= args
.size())
762 std::stringstream aStrStream
;
763 aStrStream
<< "idxcontent stylesheet missing" << std::endl
;
764 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
767 idxContentStylesheet
= fs::path(args
[i
], fs::native
);
769 else if (args
[i
].compare("-o") == 0)
772 if (i
>= args
.size())
774 std::stringstream aStrStream
;
775 aStrStream
<< "outputfilename missing" << std::endl
;
776 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
779 outputFile
= fs::path(args
[i
], fs::native
);
781 else if (args
[i
].compare("-mod") == 0)
784 if (i
>= args
.size())
786 std::stringstream aStrStream
;
787 aStrStream
<< "module name missing" << std::endl
;
788 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
793 else if (args
[i
].compare("-lang") == 0)
796 if (i
>= args
.size())
798 std::stringstream aStrStream
;
799 aStrStream
<< "language name missing" << std::endl
;
800 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
805 else if (args
[i
].compare("-hid") == 0)
808 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, "obsolete -hid argument used" );
810 else if (args
[i
].compare("-add") == 0)
812 std::string addFile
, addFileUnderPath
;
814 if (i
>= args
.size())
816 std::stringstream aStrStream
;
817 aStrStream
<< "pathname missing" << std::endl
;
818 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
821 addFileUnderPath
= args
[i
];
823 if (i
>= args
.size())
825 std::stringstream aStrStream
;
826 aStrStream
<< "pathname missing" << std::endl
;
827 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
830 if (!addFileUnderPath
.empty() && !addFile
.empty())
831 additionalFiles
[addFileUnderPath
] = addFile
;
834 helpFiles
.push_back(args
[i
]);
838 //We can be called from the helplinker executable or the extension manager
839 //In the latter case extsource is not used.
840 if( (pExtensionPath
&& pExtensionPath
->length() > 0 && pOfficeHelpPath
)
841 || !extsource
.empty())
843 bExtensionMode
= true;
844 if (!extsource
.empty())
846 //called from helplinker.exe, pExtensionPath and pOfficeHelpPath
848 sourceRoot
= fs::path(extsource
, fs::native
);
849 extensionPath
= sourceRoot
.toUTF8();
851 if (extdestination
.empty())
853 std::stringstream aStrStream
;
854 aStrStream
<< "-extlangdest is missing" << std::endl
;
855 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
859 //Convert from system path to file URL!!!
860 fs::path
p(extdestination
, fs::native
);
861 extensionDestination
= p
.toUTF8();
865 { //called from extension manager
866 extensionPath
= *pExtensionPath
;
867 sourceRoot
= fs::path(extensionPath
);
868 extensionDestination
= *pDestination
;
870 //check if -src option was used. This option must not be used
871 //when extension help is compiled.
874 std::stringstream aStrStream
;
875 aStrStream
<< "-src must not be used together with -extsource missing" << std::endl
;
876 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
880 if (!bExtensionMode
&& zipdir
.empty())
882 std::stringstream aStrStream
;
883 aStrStream
<< "no index dir given" << std::endl
;
884 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
887 if ( (!bExtensionMode
&& idxCaptionStylesheet
.empty())
888 || (!extsource
.empty() && idxCaptionStylesheet
.empty()) )
890 //No extension mode and extension mode using commandline
891 //!extsource.empty indicates extension mode using commandline
892 // -idxcaption paramter is required
893 std::stringstream aStrStream
;
894 aStrStream
<< "no index caption stylesheet given" << std::endl
;
895 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
897 else if ( bExtensionMode
&& extsource
.empty())
899 //This part is used when compileExtensionHelp is called from the extensions manager.
900 //If extension help is compiled using helplinker in the build process
901 rtl::OUString
aIdxCaptionPathFileURL( *pOfficeHelpPath
);
902 aIdxCaptionPathFileURL
+= rtl::OUString("/idxcaption.xsl");
904 rtl::OString
aOStr_IdxCaptionPathFileURL( rtl::OUStringToOString
905 ( aIdxCaptionPathFileURL
, fs::getThreadTextEncoding() ) );
906 std::string
aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL
.getStr() );
908 idxCaptionStylesheet
= fs::path( aStdStr_IdxCaptionPathFileURL
);
911 if ( (!bExtensionMode
&& idxContentStylesheet
.empty())
912 || (!extsource
.empty() && idxContentStylesheet
.empty()) )
914 //No extension mode and extension mode using commandline
915 //!extsource.empty indicates extension mode using commandline
916 // -idxcontent paramter is required
917 std::stringstream aStrStream
;
918 aStrStream
<< "no index content stylesheet given" << std::endl
;
919 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
921 else if ( bExtensionMode
&& extsource
.empty())
923 //If extension help is compiled using helplinker in the build process
924 //then -idxcontent must be supplied
925 //This part is used when compileExtensionHelp is called from the extensions manager.
926 rtl::OUString
aIdxContentPathFileURL( *pOfficeHelpPath
);
927 aIdxContentPathFileURL
+= rtl::OUString("/idxcontent.xsl");
929 rtl::OString
aOStr_IdxContentPathFileURL( rtl::OUStringToOString
930 ( aIdxContentPathFileURL
, fs::getThreadTextEncoding() ) );
931 std::string
aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL
.getStr() );
933 idxContentStylesheet
= fs::path( aStdStr_IdxContentPathFileURL
);
935 if (!bExtensionMode
&& embeddStylesheet
.empty())
937 std::stringstream aStrStream
;
938 aStrStream
<< "no embedding resolving file given" << std::endl
;
939 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
941 if (sourceRoot
.empty())
943 std::stringstream aStrStream
;
944 aStrStream
<< "no sourceroot given" << std::endl
;
945 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
947 if (!bExtensionMode
&& outputFile
.empty())
949 std::stringstream aStrStream
;
950 aStrStream
<< "no output file given" << std::endl
;
951 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
955 std::stringstream aStrStream
;
956 aStrStream
<< "module missing" << std::endl
;
957 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
959 if (!bExtensionMode
&& lang
.empty())
961 std::stringstream aStrStream
;
962 aStrStream
<< "language missing" << std::endl
;
963 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
968 // Variable to set an exception in "C" StructuredXMLErrorFunction
969 static const HelpProcessingException
* GpXMLParsingException
= NULL
;
971 extern "C" void StructuredXMLErrorFunction(void *userData
, xmlErrorPtr error
)
976 std::string aErrorMsg
= error
->message
;
977 std::string aXMLParsingFile
;
978 if( error
->file
!= NULL
)
979 aXMLParsingFile
= error
->file
;
980 int nXMLParsingLine
= error
->line
;
981 HelpProcessingException
* pException
= new HelpProcessingException( aErrorMsg
, aXMLParsingFile
, nXMLParsingLine
);
982 GpXMLParsingException
= pException
;
984 // Reset error handler
985 xmlSetStructuredErrorFunc( NULL
, NULL
);
988 HelpProcessingErrorInfo
& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException
& e
)
990 m_eErrorClass
= e
.m_eErrorClass
;
991 rtl::OString
tmpErrorMsg( e
.m_aErrorMsg
.c_str() );
992 m_aErrorMsg
= rtl::OStringToOUString( tmpErrorMsg
, fs::getThreadTextEncoding() );
993 rtl::OString
tmpXMLParsingFile( e
.m_aXMLParsingFile
.c_str() );
994 m_aXMLParsingFile
= rtl::OStringToOUString( tmpXMLParsingFile
, fs::getThreadTextEncoding() );
995 m_nXMLParsingLine
= e
.m_nXMLParsingLine
;
1000 // Returns true in case of success, false in case of error
1001 HELPLINKER_DLLPUBLIC
bool compileExtensionHelp
1003 const rtl::OUString
& aOfficeHelpPath
,
1004 const rtl::OUString
& aExtensionName
,
1005 const rtl::OUString
& aExtensionLanguageRoot
,
1006 sal_Int32 nXhpFileCount
, const rtl::OUString
* pXhpFiles
,
1007 const rtl::OUString
& aDestination
,
1008 HelpProcessingErrorInfo
& o_rHelpProcessingErrorInfo
1011 bool bSuccess
= true;
1013 std::vector
<std::string
> args
;
1014 args
.reserve(nXhpFileCount
+ 2);
1015 args
.push_back(std::string("-mod"));
1016 rtl::OString aOExtensionName
= rtl::OUStringToOString( aExtensionName
, fs::getThreadTextEncoding() );
1017 args
.push_back(std::string(aOExtensionName
.getStr()));
1019 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
1021 rtl::OUString aXhpFile
= pXhpFiles
[iXhp
];
1023 rtl::OString aOXhpFile
= rtl::OUStringToOString( aXhpFile
, fs::getThreadTextEncoding() );
1024 args
.push_back(std::string(aOXhpFile
.getStr()));
1027 rtl::OString aOExtensionLanguageRoot
= rtl::OUStringToOString( aExtensionLanguageRoot
, fs::getThreadTextEncoding() );
1028 const char* pExtensionPath
= aOExtensionLanguageRoot
.getStr();
1029 std::string aStdStrExtensionPath
= pExtensionPath
;
1030 rtl::OString aODestination
= rtl::OUStringToOString(aDestination
, fs::getThreadTextEncoding());
1031 const char* pDestination
= aODestination
.getStr();
1032 std::string aStdStrDestination
= pDestination
;
1034 // Set error handler
1035 xmlSetStructuredErrorFunc( NULL
, (xmlStructuredErrorFunc
)StructuredXMLErrorFunction
);
1038 HelpLinker
* pHelpLinker
= new HelpLinker();
1039 pHelpLinker
->main( args
, &aStdStrExtensionPath
, &aStdStrDestination
, &aOfficeHelpPath
);
1042 catch( const HelpProcessingException
& e
)
1044 if( GpXMLParsingException
!= NULL
)
1046 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
1047 delete GpXMLParsingException
;
1048 GpXMLParsingException
= NULL
;
1052 o_rHelpProcessingErrorInfo
= e
;
1056 // Reset error handler
1057 xmlSetStructuredErrorFunc( NULL
, NULL
);
1059 // i83624: Tree files
1060 ::rtl::OUString aTreeFileURL
= aExtensionLanguageRoot
;
1061 aTreeFileURL
+= rtl::OUString("/help.tree");
1062 osl::DirectoryItem aTreeFileItem
;
1063 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
1064 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileSize
);
1065 if( rcGet
== osl::FileBase::E_None
&&
1066 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
1067 aFileStatus
.isValid( osl_FileStatus_Mask_FileSize
) )
1069 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
1070 char* s
= new char[ int(len
) ]; // the buffer to hold the installed files
1071 osl::File
aFile( aTreeFileURL
);
1072 aFile
.open( osl_File_OpenFlag_Read
);
1073 aFile
.read( s
, len
, ret
);
1076 XML_Parser parser
= XML_ParserCreate( 0 );
1077 int parsed
= XML_Parse( parser
, s
, int( len
), true );
1081 XML_Error nError
= XML_GetErrorCode( parser
);
1082 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HELPPROCESSING_XMLPARSING_ERROR
;
1083 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= rtl::OUString::createFromAscii( XML_ErrorString( nError
) );;
1084 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
1085 // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
1089 XML_ParserFree( parser
);
1096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */