merge the formfield patch from ooo-build
[ooovba.git] / transex3 / source / help / HelpLinker.cxx
blob357f05aeb595b61979f1cc27ef137b176d7a788e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: HelpLinker.cxx,v $
10 * $Revision: 1.16 $
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"
33 #include <map>
35 #include <string.h>
36 #include <limits.h>
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>
45 #include <osl/time.h>
46 #include <rtl/bootstrap.hxx>
48 #ifdef SYSTEM_EXPAT
49 #include <expat.h>
50 #else
51 #include <expat/xmlparse.h>
52 #endif
54 #define DBHELP_ONLY
57 class IndexerPreProcessor
59 private:
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;
68 public:
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" );
128 if( pFile_docURL )
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" );
143 if( pFile_docURL )
145 fprintf( pFile_docURL, "%s\n", pResNodeContent->content );
146 fclose( pFile_docURL );
149 xmlFreeDoc(resContent);
152 struct Data
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
164 std::string ret;
165 cIter aEnd = _idList.end();
166 for (cIter aIter = _idList.begin(); aIter != aEnd; ++aIter)
167 ret += *aIter + ";";
168 return ret;
172 void writeKeyValue_DBHelp( FILE* pFile, const std::string& aKeyStr, const std::string& aValueStr )
174 if( pFile == NULL )
175 return;
176 char cLF = 10;
177 int nKeyLen = aKeyStr.length();
178 int nValueLen = aValueStr.length();
179 fprintf( pFile, "%x ", nKeyLen );
180 if( nKeyLen > 0 )
181 fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile );
182 fprintf( pFile, " %x ", nValueLen );
183 if( nValueLen > 0 )
184 fwrite( aValueStr.c_str(), 1, nValueLen, pFile );
185 fprintf( pFile, "%c", cLF );
188 class HelpKeyword
190 private:
191 typedef std::hash_map<std::string, Data, pref_hash> DataHashtable;
192 DataHashtable _hash;
194 public:
195 void insert(const std::string &key, const std::string &id)
197 Data &data = _hash[key];
198 data.append(id);
201 void dump(DB* table)
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;
207 DBT key;
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();
214 DBT value;
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" );
226 if( pFile == NULL )
227 return;
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() );
233 fclose( pFile );
237 class HelpLinker
239 public:
240 void main(std::vector<std::string> &args, std::string* pExtensionPath = NULL )
241 throw( HelpProcessingException );
243 HelpLinker()
244 : init(true)
245 , m_pIndexerPreProcessor(NULL)
247 ~HelpLinker()
248 { delete m_pIndexerPreProcessor; }
250 private:
251 int locCount, totCount;
252 Stringtable additionalFiles;
253 HashSet helpFiles;
254 fs::path sourceRoot;
255 fs::path embeddStylesheet;
256 fs::path idxCaptionStylesheet;
257 fs::path idxContentStylesheet;
258 fs::path zipdir;
259 fs::path outputFile;
260 std::string module;
261 std::string lang;
262 std::string hid;
263 std::string extensionPath;
264 bool bExtensionMode;
265 fs::path indexDirName;
266 Stringtable hidlistTranslation;
267 fs::path indexDirParentName;
268 bool init;
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 );
275 #if 0
277 * @param outputFile
278 * @param module
279 * @param lang
280 * @param hid
281 * @param helpFiles
282 * @param additionalFiles
285 private HelpURLStreamHandlerFactory urlHandler = null;
286 #endif
289 namespace URLEncoder
291 static std::string encode(const std::string &rIn)
293 const char *good = "!$&'()*+,-.=@_";
294 static const char hex[17] = "0123456789ABCDEF";
296 std::string result;
297 for (size_t i=0; i < rIn.length(); ++i)
299 unsigned char c = rIn[i];
300 if (isalnum (c) || strchr (good, c))
301 result += c;
302 else {
303 result += '%';
304 result += hex[c >> 4];
305 result += hex[c & 0xf];
308 return result;
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);
328 DBT key;
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);
339 size_t i = 0;
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())
345 dataB[i++] = '#';
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];
357 DBT data;
358 memset(&data, 0, sizeof(data));
359 data.data = &dataB[0];
360 data.size = dataB.size();
362 if( dbBase != NULL )
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;
389 if( bExtensionMode )
391 indexDirParentName = sourceRoot;
393 else
395 indexDirParentName = zipdir;
396 fs::create_directory(indexDirParentName);
399 #ifdef CMC_DEBUG
400 std::cerr << "will not delete tmpdir of " << indexDirParentName.native_file_string().c_str() << std::endl;
401 #endif
403 std::string mod = module;
404 std::transform (mod.begin(), mod.end(), mod.begin(), tolower);
406 // do the work here
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;
410 if (appl[0] == 's')
411 appl = appl.substr(1);
413 bool bUse_ = true;
414 #ifdef DBHELP_ONLY
415 if( !bExtensionMode )
416 bUse_ = false;
417 #endif
419 DB* helpText(0);
420 #ifndef DBHELP_ONLY
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);
425 #endif
427 fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht")));
428 FILE* pFileHelpText_DBHelp = fopen
429 ( helpTextFileName_DBHelp.native_file_string().c_str(), "wb" );
431 DB* dbBase(0);
432 #ifndef DBHELP_ONLY
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);
437 #endif
439 fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db")));
440 FILE* pFileDbBase_DBHelp = fopen
441 ( dbBaseFileName_DBHelp.native_file_string().c_str(), "wb" );
443 #ifndef DBHELP_ONLY
444 DB* keyWord(0);
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);
449 #endif
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());
460 while (fileReader)
462 std::string key;
463 fileReader >> key;
464 std::transform (key.begin(), key.end(), key.begin(), toupper);
465 std::replace(key.begin(), key.end(), ':', '_');
466 std::string data;
467 fileReader >> data;
468 if (!key.empty() && !data.empty())
469 hidlistTranslation[key] = data;
471 fileReader.close();
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 )
489 std::cout << ".";
490 std::cout.flush();
493 // process one file
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
501 std::cerr <<
502 "ERROR: input list entry '"
503 << xhpFileName
504 << "' has the wrong extension (only files with extension .xhp "
505 << "are accepted)";
506 continue;
509 fs::path langsourceRoot(sourceRoot);
510 fs::path xhpFile;
512 if( bExtensionMode )
514 // langsourceRoot == sourceRoot for extensions
515 std::string xhpFileNameComplete( extensionPath );
516 xhpFileNameComplete.append( '/' + xhpFileName );
517 xhpFile = fs::path( xhpFileNameComplete );
519 else
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;
535 aStrStream <<
536 "\nERROR: compiling help particle '"
537 << xhpFileName
538 << "' for language '"
539 << lang
540 << "' failed!";
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>";
555 #if 0
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";
560 #endif
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;
574 if (!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;
585 std::string anchorB;
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);
596 // now the keywords
597 const Hashtable *anchorToLL = streamTable.appl_keywords;
598 if (!anchorToLL)
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;
625 if (!helpTextHash)
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];
641 if (!tHid.empty())
642 helpTextId = tHid;
643 helpTextId = URLEncoder::encode(helpTextId);
645 DBT keyDbt;
646 memset(&keyDbt, 0, sizeof(keyDbt));
647 keyDbt.data = const_cast<char*>(helpTextId.c_str());
648 keyDbt.size = helpTextId.length();
650 DBT textDbt;
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 )
666 // now the indexing
667 xmlDocPtr document = streamTable.appl_doc;
668 if (!document)
669 document = streamTable.default_doc;
670 if (document)
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;
682 } // try
683 catch( HelpProcessingException& )
685 // catch HelpProcessingException to avoid locking data bases
686 #ifndef DBHELP_ONLY
687 helpText->close(helpText, 0);
688 dbBase->close(dbBase, 0);
689 keyWord->close(keyWord, 0);
690 #endif
691 if( pFileHelpText_DBHelp != NULL )
692 fclose( pFileHelpText_DBHelp );
693 if( pFileDbBase_DBHelp != NULL )
694 fclose( pFileDbBase_DBHelp );
695 throw;
698 #ifndef DBHELP_ONLY
699 helpText->close(helpText, 0);
700 dbBase->close(dbBase, 0);
701 helpKeyword.dump(keyWord);
702 keyWord->close(keyWord, 0);
703 #endif
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 )
713 // New index
714 Stringtable::iterator aEnd = additionalFiles.end();
715 for (Stringtable::iterator enumer = additionalFiles.begin(); enumer != aEnd;
716 ++enumer)
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();
724 std::cerr << pStr;
726 fs::path fsTargetName( indexDirParentName / additionalFileKey );
728 fs::copy( fsAdditionalFileName, fsTargetName );
733 /////////////////////////////////////////////////////////////////////////
734 /// remove temprary directory for index creation
735 /////////////////////////////////////////////////////////////////////////
736 #ifndef CMC_DEBUG
737 if( !bExtensionMode )
738 fs::remove_all( indexDirParentName );
739 #endif
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 )
752 helpFiles.clear();
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;
763 std::string strBuf;
764 std::ifstream fileReader(args[0].substr(1).c_str());
766 while (fileReader)
768 std::string token;
769 fileReader >> token;
770 if (!token.empty())
771 stringList.push_back(token);
773 fileReader.close();
775 args = stringList;
778 size_t i = 0;
780 while (i < args.size())
782 if (args[i].compare("-src") == 0)
784 ++i;
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)
797 ++i;
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)
809 ++i;
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)
821 ++i;
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)
833 ++i;
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)
845 ++i;
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)
857 ++i;
858 if (i >= args.size())
860 std::stringstream aStrStream;
861 aStrStream << "module name missing" << std::endl;
862 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
865 module = args[i];
867 else if (args[i].compare("-lang") == 0)
869 ++i;
870 if (i >= args.size())
872 std::stringstream aStrStream;
873 aStrStream << "language name missing" << std::endl;
874 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
877 lang = args[i];
879 else if (args[i].compare("-hid") == 0)
881 ++i;
882 if (i >= args.size())
884 std::stringstream aStrStream;
885 aStrStream << "hid list missing" << std::endl;
886 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
889 hid = args[i];
891 else if (args[i].compare("-add") == 0)
893 std::string addFile, addFileUnderPath;
894 ++i;
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];
903 ++i;
904 if (i >= args.size())
906 std::stringstream aStrStream;
907 aStrStream << "pathname missing" << std::endl;
908 throw HelpProcessingException( HELPPROCESSING_GENERAL_ERROR, aStrStream.str() );
910 addFile = args[i];
911 if (!addFileUnderPath.empty() && !addFile.empty())
912 additionalFiles[addFileUnderPath] = addFile;
914 else
915 helpFiles.push_back(args[i]);
916 ++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() );
977 if (module.empty())
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() );
996 link();
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 );
1009 delete pHelpLinker;
1011 catch( const HelpProcessingException& e )
1013 std::cerr << e.m_aErrorMsg;
1014 exit(1);
1016 sal_uInt32 endtime = osl_getGlobalTimer();
1017 std::cout << "time taken was " << (endtime-starttime)/1000.0 << " seconds" << std::endl;
1018 return 0;
1021 // Variable to set an exception in "C" StructuredXMLErrorFunction
1022 static const HelpProcessingException* GpXMLParsingException = NULL;
1024 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error)
1026 (void)userData;
1027 (void)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;
1049 return *this;
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];
1066 argv[0] = "";
1067 argv[1] = "-mod";
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];
1087 delete[] argv;
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 );
1099 delete pHelpLinker;
1101 catch( const HelpProcessingException& e )
1103 if( GpXMLParsingException != NULL )
1105 o_rHelpProcessingErrorInfo = *GpXMLParsingException;
1106 delete GpXMLParsingException;
1107 GpXMLParsingException = NULL;
1109 else
1111 o_rHelpProcessingErrorInfo = e;
1113 bSuccess = false;
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 );
1133 aFile.close();
1135 XML_Parser parser = XML_ParserCreate( 0 );
1136 int parsed = XML_Parse( parser, s, int( len ), true );
1138 if( parsed == 0 )
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 );
1145 bSuccess = false;
1148 XML_ParserFree( parser );
1149 delete[] s;
1152 return bSuccess;
1155 // vnd.sun.star.help://swriter/52821?Language=en-US&System=UNIX
1156 /* vi:set tabstop=4 shiftwidth=4 expandtab: */