File: | home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx |
Warning: | line 748, column 43 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <HelpCompiler.hxx> | |||
21 | #include <HelpLinker.hxx> | |||
22 | ||||
23 | #include <algorithm> | |||
24 | #include <fstream> | |||
25 | ||||
26 | #include <string.h> | |||
27 | ||||
28 | #include <libxslt/transform.h> | |||
29 | ||||
30 | #include <sal/types.h> | |||
31 | #include <o3tl/char16_t2wchar_t.hxx> | |||
32 | #include <sal/log.hxx> | |||
33 | ||||
34 | #include <expat.h> | |||
35 | #include <memory> | |||
36 | ||||
37 | namespace { | |||
38 | FILE* fopen_impl(const fs::path& rPath, const char* szMode) | |||
39 | { | |||
40 | #ifdef _WIN32 //We need _wfopen to support long file paths on Windows XP | |||
41 | return _wfopen(rPath.native_file_string_w().c_str(), o3tl::toW(OUString::createFromAscii(szMode).getStr())); | |||
42 | #else | |||
43 | return fopen(rPath.native_file_string().c_str(), szMode); | |||
44 | #endif | |||
45 | } | |||
46 | } | |||
47 | ||||
48 | IndexerPreProcessor::IndexerPreProcessor | |||
49 | ( const fs::path& fsIndexBaseDir, | |||
50 | const fs::path& idxCaptionStylesheet, const fs::path& idxContentStylesheet ) | |||
51 | { | |||
52 | m_fsCaptionFilesDirName = fsIndexBaseDir / "caption"; | |||
53 | fs::create_directory( m_fsCaptionFilesDirName ); | |||
54 | ||||
55 | m_fsContentFilesDirName = fsIndexBaseDir / "content"; | |||
56 | fs::create_directory( m_fsContentFilesDirName ); | |||
57 | ||||
58 | m_xsltStylesheetPtrCaption = xsltParseStylesheetFile | |||
59 | (reinterpret_cast<const xmlChar *>(idxCaptionStylesheet.native_file_string().c_str())); | |||
60 | m_xsltStylesheetPtrContent = xsltParseStylesheetFile | |||
61 | (reinterpret_cast<const xmlChar *>(idxContentStylesheet.native_file_string().c_str())); | |||
62 | } | |||
63 | ||||
64 | IndexerPreProcessor::~IndexerPreProcessor() | |||
65 | { | |||
66 | if( m_xsltStylesheetPtrCaption ) | |||
67 | xsltFreeStylesheet( m_xsltStylesheetPtrCaption ); | |||
68 | if( m_xsltStylesheetPtrContent ) | |||
69 | xsltFreeStylesheet( m_xsltStylesheetPtrContent ); | |||
70 | } | |||
71 | ||||
72 | static std::string getEncodedPath( const std::string& Path ) | |||
73 | { | |||
74 | OString aOStr_Path( Path.c_str() ); | |||
75 | OUString aOUStr_Path( OStringToOUString | |||
76 | ( aOStr_Path, osl_getThreadTextEncoding() ) ); | |||
77 | OUString aPathURL; | |||
78 | osl::File::getFileURLFromSystemPath( aOUStr_Path, aPathURL ); | |||
79 | OString aOStr_PathURL( OUStringToOString | |||
80 | ( aPathURL, osl_getThreadTextEncoding() ) ); | |||
81 | std::string aStdStr_PathURL( aOStr_PathURL.getStr() ); | |||
82 | return aStdStr_PathURL; | |||
83 | } | |||
84 | ||||
85 | void IndexerPreProcessor::processDocument | |||
86 | ( xmlDocPtr doc, const std::string &EncodedDocPath ) | |||
87 | { | |||
88 | std::string aStdStr_EncodedDocPathURL = getEncodedPath( EncodedDocPath ); | |||
89 | ||||
90 | if( m_xsltStylesheetPtrCaption ) | |||
91 | { | |||
92 | xmlDocPtr resCaption = xsltApplyStylesheet( m_xsltStylesheetPtrCaption, doc, nullptr ); | |||
93 | xmlNodePtr pResNodeCaption = resCaption->xmlChildrenNodechildren; | |||
94 | if( pResNodeCaption ) | |||
95 | { | |||
96 | fs::path fsCaptionPureTextFile_docURL = m_fsCaptionFilesDirName / aStdStr_EncodedDocPathURL; | |||
97 | FILE* pFile_docURL = fopen_impl( fsCaptionPureTextFile_docURL, "w" ); | |||
98 | if( pFile_docURL ) | |||
99 | { | |||
100 | fprintf( pFile_docURL, "%s\n", pResNodeCaption->content ); | |||
101 | fclose( pFile_docURL ); | |||
102 | } | |||
103 | } | |||
104 | xmlFreeDoc(resCaption); | |||
105 | } | |||
106 | ||||
107 | if( !m_xsltStylesheetPtrContent ) | |||
108 | return; | |||
109 | ||||
110 | xmlDocPtr resContent = xsltApplyStylesheet( m_xsltStylesheetPtrContent, doc, nullptr ); | |||
111 | xmlNodePtr pResNodeContent = resContent->xmlChildrenNodechildren; | |||
112 | if( pResNodeContent ) | |||
113 | { | |||
114 | fs::path fsContentPureTextFile_docURL = m_fsContentFilesDirName / aStdStr_EncodedDocPathURL; | |||
115 | FILE* pFile_docURL = fopen_impl( fsContentPureTextFile_docURL, "w" ); | |||
116 | if( pFile_docURL ) | |||
117 | { | |||
118 | fprintf( pFile_docURL, "%s\n", pResNodeContent->content ); | |||
119 | fclose( pFile_docURL ); | |||
120 | } | |||
121 | } | |||
122 | xmlFreeDoc(resContent); | |||
123 | } | |||
124 | ||||
125 | namespace { | |||
126 | ||||
127 | struct Data | |||
128 | { | |||
129 | std::vector<std::string> _idList; | |||
130 | ||||
131 | void append(const std::string &id) | |||
132 | { | |||
133 | _idList.push_back(id); | |||
134 | } | |||
135 | ||||
136 | std::string getString() const | |||
137 | { | |||
138 | std::string ret; | |||
139 | for (auto const& elem : _idList) | |||
140 | ret += elem + ";"; | |||
141 | return ret; | |||
142 | } | |||
143 | }; | |||
144 | ||||
145 | } | |||
146 | ||||
147 | static void writeKeyValue_DBHelp( FILE* pFile, const std::string& aKeyStr, const std::string& aValueStr ) | |||
148 | { | |||
149 | if( pFile == nullptr ) | |||
150 | return; | |||
151 | char const cLF = 10; | |||
152 | unsigned int nKeyLen = aKeyStr.length(); | |||
153 | unsigned int nValueLen = aValueStr.length(); | |||
154 | fprintf( pFile, "%x ", nKeyLen ); | |||
155 | if( nKeyLen > 0 ) | |||
156 | { | |||
157 | if (fwrite( aKeyStr.c_str(), 1, nKeyLen, pFile ) != nKeyLen) | |||
158 | fprintf(stderrstderr, "fwrite to db failed\n"); | |||
159 | } | |||
160 | if (fprintf( pFile, " %x ", nValueLen ) < 0) | |||
161 | fprintf(stderrstderr, "fwrite to db failed\n"); | |||
162 | if( nValueLen > 0 ) | |||
163 | { | |||
164 | if (fwrite( aValueStr.c_str(), 1, nValueLen, pFile ) != nValueLen) | |||
165 | fprintf(stderrstderr, "fwrite to db failed\n"); | |||
166 | } | |||
167 | if (fprintf( pFile, "%c", cLF ) < 0) | |||
168 | fprintf(stderrstderr, "fwrite to db failed\n"); | |||
169 | } | |||
170 | ||||
171 | namespace { | |||
172 | ||||
173 | class HelpKeyword | |||
174 | { | |||
175 | private: | |||
176 | typedef std::unordered_map<std::string, Data> DataHashtable; | |||
177 | DataHashtable _hash; | |||
178 | ||||
179 | public: | |||
180 | void insert(const std::string &key, const std::string &id) | |||
181 | { | |||
182 | Data &data = _hash[key]; | |||
183 | data.append(id); | |||
184 | } | |||
185 | ||||
186 | void dump_DBHelp( const fs::path& rFileName ) | |||
187 | { | |||
188 | FILE* pFile = fopen_impl( rFileName, "wb" ); | |||
189 | if( pFile == nullptr ) | |||
190 | return; | |||
191 | ||||
192 | for (auto const& elem : _hash) | |||
193 | writeKeyValue_DBHelp( pFile, elem.first, elem.second.getString() ); | |||
194 | ||||
195 | fclose( pFile ); | |||
196 | } | |||
197 | }; | |||
198 | ||||
199 | } | |||
200 | ||||
201 | namespace URLEncoder | |||
202 | { | |||
203 | static std::string encode(const std::string &rIn) | |||
204 | { | |||
205 | const char * const good = "!$&'()*+,-.=@_"; | |||
206 | static const char hex[17] = "0123456789ABCDEF"; | |||
207 | ||||
208 | std::string result; | |||
209 | for (char c : rIn) | |||
210 | { | |||
211 | if (rtl::isAsciiAlphanumeric (static_cast<unsigned char>(c)) | |||
212 | || strchr (good, c)) | |||
213 | { | |||
214 | result += c; | |||
215 | } else { | |||
216 | result += '%'; | |||
217 | result += hex[static_cast<unsigned char>(c) >> 4]; | |||
218 | result += hex[c & 0xf]; | |||
219 | } | |||
220 | } | |||
221 | return result; | |||
222 | } | |||
223 | } | |||
224 | ||||
225 | void HelpLinker::addBookmark( FILE* pFile_DBHelp, std::string thishid, | |||
226 | const std::string& fileB, const std::string& anchorB, | |||
227 | const std::string& jarfileB, const std::string& titleB) | |||
228 | { | |||
229 | HCDBG(std::cerr << "HelpLinker::addBookmark " << thishid << " " <<do { } while(false) | |||
230 | fileB << " " << anchorB << " " << jarfileB << " " << titleB << std::endl)do { } while(false); | |||
231 | ||||
232 | thishid = URLEncoder::encode(thishid); | |||
233 | ||||
234 | int fileLen = fileB.length(); | |||
235 | if (!anchorB.empty()) | |||
236 | fileLen += (1 + anchorB.length()); | |||
237 | int dataLen = 1 + fileLen + 1 + jarfileB.length() + 1 + titleB.length(); | |||
238 | ||||
239 | std::vector<unsigned char> dataB(dataLen); | |||
240 | size_t i = 0; | |||
241 | dataB[i++] = static_cast<unsigned char>(fileLen); | |||
242 | for (char j : fileB) | |||
243 | dataB[i++] = static_cast<unsigned char>(j); | |||
244 | if (!anchorB.empty()) | |||
245 | { | |||
246 | dataB[i++] = '#'; | |||
247 | for (char j : anchorB) | |||
248 | dataB[i++] = j; | |||
249 | } | |||
250 | dataB[i++] = static_cast<unsigned char>(jarfileB.length()); | |||
251 | for (char j : jarfileB) | |||
252 | dataB[i++] = j; | |||
253 | ||||
254 | dataB[i++] = static_cast<unsigned char>(titleB.length()); | |||
255 | for (char j : titleB) | |||
256 | dataB[i++] = j; | |||
257 | ||||
258 | if( pFile_DBHelp != nullptr ) | |||
259 | { | |||
260 | std::string aValueStr( dataB.begin(), dataB.end() ); | |||
261 | writeKeyValue_DBHelp( pFile_DBHelp, thishid, aValueStr ); | |||
262 | } | |||
263 | } | |||
264 | ||||
265 | void HelpLinker::initIndexerPreProcessor() | |||
266 | { | |||
267 | m_pIndexerPreProcessor.reset( new IndexerPreProcessor( indexDirParentName, | |||
268 | idxCaptionStylesheet, idxContentStylesheet ) ); | |||
269 | } | |||
270 | ||||
271 | void HelpLinker::link() | |||
272 | { | |||
273 | ||||
274 | if( bExtensionMode ) | |||
275 | { | |||
276 | indexDirParentName = extensionDestination; | |||
277 | } | |||
278 | else | |||
279 | { | |||
280 | indexDirParentName = zipdir; | |||
281 | fs::create_directory(indexDirParentName); | |||
282 | } | |||
283 | ||||
284 | std::string mod = module; | |||
285 | std::transform (mod.begin(), mod.end(), mod.begin(), tocharlower); | |||
286 | ||||
287 | // do the work here | |||
288 | // continue with introduction of the overall process thing into the | |||
289 | // here all hzip files will be worked on | |||
290 | bool bUse_ = true; | |||
291 | if( !bExtensionMode ) | |||
292 | bUse_ = false; | |||
293 | ||||
294 | fs::path helpTextFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".ht_" : ".ht"))); | |||
295 | FILE* pFileHelpText_DBHelp = fopen_impl( helpTextFileName_DBHelp, "wb" ); | |||
296 | ||||
297 | fs::path dbBaseFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".db_" : ".db"))); | |||
298 | FILE* pFileDbBase_DBHelp = fopen_impl( dbBaseFileName_DBHelp, "wb" ); | |||
299 | ||||
300 | fs::path keyWordFileName_DBHelp(indexDirParentName / (mod + (bUse_ ? ".key_" : ".key"))); | |||
301 | ||||
302 | HelpKeyword helpKeyword; | |||
303 | ||||
304 | // catch HelpProcessingException to avoid locking data bases | |||
305 | try | |||
306 | { | |||
307 | bool bIndexForExtension = true; | |||
308 | // lastly, initialize the indexBuilder | |||
309 | if ( (!bExtensionMode || bIndexForExtension) && !helpFiles.empty()) | |||
310 | initIndexerPreProcessor(); | |||
311 | ||||
312 | // here we start our loop over the hzip files. | |||
313 | for (auto const& helpFile : helpFiles) | |||
314 | { | |||
315 | // process one file | |||
316 | // streamTable contains the streams in the hzip file | |||
317 | StreamTable streamTable; | |||
318 | const std::string &xhpFileName = helpFile; | |||
319 | ||||
320 | if (!bExtensionMode && xhpFileName.rfind(".xhp") != xhpFileName.length()-4) | |||
321 | { | |||
322 | // only work on .xhp - files | |||
323 | SAL_WARN("helpcompiler",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "helpcompiler")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
324 | "ERROR: input list entry '"do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "helpcompiler")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
325 | << xhpFileNamedo { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "helpcompiler")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
326 | << "' has the wrong extension (only files with extension .xhp are accepted)")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "helpcompiler")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ERROR: input list entry '" << xhpFileName << "' has the wrong extension (only files with extension .xhp are accepted)" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("helpcompiler" ), ("/home/maarten/src/libreoffice/core/helpcompiler/source/HelpLinker.cxx" ":" "326" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
327 | ||||
328 | continue; | |||
329 | } | |||
330 | ||||
331 | fs::path langsourceRoot(sourceRoot); | |||
332 | fs::path xhpFile; | |||
333 | ||||
334 | if( bExtensionMode ) | |||
335 | { | |||
336 | // langsourceRoot == sourceRoot for extensions | |||
337 | std::string xhpFileNameComplete( extensionPath ); | |||
338 | xhpFileNameComplete.append( '/' + xhpFileName ); | |||
339 | xhpFile = fs::path( xhpFileNameComplete ); | |||
340 | } | |||
341 | else | |||
342 | { | |||
343 | langsourceRoot.append( "/" ); | |||
344 | if ( m_bUseLangRoot ) | |||
345 | langsourceRoot.append( lang + '/' ); | |||
346 | xhpFile = fs::path(xhpFileName, fs::native); | |||
347 | } | |||
348 | ||||
349 | HelpCompiler hc( streamTable, xhpFile, langsourceRoot, zipdir, | |||
350 | compactStylesheet, embeddStylesheet, module, lang, bExtensionMode ); | |||
351 | ||||
352 | HCDBG(std::cerr << "before compile of " << xhpFileName << std::endl)do { } while(false); | |||
353 | hc.compile(); | |||
354 | HCDBG(std::cerr << "after compile of " << xhpFileName << std::endl)do { } while(false); | |||
355 | ||||
356 | if (!m_bCreateIndex) | |||
357 | continue; | |||
358 | ||||
359 | std::string documentPath = streamTable.document_path; | |||
360 | if (documentPath.compare(0, 1, "/") == 0) | |||
361 | documentPath = documentPath.substr(1); | |||
362 | ||||
363 | std::string documentJarfile = streamTable.document_module + ".jar"; | |||
364 | ||||
365 | std::string documentTitle = streamTable.document_title; | |||
366 | if (documentTitle.empty()) | |||
367 | documentTitle = "<notitle>"; | |||
368 | ||||
369 | const std::string& fileB = documentPath; | |||
370 | const std::string& jarfileB = documentJarfile; | |||
371 | std::string& titleB = documentTitle; | |||
372 | ||||
373 | // add once this as its own id. | |||
374 | addBookmark( pFileDbBase_DBHelp, documentPath, fileB, std::string(), jarfileB, titleB); | |||
375 | ||||
376 | const std::vector<std::string> *hidlist = streamTable.appl_hidlist.get(); | |||
377 | if (hidlist) | |||
378 | { | |||
379 | // now iterate over all elements of the hidlist | |||
380 | for (auto & elem : *hidlist) | |||
381 | { | |||
382 | std::string thishid = elem; | |||
383 | ||||
384 | std::string anchorB; | |||
385 | size_t index = thishid.rfind('#'); | |||
386 | if (index != std::string::npos) | |||
387 | { | |||
388 | anchorB = thishid.substr(1 + index); | |||
389 | thishid = thishid.substr(0, index); | |||
390 | } | |||
391 | addBookmark( pFileDbBase_DBHelp, thishid, fileB, anchorB, jarfileB, titleB); | |||
392 | } | |||
393 | } | |||
394 | ||||
395 | // now the keywords | |||
396 | const Hashtable *anchorToLL = streamTable.appl_keywords.get(); | |||
397 | if (anchorToLL && !anchorToLL->empty()) | |||
398 | { | |||
399 | std::string fakedHid = URLEncoder::encode(documentPath); | |||
400 | for (auto const& elemAnchor : *anchorToLL) | |||
401 | { | |||
402 | const std::string &anchor = elemAnchor.first; | |||
403 | addBookmark(pFileDbBase_DBHelp, documentPath, fileB, | |||
404 | anchor, jarfileB, titleB); | |||
405 | std::string totalId = fakedHid + "#" + anchor; | |||
406 | // std::cerr << hzipFileName << std::endl; | |||
407 | const LinkedList& ll = elemAnchor.second; | |||
408 | for (auto const& elem : ll) | |||
409 | { | |||
410 | helpKeyword.insert(elem, totalId); | |||
411 | } | |||
412 | } | |||
413 | ||||
414 | } | |||
415 | ||||
416 | // and last the helptexts | |||
417 | const Stringtable *helpTextHash = streamTable.appl_helptexts.get(); | |||
418 | if (helpTextHash) | |||
419 | { | |||
420 | for (auto const& elem : *helpTextHash) | |||
421 | { | |||
422 | std::string helpTextId = elem.first; | |||
423 | const std::string& helpTextText = elem.second; | |||
424 | ||||
425 | helpTextId = URLEncoder::encode(helpTextId); | |||
426 | ||||
427 | if( pFileHelpText_DBHelp != nullptr ) | |||
428 | writeKeyValue_DBHelp( pFileHelpText_DBHelp, helpTextId, helpTextText ); | |||
429 | } | |||
430 | } | |||
431 | ||||
432 | //IndexerPreProcessor | |||
433 | if( !bExtensionMode || bIndexForExtension ) | |||
434 | { | |||
435 | // now the indexing | |||
436 | xmlDocPtr document = streamTable.appl_doc; | |||
437 | if (document) | |||
438 | { | |||
439 | std::string temp = module; | |||
440 | std::transform (temp.begin(), temp.end(), temp.begin(), tocharlower); | |||
441 | m_pIndexerPreProcessor->processDocument(document, URLEncoder::encode(documentPath) ); | |||
442 | } | |||
443 | } | |||
444 | ||||
445 | } | |||
446 | ||||
447 | } | |||
448 | catch( const HelpProcessingException& ) | |||
449 | { | |||
450 | // catch HelpProcessingException to avoid locking data bases | |||
451 | if( pFileHelpText_DBHelp != nullptr ) | |||
452 | fclose( pFileHelpText_DBHelp ); | |||
453 | if( pFileDbBase_DBHelp != nullptr ) | |||
454 | fclose( pFileDbBase_DBHelp ); | |||
455 | throw; | |||
456 | } | |||
457 | ||||
458 | if( pFileHelpText_DBHelp != nullptr ) | |||
459 | fclose( pFileHelpText_DBHelp ); | |||
460 | if( pFileDbBase_DBHelp != nullptr ) | |||
461 | fclose( pFileDbBase_DBHelp ); | |||
462 | ||||
463 | helpKeyword.dump_DBHelp( keyWordFileName_DBHelp); | |||
464 | ||||
465 | if( bExtensionMode ) | |||
466 | return; | |||
467 | ||||
468 | // New index | |||
469 | for (auto const& additionalFile : additionalFiles) | |||
470 | { | |||
471 | const std::string &additionalFileName = additionalFile.second; | |||
472 | const std::string &additionalFileKey = additionalFile.first; | |||
473 | ||||
474 | fs::path fsAdditionalFileName( additionalFileName, fs::native ); | |||
475 | HCDBG({do { } while(false) | |||
476 | std::string aNativeStr = fsAdditionalFileName.native_file_string();do { } while(false) | |||
477 | const char* pStr = aNativeStr.c_str();do { } while(false) | |||
478 | std::cerr << pStr << std::endl;do { } while(false) | |||
479 | })do { } while(false); | |||
480 | ||||
481 | fs::path fsTargetName( indexDirParentName / additionalFileKey ); | |||
482 | ||||
483 | fs::copy( fsAdditionalFileName, fsTargetName ); | |||
484 | } | |||
485 | } | |||
486 | ||||
487 | ||||
488 | void HelpLinker::main( std::vector<std::string> &args, | |||
489 | std::string const * pExtensionPath, std::string const * pDestination, | |||
490 | const OUString* pOfficeHelpPath ) | |||
491 | { | |||
492 | bExtensionMode = false; | |||
493 | helpFiles.clear(); | |||
494 | ||||
495 | if ((!args.empty()) && args[0][0] == '@') | |||
| ||||
496 | { | |||
497 | std::vector<std::string> stringList; | |||
498 | std::ifstream fileReader(args[0].substr(1).c_str()); | |||
499 | ||||
500 | while (fileReader) | |||
501 | { | |||
502 | std::string token; | |||
503 | fileReader >> token; | |||
504 | if (!token.empty()) | |||
505 | stringList.push_back(token); | |||
506 | } | |||
507 | fileReader.close(); | |||
508 | ||||
509 | args = stringList; | |||
510 | } | |||
511 | ||||
512 | size_t i = 0; | |||
513 | bool bSrcOption = false; | |||
514 | while (i < args.size()) | |||
515 | { | |||
516 | if (args[i].compare("-extlangsrc") == 0) | |||
517 | { | |||
518 | ++i; | |||
519 | if (i >= args.size()) | |||
520 | { | |||
521 | std::stringstream aStrStream; | |||
522 | aStrStream << "extension source missing" << std::endl; | |||
523 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
524 | } | |||
525 | extsource = args[i]; | |||
526 | } | |||
527 | else if (args[i].compare("-extlangdest") == 0) | |||
528 | { | |||
529 | //If this argument is not provided then the location provided in -extsource will | |||
530 | //also be the destination | |||
531 | ++i; | |||
532 | if (i >= args.size()) | |||
533 | { | |||
534 | std::stringstream aStrStream; | |||
535 | aStrStream << "extension destination missing" << std::endl; | |||
536 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
537 | } | |||
538 | extdestination = args[i]; | |||
539 | } | |||
540 | else if (args[i].compare("-src") == 0) | |||
541 | { | |||
542 | ++i; | |||
543 | if (i >= args.size()) | |||
544 | { | |||
545 | std::stringstream aStrStream; | |||
546 | aStrStream << "sourceroot missing" << std::endl; | |||
547 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
548 | } | |||
549 | bSrcOption = true; | |||
550 | sourceRoot = fs::path(args[i], fs::native); | |||
551 | } | |||
552 | else if (args[i].compare("-compact") == 0) | |||
553 | { | |||
554 | ++i; | |||
555 | if (i >= args.size()) | |||
556 | { | |||
557 | std::stringstream aStrStream; | |||
558 | aStrStream << "compactStylesheet missing" << std::endl; | |||
559 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
560 | } | |||
561 | ||||
562 | compactStylesheet = fs::path(args[i], fs::native); | |||
563 | } | |||
564 | else if (args[i].compare("-sty") == 0) | |||
565 | { | |||
566 | ++i; | |||
567 | if (i >= args.size()) | |||
568 | { | |||
569 | std::stringstream aStrStream; | |||
570 | aStrStream << "embeddingStylesheet missing" << std::endl; | |||
571 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
572 | } | |||
573 | ||||
574 | embeddStylesheet = fs::path(args[i], fs::native); | |||
575 | } | |||
576 | else if (args[i].compare("-zipdir") == 0) | |||
577 | { | |||
578 | ++i; | |||
579 | if (i >= args.size()) | |||
580 | { | |||
581 | std::stringstream aStrStream; | |||
582 | aStrStream << "idxtemp missing" << std::endl; | |||
583 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
584 | } | |||
585 | ||||
586 | zipdir = fs::path(args[i], fs::native); | |||
587 | } | |||
588 | else if (args[i].compare("-idxcaption") == 0) | |||
589 | { | |||
590 | ++i; | |||
591 | if (i >= args.size()) | |||
592 | { | |||
593 | std::stringstream aStrStream; | |||
594 | aStrStream << "idxcaption stylesheet missing" << std::endl; | |||
595 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
596 | } | |||
597 | ||||
598 | idxCaptionStylesheet = fs::path(args[i], fs::native); | |||
599 | } | |||
600 | else if (args[i].compare("-idxcontent") == 0) | |||
601 | { | |||
602 | ++i; | |||
603 | if (i >= args.size()) | |||
604 | { | |||
605 | std::stringstream aStrStream; | |||
606 | aStrStream << "idxcontent stylesheet missing" << std::endl; | |||
607 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
608 | } | |||
609 | ||||
610 | idxContentStylesheet = fs::path(args[i], fs::native); | |||
611 | } | |||
612 | else if (args[i].compare("-o") == 0) | |||
613 | { | |||
614 | ++i; | |||
615 | if (i >= args.size()) | |||
616 | { | |||
617 | std::stringstream aStrStream; | |||
618 | aStrStream << "outputfilename missing" << std::endl; | |||
619 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
620 | } | |||
621 | ||||
622 | outputFile = fs::path(args[i], fs::native); | |||
623 | } | |||
624 | else if (args[i].compare("-mod") == 0) | |||
625 | { | |||
626 | ++i; | |||
627 | if (i >= args.size()) | |||
628 | { | |||
629 | std::stringstream aStrStream; | |||
630 | aStrStream << "module name missing" << std::endl; | |||
631 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
632 | } | |||
633 | ||||
634 | module = args[i]; | |||
635 | } | |||
636 | else if (args[i].compare("-lang") == 0) | |||
637 | { | |||
638 | ++i; | |||
639 | if (i >= args.size()) | |||
640 | { | |||
641 | std::stringstream aStrStream; | |||
642 | aStrStream << "language name missing" << std::endl; | |||
643 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
644 | } | |||
645 | ||||
646 | lang = args[i]; | |||
647 | } | |||
648 | else if (args[i].compare("-hid") == 0) | |||
649 | { | |||
650 | ++i; | |||
651 | throw HelpProcessingException( HelpProcessingErrorClass::General, "obsolete -hid argument used" ); | |||
652 | } | |||
653 | else if (args[i].compare("-add") == 0) | |||
654 | { | |||
655 | std::string addFile, addFileUnderPath; | |||
656 | ++i; | |||
657 | if (i >= args.size()) | |||
658 | { | |||
659 | std::stringstream aStrStream; | |||
660 | aStrStream << "pathname missing" << std::endl; | |||
661 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
662 | } | |||
663 | ||||
664 | addFileUnderPath = args[i]; | |||
665 | ++i; | |||
666 | if (i >= args.size()) | |||
667 | { | |||
668 | std::stringstream aStrStream; | |||
669 | aStrStream << "pathname missing" << std::endl; | |||
670 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
671 | } | |||
672 | addFile = args[i]; | |||
673 | if (!addFileUnderPath.empty() && !addFile.empty()) | |||
674 | additionalFiles[addFileUnderPath] = addFile; | |||
675 | } | |||
676 | else if (args[i].compare("-nolangroot") == 0) | |||
677 | m_bUseLangRoot = false; | |||
678 | else if (args[i].compare("-noindex") == 0) | |||
679 | m_bCreateIndex = false; | |||
680 | else | |||
681 | helpFiles.push_back(args[i]); | |||
682 | ++i; | |||
683 | } | |||
684 | ||||
685 | //We can be called from the helplinker executable or the extension manager | |||
686 | //In the latter case extsource is not used. | |||
687 | if( (pExtensionPath && pExtensionPath->length() > 0 && pOfficeHelpPath) | |||
688 | || !extsource.empty()) | |||
689 | { | |||
690 | bExtensionMode = true; | |||
691 | if (!extsource.empty()) | |||
692 | { | |||
693 | //called from helplinker.exe, pExtensionPath and pOfficeHelpPath | |||
694 | //should be NULL | |||
695 | sourceRoot = fs::path(extsource, fs::native); | |||
696 | extensionPath = sourceRoot.toUTF8(); | |||
697 | ||||
698 | if (extdestination.empty()) | |||
699 | { | |||
700 | std::stringstream aStrStream; | |||
701 | aStrStream << "-extlangdest is missing" << std::endl; | |||
702 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
703 | } | |||
704 | else | |||
705 | { | |||
706 | //Convert from system path to file URL!!! | |||
707 | fs::path p(extdestination, fs::native); | |||
708 | extensionDestination = p.toUTF8(); | |||
709 | } | |||
710 | } | |||
711 | else | |||
712 | { //called from extension manager | |||
713 | extensionPath = *pExtensionPath; | |||
714 | sourceRoot = fs::path(extensionPath); | |||
715 | extensionDestination = *pDestination; | |||
716 | } | |||
717 | //check if -src option was used. This option must not be used | |||
718 | //when extension help is compiled. | |||
719 | if (bSrcOption) | |||
720 | { | |||
721 | std::stringstream aStrStream; | |||
722 | aStrStream << "-src must not be used together with -extsource missing" << std::endl; | |||
723 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
724 | } | |||
725 | } | |||
726 | ||||
727 | if (!bExtensionMode && zipdir.empty()) | |||
728 | { | |||
729 | std::stringstream aStrStream; | |||
730 | aStrStream << "no index dir given" << std::endl; | |||
731 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
732 | } | |||
733 | ||||
734 | if ( (!bExtensionMode
| |||
735 | || (!extsource.empty() && idxCaptionStylesheet.empty()) ) | |||
736 | { | |||
737 | //No extension mode and extension mode using commandline | |||
738 | //!extsource.empty indicates extension mode using commandline | |||
739 | // -idxcaption parameter is required | |||
740 | std::stringstream aStrStream; | |||
741 | aStrStream << "no index caption stylesheet given" << std::endl; | |||
742 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
743 | } | |||
744 | else if ( bExtensionMode
| |||
745 | { | |||
746 | //This part is used when compileExtensionHelp is called from the extensions manager. | |||
747 | //If extension help is compiled using helplinker in the build process | |||
748 | OUString aIdxCaptionPathFileURL = *pOfficeHelpPath + "/idxcaption.xsl"; | |||
| ||||
749 | ||||
750 | OString aOStr_IdxCaptionPathFileURL( OUStringToOString | |||
751 | ( aIdxCaptionPathFileURL, osl_getThreadTextEncoding() ) ); | |||
752 | std::string aStdStr_IdxCaptionPathFileURL( aOStr_IdxCaptionPathFileURL.getStr() ); | |||
753 | ||||
754 | idxCaptionStylesheet = fs::path( aStdStr_IdxCaptionPathFileURL ); | |||
755 | } | |||
756 | ||||
757 | if ( (!bExtensionMode && idxContentStylesheet.empty()) | |||
758 | || (!extsource.empty() && idxContentStylesheet.empty()) ) | |||
759 | { | |||
760 | //No extension mode and extension mode using commandline | |||
761 | //!extsource.empty indicates extension mode using commandline | |||
762 | // -idxcontent parameter is required | |||
763 | std::stringstream aStrStream; | |||
764 | aStrStream << "no index content stylesheet given" << std::endl; | |||
765 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
766 | } | |||
767 | else if ( bExtensionMode && extsource.empty()) | |||
768 | { | |||
769 | //If extension help is compiled using helplinker in the build process | |||
770 | //then -idxcontent must be supplied | |||
771 | //This part is used when compileExtensionHelp is called from the extensions manager. | |||
772 | OUString aIdxContentPathFileURL = *pOfficeHelpPath + "/idxcontent.xsl"; | |||
773 | ||||
774 | OString aOStr_IdxContentPathFileURL( OUStringToOString | |||
775 | ( aIdxContentPathFileURL, osl_getThreadTextEncoding() ) ); | |||
776 | std::string aStdStr_IdxContentPathFileURL( aOStr_IdxContentPathFileURL.getStr() ); | |||
777 | ||||
778 | idxContentStylesheet = fs::path( aStdStr_IdxContentPathFileURL ); | |||
779 | } | |||
780 | if (!bExtensionMode && embeddStylesheet.empty()) | |||
781 | { | |||
782 | std::stringstream aStrStream; | |||
783 | aStrStream << "no embedding resolving file given" << std::endl; | |||
784 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
785 | } | |||
786 | if (sourceRoot.empty()) | |||
787 | { | |||
788 | std::stringstream aStrStream; | |||
789 | aStrStream << "no sourceroot given" << std::endl; | |||
790 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
791 | } | |||
792 | if (!bExtensionMode && outputFile.empty()) | |||
793 | { | |||
794 | std::stringstream aStrStream; | |||
795 | aStrStream << "no output file given" << std::endl; | |||
796 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
797 | } | |||
798 | if (module.empty()) | |||
799 | { | |||
800 | std::stringstream aStrStream; | |||
801 | aStrStream << "module missing" << std::endl; | |||
802 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
803 | } | |||
804 | if (!bExtensionMode && lang.empty()) | |||
805 | { | |||
806 | std::stringstream aStrStream; | |||
807 | aStrStream << "language missing" << std::endl; | |||
808 | throw HelpProcessingException( HelpProcessingErrorClass::General, aStrStream.str() ); | |||
809 | } | |||
810 | link(); | |||
811 | } | |||
812 | ||||
813 | // Variable to set an exception in "C" StructuredXMLErrorFunction | |||
814 | static const HelpProcessingException* GpXMLParsingException = nullptr; | |||
815 | ||||
816 | extern "C" { | |||
817 | ||||
818 | static void StructuredXMLErrorFunction(SAL_UNUSED_PARAMETER__attribute__ ((unused)) void *, xmlErrorPtr error) | |||
819 | { | |||
820 | std::string aErrorMsg = error->message; | |||
821 | std::string aXMLParsingFile; | |||
822 | if( error->file != nullptr ) | |||
823 | aXMLParsingFile = error->file; | |||
824 | int nXMLParsingLine = error->line; | |||
825 | HelpProcessingException* pException = new HelpProcessingException( aErrorMsg, aXMLParsingFile, nXMLParsingLine ); | |||
826 | GpXMLParsingException = pException; | |||
827 | ||||
828 | // Reset error handler | |||
829 | xmlSetStructuredErrorFunc( nullptr, nullptr ); | |||
830 | } | |||
831 | ||||
832 | } | |||
833 | ||||
834 | HelpProcessingErrorInfo& HelpProcessingErrorInfo::operator=( const struct HelpProcessingException& e ) | |||
835 | { | |||
836 | m_eErrorClass = e.m_eErrorClass; | |||
837 | OString tmpErrorMsg( e.m_aErrorMsg.c_str() ); | |||
838 | m_aErrorMsg = OStringToOUString( tmpErrorMsg, osl_getThreadTextEncoding() ); | |||
839 | OString tmpXMLParsingFile( e.m_aXMLParsingFile.c_str() ); | |||
840 | m_aXMLParsingFile = OStringToOUString( tmpXMLParsingFile, osl_getThreadTextEncoding() ); | |||
841 | m_nXMLParsingLine = e.m_nXMLParsingLine; | |||
842 | return *this; | |||
843 | } | |||
844 | ||||
845 | ||||
846 | // Returns true in case of success, false in case of error | |||
847 | bool compileExtensionHelp | |||
848 | ( | |||
849 | const OUString& aOfficeHelpPath, | |||
850 | const OUString& aExtensionName, | |||
851 | const OUString& aExtensionLanguageRoot, | |||
852 | sal_Int32 nXhpFileCount, const OUString* pXhpFiles, | |||
853 | const OUString& aDestination, | |||
854 | HelpProcessingErrorInfo& o_rHelpProcessingErrorInfo | |||
855 | ) | |||
856 | { | |||
857 | bool bSuccess = true; | |||
858 | ||||
859 | std::vector<std::string> args; | |||
860 | args.reserve(nXhpFileCount + 2); | |||
861 | args.push_back(std::string("-mod")); | |||
862 | OString aOExtensionName = OUStringToOString( aExtensionName, osl_getThreadTextEncoding() ); | |||
863 | args.push_back(std::string(aOExtensionName.getStr())); | |||
864 | ||||
865 | for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp ) | |||
866 | { | |||
867 | OUString aXhpFile = pXhpFiles[iXhp]; | |||
868 | ||||
869 | OString aOXhpFile = OUStringToOString( aXhpFile, osl_getThreadTextEncoding() ); | |||
870 | args.push_back(std::string(aOXhpFile.getStr())); | |||
871 | } | |||
872 | ||||
873 | OString aOExtensionLanguageRoot = OUStringToOString( aExtensionLanguageRoot, osl_getThreadTextEncoding() ); | |||
874 | const char* pExtensionPath = aOExtensionLanguageRoot.getStr(); | |||
875 | std::string aStdStrExtensionPath = pExtensionPath; | |||
876 | OString aODestination = OUStringToOString(aDestination, osl_getThreadTextEncoding()); | |||
877 | const char* pDestination = aODestination.getStr(); | |||
878 | std::string aStdStrDestination = pDestination; | |||
879 | ||||
880 | // Set error handler | |||
881 | xmlSetStructuredErrorFunc( nullptr, StructuredXMLErrorFunction ); | |||
882 | try | |||
883 | { | |||
884 | std::unique_ptr<HelpLinker> pHelpLinker(new HelpLinker()); | |||
885 | pHelpLinker->main( args, &aStdStrExtensionPath, &aStdStrDestination, &aOfficeHelpPath ); | |||
886 | } | |||
887 | catch( const HelpProcessingException& e ) | |||
888 | { | |||
889 | if( GpXMLParsingException != nullptr ) | |||
890 | { | |||
891 | o_rHelpProcessingErrorInfo = *GpXMLParsingException; | |||
892 | delete GpXMLParsingException; | |||
893 | GpXMLParsingException = nullptr; | |||
894 | } | |||
895 | else | |||
896 | { | |||
897 | o_rHelpProcessingErrorInfo = e; | |||
898 | } | |||
899 | bSuccess = false; | |||
900 | } | |||
901 | // Reset error handler | |||
902 | xmlSetStructuredErrorFunc( nullptr, nullptr ); | |||
903 | ||||
904 | // i83624: Tree files | |||
905 | // The following basically checks if the help.tree is well formed XML. | |||
906 | // Apparently there have been cases when translations contained | |||
907 | // non-well-formed XML in the past. | |||
908 | OUString aTreeFileURL = aExtensionLanguageRoot + "/help.tree"; | |||
909 | osl::DirectoryItem aTreeFileItem; | |||
910 | osl::FileBase::RC rcGet = osl::DirectoryItem::get( aTreeFileURL, aTreeFileItem ); | |||
911 | osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileSize0x00000080 ); | |||
912 | if( rcGet == osl::FileBase::E_None && | |||
913 | aTreeFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None && | |||
914 | aFileStatus.isValid( osl_FileStatus_Mask_FileSize0x00000080 ) ) | |||
915 | { | |||
916 | sal_uInt64 ret, len = aFileStatus.getFileSize(); | |||
917 | std::unique_ptr<char[]> s(new char[ int(len) ]); // the buffer to hold the installed files | |||
918 | osl::File aFile( aTreeFileURL ); | |||
919 | (void)aFile.open( osl_File_OpenFlag_Read0x00000001L ); | |||
920 | aFile.read( s.get(), len, ret ); | |||
921 | aFile.close(); | |||
922 | ||||
923 | XML_Parser parser = XML_ParserCreate( nullptr ); | |||
924 | XML_Status parsed = XML_Parse( parser, s.get(), int( len ), true ); | |||
925 | ||||
926 | if (XML_STATUS_ERRORXML_STATUS_ERROR == parsed) | |||
927 | { | |||
928 | XML_Error nError = XML_GetErrorCode( parser ); | |||
929 | o_rHelpProcessingErrorInfo.m_eErrorClass = HelpProcessingErrorClass::XmlParsing; | |||
930 | o_rHelpProcessingErrorInfo.m_aErrorMsg = OUString::createFromAscii( XML_ErrorString( nError ) ); | |||
931 | o_rHelpProcessingErrorInfo.m_aXMLParsingFile = aTreeFileURL; | |||
932 | // CRASHES!!! o_rHelpProcessingErrorInfo.m_nXMLParsingLine = XML_GetCurrentLineNumber( parser ); | |||
933 | bSuccess = false; | |||
934 | } | |||
935 | ||||
936 | XML_ParserFree( parser ); | |||
937 | } | |||
938 | ||||
939 | return bSuccess; | |||
940 | } | |||
941 | ||||
942 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |