1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: HelpLinker.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "HelpCompiler.hxx"
38 #include <libxslt/xslt.h>
39 #include <libxslt/transform.h>
40 #include <libxslt/xsltutils.h>
41 #include <libxslt/functions.h>
42 #include <libxslt/extensions.h>
44 #include <sal/types.h>
46 #include <rtl/bootstrap.hxx>
51 #include <expat/xmlparse.h>
57 class IndexerPreProcessor
60 std::string m_aModuleName
;
61 fs::path m_fsIndexBaseDir
;
62 fs::path m_fsCaptionFilesDirName
;
63 fs::path m_fsContentFilesDirName
;
65 xsltStylesheetPtr m_xsltStylesheetPtrCaption
;
66 xsltStylesheetPtr m_xsltStylesheetPtrContent
;
69 IndexerPreProcessor( const std::string
& aModuleName
, const fs::path
& fsIndexBaseDir
,
70 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
);
71 ~IndexerPreProcessor();
73 void processDocument( xmlDocPtr doc
, const std::string
& EncodedDocPath
);
76 IndexerPreProcessor::IndexerPreProcessor
77 ( const std::string
& aModuleName
, const fs::path
& fsIndexBaseDir
,
78 const fs::path
& idxCaptionStylesheet
, const fs::path
& idxContentStylesheet
)
79 : m_aModuleName( aModuleName
)
80 , m_fsIndexBaseDir( fsIndexBaseDir
)
82 m_fsCaptionFilesDirName
= fsIndexBaseDir
/ "caption";
83 fs::create_directory( m_fsCaptionFilesDirName
);
85 m_fsContentFilesDirName
= fsIndexBaseDir
/ "content";
86 fs::create_directory( m_fsContentFilesDirName
);
88 m_xsltStylesheetPtrCaption
= xsltParseStylesheetFile
89 ((const xmlChar
*)idxCaptionStylesheet
.native_file_string().c_str());
90 m_xsltStylesheetPtrContent
= xsltParseStylesheetFile
91 ((const xmlChar
*)idxContentStylesheet
.native_file_string().c_str());
94 IndexerPreProcessor::~IndexerPreProcessor()
96 if( m_xsltStylesheetPtrCaption
)
97 xsltFreeStylesheet( m_xsltStylesheetPtrCaption
);
98 if( m_xsltStylesheetPtrContent
)
99 xsltFreeStylesheet( m_xsltStylesheetPtrContent
);
103 std::string
getEncodedPath( const std::string
& Path
)
105 rtl::OString
aOStr_Path( Path
.c_str() );
106 rtl::OUString
aOUStr_Path( rtl::OStringToOUString
107 ( aOStr_Path
, fs::getThreadTextEncoding() ) );
108 rtl::OUString aPathURL
;
109 osl::File::getFileURLFromSystemPath( aOUStr_Path
, aPathURL
);
110 rtl::OString
aOStr_PathURL( rtl::OUStringToOString
111 ( aPathURL
, fs::getThreadTextEncoding() ) );
112 std::string
aStdStr_PathURL( aOStr_PathURL
.getStr() );
113 return aStdStr_PathURL
;
116 void IndexerPreProcessor::processDocument
117 ( xmlDocPtr doc
, const std::string
&EncodedDocPath
)
119 std::string aStdStr_EncodedDocPathURL
= getEncodedPath( EncodedDocPath
);
121 xmlDocPtr resCaption
= xsltApplyStylesheet( m_xsltStylesheetPtrCaption
, doc
, NULL
);
122 xmlNodePtr pResNodeCaption
= resCaption
->xmlChildrenNode
;
123 if( pResNodeCaption
)
125 fs::path fsCaptionPureTextFile_docURL
= m_fsCaptionFilesDirName
/ aStdStr_EncodedDocPathURL
;
126 std::string aCaptionPureTextFileStr_docURL
= fsCaptionPureTextFile_docURL
.native_file_string();
127 FILE* pFile_docURL
= fopen( aCaptionPureTextFileStr_docURL
.c_str(), "w" );
130 fprintf( pFile_docURL
, "%s\n", pResNodeCaption
->content
);
131 fclose( pFile_docURL
);
134 xmlFreeDoc(resCaption
);
136 xmlDocPtr resContent
= xsltApplyStylesheet( m_xsltStylesheetPtrContent
, doc
, NULL
);
137 xmlNodePtr pResNodeContent
= resContent
->xmlChildrenNode
;
138 if( pResNodeContent
)
140 fs::path fsContentPureTextFile_docURL
= m_fsContentFilesDirName
/ aStdStr_EncodedDocPathURL
;
141 std::string aContentPureTextFileStr_docURL
= fsContentPureTextFile_docURL
.native_file_string();
142 FILE* pFile_docURL
= fopen( aContentPureTextFileStr_docURL
.c_str(), "w" );
145 fprintf( pFile_docURL
, "%s\n", pResNodeContent
->content
);
146 fclose( pFile_docURL
);
149 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 int nKeyLen
= aKeyStr
.length();
178 int nValueLen
= aValueStr
.length();
179 fprintf( pFile
, "%x ", nKeyLen
);
181 fwrite( aKeyStr
.c_str(), 1, nKeyLen
, pFile
);
182 fprintf( pFile
, " %x ", nValueLen
);
184 fwrite( aValueStr
.c_str(), 1, nValueLen
, pFile
);
185 fprintf( pFile
, "%c", cLF
);
191 typedef std::hash_map
<std::string
, Data
, pref_hash
> DataHashtable
;
195 void insert(const std::string
&key
, const std::string
&id
)
197 Data
&data
= _hash
[key
];
203 DataHashtable::const_iterator aEnd
= _hash
.end();
204 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
206 const std::string
&keystr
= aIter
->first
;
208 memset(&key
, 0, sizeof(key
));
209 key
.data
= const_cast<char*>(keystr
.c_str());
210 key
.size
= keystr
.length();
212 const Data
&data
= aIter
->second
;
213 std::string str
= data
.getString();
215 memset(&value
, 0, sizeof(value
));
216 value
.data
= const_cast<char*>(str
.c_str());
217 value
.size
= str
.length();
219 table
->put(table
, NULL
, &key
, &value
, 0);
223 void dump_DBHelp( const std::string
& rFileName
)
225 FILE* pFile
= fopen( rFileName
.c_str(), "wb" );
229 DataHashtable::const_iterator aEnd
= _hash
.end();
230 for (DataHashtable::const_iterator aIter
= _hash
.begin(); aIter
!= aEnd
; ++aIter
)
231 writeKeyValue_DBHelp( pFile
, aIter
->first
, aIter
->second
.getString() );
240 void main(std::vector
<std::string
> &args
, std::string
* pExtensionPath
= NULL
)
241 throw( HelpProcessingException
);
245 , m_pIndexerPreProcessor(NULL
)
248 { delete m_pIndexerPreProcessor
; }
251 int locCount
, totCount
;
252 Stringtable additionalFiles
;
255 fs::path embeddStylesheet
;
256 fs::path idxCaptionStylesheet
;
257 fs::path idxContentStylesheet
;
263 std::string extensionPath
;
265 fs::path indexDirName
;
266 Stringtable hidlistTranslation
;
267 fs::path indexDirParentName
;
269 IndexerPreProcessor
* m_pIndexerPreProcessor
;
270 void initIndexerPreProcessor();
271 void link() throw( HelpProcessingException
);
272 void 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
);
282 * @param additionalFiles
285 private HelpURLStreamHandlerFactory urlHandler
= null
;
291 static std::string
encode(const std::string
&rIn
)
293 const char *good
= "!$&'()*+,-.=@_";
294 static const char hex
[17] = "0123456789ABCDEF";
297 for (size_t i
=0; i
< rIn
.length(); ++i
)
299 unsigned char c
= rIn
[i
];
300 if (isalnum (c
) || strchr (good
, c
))
304 result
+= hex
[c
>> 4];
305 result
+= hex
[c
& 0xf];
312 void HelpLinker::addBookmark( DB
* dbBase
, FILE* pFile_DBHelp
, std::string thishid
,
313 const std::string
& fileB
, const std::string
& anchorB
,
314 const std::string
& jarfileB
, const std::string
& titleB
)
316 HCDBG(std::cerr
<< "HelpLinker::addBookmark " << thishid
<< " " <<
317 fileB
<< " " << anchorB
<< " " << jarfileB
<< " " << titleB
<< std::endl
);
319 std::string temp
= thishid
;
320 std::transform (temp
.begin(), temp
.end(), temp
.begin(), toupper
);
321 std::replace(temp
.begin(), temp
.end(), ':', '_');
322 const std::string
& translatedHid
= hidlistTranslation
[temp
];
323 if (!translatedHid
.empty())
324 thishid
= translatedHid
;
326 thishid
= URLEncoder::encode(thishid
);
329 memset(&key
, 0, sizeof(key
));
330 key
.data
= const_cast<char*>(thishid
.c_str());
331 key
.size
= thishid
.length();
333 int fileLen
= fileB
.length();
334 if (!anchorB
.empty())
335 fileLen
+= (1 + anchorB
.length());
336 int dataLen
= 1 + fileLen
+ 1 + jarfileB
.length() + 1 + titleB
.length();
338 std::vector
<unsigned char> dataB(dataLen
);
340 dataB
[i
++] = static_cast<unsigned char>(fileLen
);
341 for (size_t j
= 0; j
< fileB
.length(); ++j
)
342 dataB
[i
++] = fileB
[j
];
343 if (!anchorB
.empty())
346 for (size_t j
= 0; j
< anchorB
.length(); ++j
)
347 dataB
[i
++] = anchorB
[j
];
349 dataB
[i
++] = static_cast<unsigned char>(jarfileB
.length());
350 for (size_t j
= 0; j
< jarfileB
.length(); ++j
)
351 dataB
[i
++] = jarfileB
[j
];
353 dataB
[i
++] = static_cast<unsigned char>(titleB
.length());
354 for (size_t j
= 0; j
< titleB
.length(); ++j
)
355 dataB
[i
++] = titleB
[j
];
358 memset(&data
, 0, sizeof(data
));
359 data
.data
= &dataB
[0];
360 data
.size
= dataB
.size();
363 dbBase
->put(dbBase
, NULL
, &key
, &data
, 0);
365 if( pFile_DBHelp
!= NULL
)
367 std::string
aValueStr( dataB
.begin(), dataB
.end() );
368 writeKeyValue_DBHelp( pFile_DBHelp
, thishid
, aValueStr
);
372 void HelpLinker::initIndexerPreProcessor()
374 if( m_pIndexerPreProcessor
)
375 delete m_pIndexerPreProcessor
;
376 std::string mod
= module
;
377 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tolower
);
378 m_pIndexerPreProcessor
= new IndexerPreProcessor( mod
, indexDirParentName
,
379 idxCaptionStylesheet
, idxContentStylesheet
);
385 void HelpLinker::link() throw( HelpProcessingException
)
387 bool bIndexForExtension
= true;
391 indexDirParentName
= sourceRoot
;
395 indexDirParentName
= zipdir
;
396 fs::create_directory(indexDirParentName
);
400 std::cerr
<< "will not delete tmpdir of " << indexDirParentName
.native_file_string().c_str() << std::endl
;
403 std::string mod
= module
;
404 std::transform (mod
.begin(), mod
.end(), mod
.begin(), tolower
);
407 // continue with introduction of the overall process thing into the
408 // here all hzip files will be worked on
409 std::string appl
= mod
;
411 appl
= appl
.substr(1);
415 if( !bExtensionMode
)
421 fs::path
helpTextFileName(indexDirParentName
/ (mod
+ ".ht"));
422 db_create(&helpText
,0,0);
423 helpText
->open(helpText
, NULL
, helpTextFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
424 DB_CREATE
| DB_TRUNCATE
, 0644);
427 fs::path
helpTextFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".ht_" : ".ht")));
428 FILE* pFileHelpText_DBHelp
= fopen
429 ( helpTextFileName_DBHelp
.native_file_string().c_str(), "wb" );
433 fs::path
dbBaseFileName(indexDirParentName
/ (mod
+ ".db"));
434 db_create(&dbBase
,0,0);
435 dbBase
->open(dbBase
, NULL
, dbBaseFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
436 DB_CREATE
| DB_TRUNCATE
, 0644);
439 fs::path
dbBaseFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".db_" : ".db")));
440 FILE* pFileDbBase_DBHelp
= fopen
441 ( dbBaseFileName_DBHelp
.native_file_string().c_str(), "wb" );
445 fs::path
keyWordFileName(indexDirParentName
/ (mod
+ ".key"));
446 db_create(&keyWord
,0,0);
447 keyWord
->open(keyWord
, NULL
, keyWordFileName
.native_file_string().c_str(), NULL
, DB_BTREE
,
448 DB_CREATE
| DB_TRUNCATE
, 0644);
451 fs::path
keyWordFileName_DBHelp(indexDirParentName
/ (mod
+ (bUse_
? ".key_" : ".key")));
453 HelpKeyword helpKeyword
;
455 // catch HelpProcessingException to avoid locking data bases
459 std::ifstream
fileReader(hid
.c_str());
464 std::transform (key
.begin(), key
.end(), key
.begin(), toupper
);
465 std::replace(key
.begin(), key
.end(), ':', '_');
468 if (!key
.empty() && !data
.empty())
469 hidlistTranslation
[key
] = data
;
473 // lastly, initialize the indexBuilder
474 if ( (!bExtensionMode
|| bIndexForExtension
) && !helpFiles
.empty())
475 initIndexerPreProcessor();
477 if( !bExtensionMode
)
479 std::cout
<< "Making " << outputFile
.native_file_string() <<
480 " from " << helpFiles
.size() << " input files" << std::endl
;
483 // here we start our loop over the hzip files.
484 HashSet::iterator end
= helpFiles
.end();
485 for (HashSet::iterator iter
= helpFiles
.begin(); iter
!= end
; ++iter
)
487 if( !bExtensionMode
)
494 // streamTable contains the streams in the hzip file
495 StreamTable streamTable
;
496 const std::string
&xhpFileName
= *iter
;
498 if (!bExtensionMode
&& xhpFileName
.rfind(".xhp") != xhpFileName
.length()-4)
500 // only work on .xhp - files
502 "ERROR: input list entry '"
504 << "' has the wrong extension (only files with extension .xhp "
509 fs::path
langsourceRoot(sourceRoot
);
514 // langsourceRoot == sourceRoot for extensions
515 std::string
xhpFileNameComplete( extensionPath
);
516 xhpFileNameComplete
.append( '/' + xhpFileName
);
517 xhpFile
= fs::path( xhpFileNameComplete
);
521 langsourceRoot
.append('/' + lang
+ '/');
522 xhpFile
= fs::path(xhpFileName
, fs::native
);
525 HelpCompiler
hc( streamTable
, xhpFile
, langsourceRoot
,
526 embeddStylesheet
, module
, lang
, bExtensionMode
);
528 HCDBG(std::cerr
<< "before compile of " << xhpFileName
<< std::endl
);
529 bool success
= hc
.compile();
530 HCDBG(std::cerr
<< "after compile of " << xhpFileName
<< std::endl
);
532 if (!success
&& !bExtensionMode
)
534 std::stringstream aStrStream
;
536 "\nERROR: compiling help particle '"
538 << "' for language '"
541 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
544 const std::string documentBaseId
= streamTable
.document_id
;
545 std::string documentPath
= streamTable
.document_path
;
546 if (documentPath
.find("/") == 0)
547 documentPath
= documentPath
.substr(1);
549 std::string documentJarfile
= streamTable
.document_module
+ ".jar";
551 std::string documentTitle
= streamTable
.document_title
;
552 if (documentTitle
.empty())
553 documentTitle
= "<notitle>";
556 std::cout
<< "for " << xhpFileName
<< " documentBaseId is " << documentBaseId
<< "\n";
557 std::cout
<< "for " << xhpFileName
<< " documentPath is " << documentPath
<< "\n";
558 std::cout
<< "for " << xhpFileName
<< " documentJarfile is " << documentJarfile
<< "\n";
559 std::cout
<< "for " << xhpFileName
<< " documentPath is " << documentTitle
<< "\n";
562 const std::string
& fileB
= documentPath
;
563 const std::string
& jarfileB
= documentJarfile
;
564 std::string
& titleB
= documentTitle
;
566 // add once this as its own id.
567 addBookmark(dbBase
, pFileDbBase_DBHelp
, documentPath
, fileB
, std::string(), jarfileB
, titleB
);
569 // first the database *.db
570 // ByteArrayInputStream bais = null;
571 // ObjectInputStream ois = null;
573 const HashSet
*hidlist
= streamTable
.appl_hidlist
;
575 hidlist
= streamTable
.default_hidlist
;
576 if (hidlist
&& !hidlist
->empty())
578 // now iterate over all elements of the hidlist
579 HashSet::const_iterator aEnd
= hidlist
->end();
580 for (HashSet::const_iterator hidListIter
= hidlist
->begin();
581 hidListIter
!= aEnd
; ++hidListIter
)
583 std::string thishid
= *hidListIter
;
586 size_t index
= thishid
.rfind('#');
587 if (index
!= std::string::npos
)
589 anchorB
= thishid
.substr(1 + index
);
590 thishid
= thishid
.substr(0, index
);
592 addBookmark(dbBase
, pFileDbBase_DBHelp
, thishid
, fileB
, anchorB
, jarfileB
, titleB
);
597 const Hashtable
*anchorToLL
= streamTable
.appl_keywords
;
599 anchorToLL
= streamTable
.default_keywords
;
600 if (anchorToLL
&& !anchorToLL
->empty())
602 std::string fakedHid
= URLEncoder::encode(documentPath
);
603 Hashtable::const_iterator aEnd
= anchorToLL
->end();
604 for (Hashtable::const_iterator enumer
= anchorToLL
->begin();
605 enumer
!= aEnd
; ++enumer
)
607 const std::string
&anchor
= enumer
->first
;
608 addBookmark(dbBase
, pFileDbBase_DBHelp
, documentPath
, fileB
,
609 anchor
, jarfileB
, titleB
);
610 std::string totalId
= fakedHid
+ "#" + anchor
;
611 // std::cerr << hzipFileName << std::endl;
612 const LinkedList
& ll
= enumer
->second
;
613 LinkedList::const_iterator aOtherEnd
= ll
.end();
614 for (LinkedList::const_iterator llIter
= ll
.begin();
615 llIter
!= aOtherEnd
; ++llIter
)
617 helpKeyword
.insert(*llIter
, totalId
);
623 // and last the helptexts
624 const Stringtable
*helpTextHash
= streamTable
.appl_helptexts
;
626 helpTextHash
= streamTable
.default_helptexts
;
627 if (helpTextHash
&& !helpTextHash
->empty())
629 Stringtable::const_iterator aEnd
= helpTextHash
->end();
630 for (Stringtable::const_iterator helpTextIter
= helpTextHash
->begin();
631 helpTextIter
!= aEnd
; ++helpTextIter
)
633 std::string helpTextId
= helpTextIter
->first
;
634 const std::string
& helpTextText
= helpTextIter
->second
;
636 std::string temp
= helpTextId
;
637 std::transform (temp
.begin(), temp
.end(), temp
.begin(), toupper
);
638 std::replace(temp
.begin(), temp
.end(), ':', '_');
640 const std::string
& tHid
= hidlistTranslation
[temp
];
643 helpTextId
= URLEncoder::encode(helpTextId
);
646 memset(&keyDbt
, 0, sizeof(keyDbt
));
647 keyDbt
.data
= const_cast<char*>(helpTextId
.c_str());
648 keyDbt
.size
= helpTextId
.length();
651 memset(&textDbt
, 0, sizeof(textDbt
));
652 textDbt
.data
= const_cast<char*>(helpTextText
.c_str());
653 textDbt
.size
= helpTextText
.length();
655 if( helpText
!= NULL
)
656 helpText
->put(helpText
, NULL
, &keyDbt
, &textDbt
, 0);
658 if( pFileHelpText_DBHelp
!= NULL
)
659 writeKeyValue_DBHelp( pFileHelpText_DBHelp
, helpTextId
, helpTextText
);
663 //IndexerPreProcessor
664 if( !bExtensionMode
|| bIndexForExtension
)
667 xmlDocPtr document
= streamTable
.appl_doc
;
669 document
= streamTable
.default_doc
;
672 std::string temp
= module
;
673 std::transform (temp
.begin(), temp
.end(), temp
.begin(), tolower
);
674 m_pIndexerPreProcessor
->processDocument(document
, URLEncoder::encode(documentPath
) );
678 } // while loop over hzip files ending
679 if( !bExtensionMode
)
680 std::cout
<< std::endl
;
683 catch( HelpProcessingException
& )
685 // catch HelpProcessingException to avoid locking data bases
687 helpText
->close(helpText
, 0);
688 dbBase
->close(dbBase
, 0);
689 keyWord
->close(keyWord
, 0);
691 if( pFileHelpText_DBHelp
!= NULL
)
692 fclose( pFileHelpText_DBHelp
);
693 if( pFileDbBase_DBHelp
!= NULL
)
694 fclose( pFileDbBase_DBHelp
);
699 helpText
->close(helpText
, 0);
700 dbBase
->close(dbBase
, 0);
701 helpKeyword
.dump(keyWord
);
702 keyWord
->close(keyWord
, 0);
704 if( pFileHelpText_DBHelp
!= NULL
)
705 fclose( pFileHelpText_DBHelp
);
706 if( pFileDbBase_DBHelp
!= NULL
)
707 fclose( pFileDbBase_DBHelp
);
709 helpKeyword
.dump_DBHelp( keyWordFileName_DBHelp
.native_file_string() );
711 if( !bExtensionMode
)
714 Stringtable::iterator aEnd
= additionalFiles
.end();
715 for (Stringtable::iterator enumer
= additionalFiles
.begin(); enumer
!= aEnd
;
718 const std::string
&additionalFileName
= enumer
->second
;
719 const std::string
&additionalFileKey
= enumer
->first
;
721 fs::path
fsAdditionalFileName( additionalFileName
, fs::native
);
722 std::string aNativeStr
= fsAdditionalFileName
.native_file_string();
723 const char* pStr
= aNativeStr
.c_str();
726 fs::path
fsTargetName( indexDirParentName
/ additionalFileKey
);
728 fs::copy( fsAdditionalFileName
, fsTargetName
);
733 /////////////////////////////////////////////////////////////////////////
734 /// remove temprary directory for index creation
735 /////////////////////////////////////////////////////////////////////////
737 if( !bExtensionMode )
738 fs::remove_all( indexDirParentName );
744 void HelpLinker::main(std::vector
<std::string
> &args
, std::string
* pExtensionPath
)
745 throw( HelpProcessingException
)
747 rtl::OUString aOfficeHelpPath
;
749 bExtensionMode
= false;
750 if( pExtensionPath
&& pExtensionPath
->length() > 0 )
753 bExtensionMode
= true;
754 extensionPath
= *pExtensionPath
;
755 sourceRoot
= fs::path(extensionPath
);
757 aOfficeHelpPath
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/help") );
758 rtl::Bootstrap::expandMacros( aOfficeHelpPath
);
760 if (args
.size() > 0 && args
[0][0] == '@')
762 std::vector
<std::string
> stringList
;
764 std::ifstream
fileReader(args
[0].substr(1).c_str());
771 stringList
.push_back(token
);
780 while (i
< args
.size())
782 if (args
[i
].compare("-src") == 0)
785 if (i
>= args
.size())
787 std::stringstream aStrStream
;
788 aStrStream
<< "sourceroot missing" << std::endl
;
789 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
792 if( !bExtensionMode
)
793 sourceRoot
= fs::path(args
[i
], fs::native
);
795 else if (args
[i
].compare("-sty") == 0)
798 if (i
>= args
.size())
800 std::stringstream aStrStream
;
801 aStrStream
<< "embeddingStylesheet missing" << std::endl
;
802 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
805 embeddStylesheet
= fs::path(args
[i
], fs::native
);
807 else if (args
[i
].compare("-zipdir") == 0)
810 if (i
>= args
.size())
812 std::stringstream aStrStream
;
813 aStrStream
<< "idxtemp missing" << std::endl
;
814 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
817 zipdir
= fs::path(args
[i
], fs::native
);
819 else if (args
[i
].compare("-idxcaption") == 0)
822 if (i
>= args
.size())
824 std::stringstream aStrStream
;
825 aStrStream
<< "idxcaption stylesheet missing" << std::endl
;
826 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
829 idxCaptionStylesheet
= fs::path(args
[i
], fs::native
);
831 else if (args
[i
].compare("-idxcontent") == 0)
834 if (i
>= args
.size())
836 std::stringstream aStrStream
;
837 aStrStream
<< "idxcontent stylesheet missing" << std::endl
;
838 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
841 idxContentStylesheet
= fs::path(args
[i
], fs::native
);
843 else if (args
[i
].compare("-o") == 0)
846 if (i
>= args
.size())
848 std::stringstream aStrStream
;
849 aStrStream
<< "outputfilename missing" << std::endl
;
850 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
853 outputFile
= fs::path(args
[i
], fs::native
);
855 else if (args
[i
].compare("-mod") == 0)
858 if (i
>= args
.size())
860 std::stringstream aStrStream
;
861 aStrStream
<< "module name missing" << std::endl
;
862 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
867 else if (args
[i
].compare("-lang") == 0)
870 if (i
>= args
.size())
872 std::stringstream aStrStream
;
873 aStrStream
<< "language name missing" << std::endl
;
874 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
879 else if (args
[i
].compare("-hid") == 0)
882 if (i
>= args
.size())
884 std::stringstream aStrStream
;
885 aStrStream
<< "hid list missing" << std::endl
;
886 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
891 else if (args
[i
].compare("-add") == 0)
893 std::string addFile
, addFileUnderPath
;
895 if (i
>= args
.size())
897 std::stringstream aStrStream
;
898 aStrStream
<< "pathname missing" << std::endl
;
899 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
902 addFileUnderPath
= args
[i
];
904 if (i
>= args
.size())
906 std::stringstream aStrStream
;
907 aStrStream
<< "pathname missing" << std::endl
;
908 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
911 if (!addFileUnderPath
.empty() && !addFile
.empty())
912 additionalFiles
[addFileUnderPath
] = addFile
;
915 helpFiles
.push_back(args
[i
]);
919 if (!bExtensionMode
&& zipdir
.empty())
921 std::stringstream aStrStream
;
922 aStrStream
<< "no index dir given" << std::endl
;
923 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
925 if (!bExtensionMode
&& idxCaptionStylesheet
.empty())
927 std::stringstream aStrStream
;
928 aStrStream
<< "no index caption stylesheet given" << std::endl
;
929 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
931 else if ( bExtensionMode
)
933 rtl::OUString
aIdxCaptionPathFileURL( aOfficeHelpPath
);
934 aIdxCaptionPathFileURL
+= rtl::OUString::createFromAscii( "/idxcaption.xsl" );
936 rtl::OString
aOStr_IdxCaptionPathFileURL( rtl::OUStringToOString
937 ( aIdxCaptionPathFileURL
, fs::getThreadTextEncoding() ) );
938 std::string
aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL
.getStr() );
940 idxCaptionStylesheet
= fs::path( aStdStr_IdxCaptionPathFileURL
);
942 if (!bExtensionMode
&& idxContentStylesheet
.empty())
944 std::stringstream aStrStream
;
945 aStrStream
<< "no index content stylesheet given" << std::endl
;
946 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
948 else if ( bExtensionMode
)
950 rtl::OUString
aIdxContentPathFileURL( aOfficeHelpPath
);
951 aIdxContentPathFileURL
+= rtl::OUString::createFromAscii( "/idxcontent.xsl" );
953 rtl::OString
aOStr_IdxContentPathFileURL( rtl::OUStringToOString
954 ( aIdxContentPathFileURL
, fs::getThreadTextEncoding() ) );
955 std::string
aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL
.getStr() );
957 idxContentStylesheet
= fs::path( aStdStr_IdxContentPathFileURL
);
959 if (!bExtensionMode
&& embeddStylesheet
.empty())
961 std::stringstream aStrStream
;
962 aStrStream
<< "no embedding resolving file given" << std::endl
;
963 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
965 if (sourceRoot
.empty())
967 std::stringstream aStrStream
;
968 aStrStream
<< "no sourceroot given" << std::endl
;
969 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
971 if (!bExtensionMode
&& outputFile
.empty())
973 std::stringstream aStrStream
;
974 aStrStream
<< "no output file given" << std::endl
;
975 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
979 std::stringstream aStrStream
;
980 aStrStream
<< "module missing" << std::endl
;
981 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
983 if (!bExtensionMode
&& lang
.empty())
985 std::stringstream aStrStream
;
986 aStrStream
<< "language missing" << std::endl
;
987 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
989 if (!bExtensionMode
&& hid
.empty())
991 std::stringstream aStrStream
;
992 aStrStream
<< "hid list missing" << std::endl
;
993 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR
, aStrStream
.str() );
999 int main(int argc
, char**argv
)
1001 sal_uInt32 starttime
= osl_getGlobalTimer();
1002 std::vector
<std::string
> args
;
1003 for (int i
= 1; i
< argc
; ++i
)
1004 args
.push_back(std::string(argv
[i
]));
1007 HelpLinker
* pHelpLinker
= new HelpLinker();
1008 pHelpLinker
->main( args
);
1011 catch( const HelpProcessingException
& e
)
1013 std::cerr
<< e
.m_aErrorMsg
;
1016 sal_uInt32 endtime
= osl_getGlobalTimer();
1017 std::cout
<< "time taken was " << (endtime
-starttime
)/1000.0 << " seconds" << std::endl
;
1021 // Variable to set an exception in "C" StructuredXMLErrorFunction
1022 static const HelpProcessingException
* GpXMLParsingException
= NULL
;
1024 extern "C" void StructuredXMLErrorFunction(void *userData
, xmlErrorPtr error
)
1029 std::string aErrorMsg
= error
->message
;
1030 std::string aXMLParsingFile
;
1031 if( error
->file
!= NULL
)
1032 aXMLParsingFile
= error
->file
;
1033 int nXMLParsingLine
= error
->line
;
1034 HelpProcessingException
* pException
= new HelpProcessingException( aErrorMsg
, aXMLParsingFile
, nXMLParsingLine
);
1035 GpXMLParsingException
= pException
;
1037 // Reset error handler
1038 xmlSetStructuredErrorFunc( NULL
, NULL
);
1041 HelpProcessingErrorInfo
& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException
& e
)
1043 m_eErrorClass
= e
.m_eErrorClass
;
1044 rtl::OString
tmpErrorMsg( e
.m_aErrorMsg
.c_str() );
1045 m_aErrorMsg
= rtl::OStringToOUString( tmpErrorMsg
, fs::getThreadTextEncoding() );
1046 rtl::OString
tmpXMLParsingFile( e
.m_aXMLParsingFile
.c_str() );
1047 m_aXMLParsingFile
= rtl::OStringToOUString( tmpXMLParsingFile
, fs::getThreadTextEncoding() );
1048 m_nXMLParsingLine
= e
.m_nXMLParsingLine
;
1053 // Returns true in case of success, false in case of error
1054 HELPLINKER_DLLPUBLIC
bool compileExtensionHelp
1056 const rtl::OUString
& aExtensionName
,
1057 const rtl::OUString
& aExtensionLanguageRoot
,
1058 sal_Int32 nXhpFileCount
, const rtl::OUString
* pXhpFiles
,
1059 HelpProcessingErrorInfo
& o_rHelpProcessingErrorInfo
1062 bool bSuccess
= true;
1064 sal_Int32 argc
= nXhpFileCount
+ 3;
1065 const char** argv
= new const char*[argc
];
1068 rtl::OString aOExtensionName
= rtl::OUStringToOString( aExtensionName
, fs::getThreadTextEncoding() );
1069 argv
[2] = aOExtensionName
.getStr();
1071 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
1073 rtl::OUString aXhpFile
= pXhpFiles
[iXhp
];
1075 rtl::OString aOXhpFile
= rtl::OUStringToOString( aXhpFile
, fs::getThreadTextEncoding() );
1076 char* pArgStr
= new char[aOXhpFile
.getLength() + 1];
1077 strcpy( pArgStr
, aOXhpFile
.getStr() );
1078 argv
[iXhp
+ 3] = pArgStr
;
1081 std::vector
<std::string
> args
;
1082 for( sal_Int32 i
= 1; i
< argc
; ++i
)
1083 args
.push_back(std::string( argv
[i
]) );
1085 for( sal_Int32 iXhp
= 0 ; iXhp
< nXhpFileCount
; ++iXhp
)
1086 delete argv
[iXhp
+ 3];
1089 rtl::OString aOExtensionLanguageRoot
= rtl::OUStringToOString( aExtensionLanguageRoot
, fs::getThreadTextEncoding() );
1090 const char* pExtensionPath
= aOExtensionLanguageRoot
.getStr();
1091 std::string aStdStrExtensionPath
= pExtensionPath
;
1093 // Set error handler
1094 xmlSetStructuredErrorFunc( NULL
, (xmlStructuredErrorFunc
)StructuredXMLErrorFunction
);
1097 HelpLinker
* pHelpLinker
= new HelpLinker();
1098 pHelpLinker
->main( args
,&aStdStrExtensionPath
);
1101 catch( const HelpProcessingException
& e
)
1103 if( GpXMLParsingException
!= NULL
)
1105 o_rHelpProcessingErrorInfo
= *GpXMLParsingException
;
1106 delete GpXMLParsingException
;
1107 GpXMLParsingException
= NULL
;
1111 o_rHelpProcessingErrorInfo
= e
;
1115 // Reset error handler
1116 xmlSetStructuredErrorFunc( NULL
, NULL
);
1118 // i83624: Tree files
1119 ::rtl::OUString aTreeFileURL
= aExtensionLanguageRoot
;
1120 aTreeFileURL
+= rtl::OUString::createFromAscii( "/help.tree" );
1121 osl::DirectoryItem aTreeFileItem
;
1122 osl::FileBase::RC rcGet
= osl::DirectoryItem::get( aTreeFileURL
, aTreeFileItem
);
1123 osl::FileStatus
aFileStatus( FileStatusMask_FileSize
);
1124 if( rcGet
== osl::FileBase::E_None
&&
1125 aTreeFileItem
.getFileStatus( aFileStatus
) == osl::FileBase::E_None
&&
1126 aFileStatus
.isValid( FileStatusMask_FileSize
) )
1128 sal_uInt64 ret
, len
= aFileStatus
.getFileSize();
1129 char* s
= new char[ int(len
) ]; // the buffer to hold the installed files
1130 osl::File
aFile( aTreeFileURL
);
1131 aFile
.open( OpenFlag_Read
);
1132 aFile
.read( s
, len
, ret
);
1135 XML_Parser parser
= XML_ParserCreate( 0 );
1136 int parsed
= XML_Parse( parser
, s
, int( len
), true );
1140 XML_Error nError
= XML_GetErrorCode( parser
);
1141 o_rHelpProcessingErrorInfo
.m_eErrorClass
= HELPPROCESSING_XMLPARSING_ERROR
;
1142 o_rHelpProcessingErrorInfo
.m_aErrorMsg
= rtl::OUString::createFromAscii( XML_ErrorString( nError
) );;
1143 o_rHelpProcessingErrorInfo
.m_aXMLParsingFile
= aTreeFileURL
;
1144 // CRAHSES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser );
1148 XML_ParserFree( parser
);
1155 // vnd.sun.star.help://swriter/52821?Language=en-US&System=UNIX
1156 /* vi:set tabstop=4 shiftwidth=4 expandtab: */