/src/libreoffice/sax/source/expatwrap/sax_expat.cxx
Line | Count | Source |
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 <string.h> |
21 | | #include <cassert> |
22 | | #include <memory> |
23 | | #include <mutex> |
24 | | #include <utility> |
25 | | #include <string_view> |
26 | | #include <vector> |
27 | | |
28 | | |
29 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
30 | | #include <com/sun/star/lang/XInitialization.hpp> |
31 | | #include <com/sun/star/uno/XComponentContext.hpp> |
32 | | #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> |
33 | | #include <com/sun/star/xml/sax/XParser.hpp> |
34 | | #include <com/sun/star/xml/sax/SAXParseException.hpp> |
35 | | #include <com/sun/star/io/IOException.hpp> |
36 | | #include <com/sun/star/io/XSeekable.hpp> |
37 | | #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> |
38 | | |
39 | | #include <comphelper/attributelist.hxx> |
40 | | #include <cppuhelper/weak.hxx> |
41 | | #include <cppuhelper/implbase.hxx> |
42 | | #include <cppuhelper/supportsservice.hxx> |
43 | | #include <rtl/ref.hxx> |
44 | | #include <sal/log.hxx> |
45 | | |
46 | | #include <expat.h> |
47 | | #include <xml2utf.hxx> |
48 | | |
49 | | using namespace ::cppu; |
50 | | using namespace ::com::sun::star::lang; |
51 | | using namespace ::com::sun::star::xml::sax; |
52 | | using namespace ::com::sun::star::io; |
53 | | |
54 | | |
55 | | namespace { |
56 | | |
57 | 1.21M | #define XML_CHAR_TO_OUSTRING(x) OUString(x , strlen( x ), RTL_TEXTENCODING_UTF8) |
58 | | #define XML_CHAR_N_TO_USTRING(x,n) OUString(x,n, RTL_TEXTENCODING_UTF8 ) |
59 | | |
60 | | |
61 | | /* |
62 | | * The following macro encapsulates any call to an event handler. |
63 | | * It ensures, that exceptions thrown by the event handler are |
64 | | * treated properly. |
65 | | */ |
66 | | #define CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pThis,call) \ |
67 | 634k | if( ! pThis->bExceptionWasThrown ) { \ |
68 | 633k | try {\ |
69 | 633k | pThis->call;\ |
70 | 633k | }\ |
71 | 633k | catch( const SAXParseException &e ) {\ |
72 | 0 | callErrorHandler( pThis , e );\ |
73 | 0 | }\ |
74 | 633k | catch( const SAXException &e ) {\ |
75 | 28 | callErrorHandler( pThis , SAXParseException(\ |
76 | 28 | e.Message, \ |
77 | 28 | e.Context, \ |
78 | 28 | e.WrappedException,\ |
79 | 28 | pThis->rDocumentLocator->getPublicId(),\ |
80 | 28 | pThis->rDocumentLocator->getSystemId(),\ |
81 | 28 | pThis->rDocumentLocator->getLineNumber(),\ |
82 | 28 | pThis->rDocumentLocator->getColumnNumber()\ |
83 | 28 | ) );\ |
84 | 28 | }\ |
85 | 633k | catch( const css::uno::RuntimeException &e ) {\ |
86 | 0 | pThis->bExceptionWasThrown = true; \ |
87 | 0 | pThis->bRTExceptionWasThrown = true; \ |
88 | 0 | pImpl->rtexception = e; \ |
89 | 0 | }\ |
90 | 633k | catch( const css::uno::Exception &e ) {\ |
91 | 0 | pThis->bExceptionWasThrown = true; \ |
92 | 0 | pThis->bRTExceptionWasThrown = true; \ |
93 | 0 | pImpl->rtexception = WrappedTargetRuntimeException(u"Non-runtime UNO exception caught during parse"_ustr, e.Context, css::uno::Any(e)); \ |
94 | 0 | }\ |
95 | 633k | }\ |
96 | 634k | ((void)0) |
97 | | |
98 | | |
99 | | class SaxExpatParser_Impl; |
100 | | |
101 | | // This class implements the external Parser interface |
102 | | class SaxExpatParser |
103 | | : public WeakImplHelper< XInitialization |
104 | | , XServiceInfo |
105 | | , XParser > |
106 | | { |
107 | | |
108 | | public: |
109 | | SaxExpatParser(); |
110 | | |
111 | | // css::lang::XInitialization: |
112 | | virtual void SAL_CALL initialize(css::uno::Sequence<css::uno::Any> const& rArguments) override; |
113 | | |
114 | | // The SAX-Parser-Interface |
115 | | virtual void SAL_CALL parseStream( const InputSource& structSource) override; |
116 | | virtual void SAL_CALL setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler) override; |
117 | | |
118 | | virtual void SAL_CALL setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler) override; |
119 | | virtual void SAL_CALL setDTDHandler(const css::uno::Reference < XDTDHandler > & xHandler) override; |
120 | | virtual void SAL_CALL setEntityResolver(const css::uno::Reference< XEntityResolver >& xResolver) override; |
121 | | |
122 | | virtual void SAL_CALL setLocale( const Locale &locale ) override; |
123 | | |
124 | | public: // XServiceInfo |
125 | | OUString SAL_CALL getImplementationName() override; |
126 | | css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; |
127 | | sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; |
128 | | |
129 | | private: |
130 | | std::unique_ptr<SaxExpatParser_Impl> m_pImpl; |
131 | | }; |
132 | | |
133 | | |
134 | | // Entity binds all information needed for a single file |
135 | | struct Entity |
136 | | { |
137 | | InputSource structSource; |
138 | | XML_Parser pParser; |
139 | | sax_expatwrap::XMLFile2UTFConverter converter; |
140 | | }; |
141 | | |
142 | | class LocatorImpl; |
143 | | class SaxExpatParser_Impl |
144 | | { |
145 | | public: // module scope |
146 | | std::mutex aMutex; |
147 | | bool m_bEnableDoS; // fdo#60471 thank you Adobe Illustrator |
148 | | |
149 | | css::uno::Reference< XDocumentHandler > rDocumentHandler; |
150 | | css::uno::Reference< XExtendedDocumentHandler > rExtendedDocumentHandler; |
151 | | |
152 | | css::uno::Reference< XErrorHandler > rErrorHandler; |
153 | | css::uno::Reference< XDTDHandler > rDTDHandler; |
154 | | css::uno::Reference< XEntityResolver > rEntityResolver; |
155 | | rtl::Reference < LocatorImpl > rDocumentLocator; |
156 | | |
157 | | |
158 | | rtl::Reference < comphelper::AttributeList > rAttrList; |
159 | | |
160 | | // External entity stack |
161 | | std::vector<struct Entity> vecEntity; |
162 | | void pushEntity( Entity &&entity ) |
163 | 40.8k | { vecEntity.push_back( std::move(entity) ); } |
164 | | void popEntity() |
165 | 40.8k | { vecEntity.pop_back( ); } |
166 | | struct Entity &getEntity() |
167 | 245k | { return vecEntity.back(); } |
168 | | |
169 | | |
170 | | // Exception cannot be thrown through the C-XmlParser (possible resource leaks), |
171 | | // therefore the exception must be saved somewhere. |
172 | | SAXParseException exception; |
173 | | css::uno::RuntimeException rtexception; |
174 | | bool bExceptionWasThrown; |
175 | | bool bRTExceptionWasThrown; |
176 | | |
177 | | public: |
178 | | SaxExpatParser_Impl() |
179 | 40.8k | : m_bEnableDoS(false) |
180 | 40.8k | , bExceptionWasThrown(false) |
181 | 40.8k | , bRTExceptionWasThrown(false) |
182 | 40.8k | { |
183 | 40.8k | } |
184 | | |
185 | | // the C-Callbacks for the expat parser |
186 | | void static callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts); |
187 | | void static callbackEndElement(void *userData, const XML_Char *name); |
188 | | void static callbackCharacters( void *userData , const XML_Char *s , int nLen ); |
189 | | void static callbackProcessingInstruction( void *userData , |
190 | | const XML_Char *sTarget , |
191 | | const XML_Char *sData ); |
192 | | |
193 | | void static callbackEntityDecl( void *userData , |
194 | | const XML_Char *entityName, |
195 | | int is_parameter_entity, |
196 | | const XML_Char *value, |
197 | | int value_length, |
198 | | const XML_Char *base, |
199 | | const XML_Char *systemId, |
200 | | const XML_Char *publicId, |
201 | | const XML_Char *notationName); |
202 | | |
203 | | void static callbackNotationDecl( void *userData, |
204 | | const XML_Char *notationName, |
205 | | const XML_Char *base, |
206 | | const XML_Char *systemId, |
207 | | const XML_Char *publicId); |
208 | | |
209 | | bool static callbackExternalEntityRef( XML_Parser parser, |
210 | | const XML_Char *openEntityNames, |
211 | | const XML_Char *base, |
212 | | const XML_Char *systemId, |
213 | | const XML_Char *publicId); |
214 | | |
215 | | int static callbackUnknownEncoding(void *encodingHandlerData, |
216 | | const XML_Char *name, |
217 | | XML_Encoding *info); |
218 | | |
219 | | void static callbackDefault( void *userData, const XML_Char *s, int len); |
220 | | |
221 | | void static callbackStartCDATA( void *userData ); |
222 | | void static callbackEndCDATA( void *userData ); |
223 | | void static callbackComment( void *userData , const XML_Char *s ); |
224 | | void static callErrorHandler( SaxExpatParser_Impl *pImpl , const SAXParseException &e ); |
225 | | |
226 | | public: |
227 | | void parse(); |
228 | | }; |
229 | | |
230 | | extern "C" |
231 | | { |
232 | | static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts) |
233 | 306k | { |
234 | 306k | SaxExpatParser_Impl::callbackStartElement(userData,name,atts); |
235 | 306k | } |
236 | | static void call_callbackEndElement(void *userData, const XML_Char *name) |
237 | 290k | { |
238 | 290k | SaxExpatParser_Impl::callbackEndElement(userData,name); |
239 | 290k | } |
240 | | static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen ) |
241 | 36.2k | { |
242 | 36.2k | SaxExpatParser_Impl::callbackCharacters(userData,s,nLen); |
243 | 36.2k | } |
244 | | static void call_callbackProcessingInstruction(void *userData,const XML_Char *sTarget,const XML_Char *sData ) |
245 | 945 | { |
246 | 945 | SaxExpatParser_Impl::callbackProcessingInstruction(userData,sTarget,sData ); |
247 | 945 | } |
248 | | static void call_callbackEntityDecl(void *userData , |
249 | | const XML_Char *entityName, |
250 | | int is_parameter_entity, |
251 | | const XML_Char *value, |
252 | | int value_length, |
253 | | const XML_Char *base, |
254 | | const XML_Char *systemId, |
255 | | const XML_Char *publicId, |
256 | | const XML_Char *notationName) |
257 | 2 | { |
258 | 2 | SaxExpatParser_Impl::callbackEntityDecl(userData, entityName, |
259 | 2 | is_parameter_entity, value, value_length, |
260 | 2 | base, systemId, publicId, notationName); |
261 | 2 | } |
262 | | static void call_callbackNotationDecl(void *userData, |
263 | | const XML_Char *notationName, |
264 | | const XML_Char *base, |
265 | | const XML_Char *systemId, |
266 | | const XML_Char *publicId) |
267 | 0 | { |
268 | 0 | SaxExpatParser_Impl::callbackNotationDecl(userData,notationName,base,systemId,publicId); |
269 | 0 | } |
270 | | static int call_callbackExternalEntityRef(XML_Parser parser, |
271 | | const XML_Char *openEntityNames, |
272 | | const XML_Char *base, |
273 | | const XML_Char *systemId, |
274 | | const XML_Char *publicId) |
275 | 0 | { |
276 | 0 | return SaxExpatParser_Impl::callbackExternalEntityRef(parser,openEntityNames,base,systemId,publicId); |
277 | 0 | } |
278 | | static int call_callbackUnknownEncoding(void *encodingHandlerData, |
279 | | const XML_Char *name, |
280 | | XML_Encoding *info) |
281 | 1 | { |
282 | 1 | return SaxExpatParser_Impl::callbackUnknownEncoding(encodingHandlerData,name,info); |
283 | 1 | } |
284 | | static void call_callbackDefault( void *userData, const XML_Char *s, int len) |
285 | 0 | { |
286 | 0 | SaxExpatParser_Impl::callbackDefault(userData,s,len); |
287 | 0 | } |
288 | | static void call_callbackStartCDATA( void *userData ) |
289 | 0 | { |
290 | 0 | SaxExpatParser_Impl::callbackStartCDATA(userData); |
291 | 0 | } |
292 | | static void call_callbackEndCDATA( void *userData ) |
293 | 0 | { |
294 | 0 | SaxExpatParser_Impl::callbackEndCDATA(userData); |
295 | 0 | } |
296 | | static void call_callbackComment( void *userData , const XML_Char *s ) |
297 | 0 | { |
298 | 0 | SaxExpatParser_Impl::callbackComment(userData,s); |
299 | 0 | } |
300 | | } |
301 | | |
302 | | |
303 | | // LocatorImpl |
304 | | |
305 | | class LocatorImpl : |
306 | | public WeakImplHelper< XLocator, css::io::XSeekable > |
307 | | // should use a different interface for stream positions! |
308 | | { |
309 | | public: |
310 | | explicit LocatorImpl(SaxExpatParser_Impl *p) |
311 | 40.8k | : m_pParser(p) |
312 | 40.8k | { |
313 | 40.8k | } |
314 | | |
315 | | public: //XLocator |
316 | | virtual sal_Int32 SAL_CALL getColumnNumber() override |
317 | 12.5k | { |
318 | 12.5k | return XML_GetCurrentColumnNumber( m_pParser->getEntity().pParser ); |
319 | 12.5k | } |
320 | | virtual sal_Int32 SAL_CALL getLineNumber() override |
321 | 25.1k | { |
322 | 25.1k | return XML_GetCurrentLineNumber( m_pParser->getEntity().pParser ); |
323 | 25.1k | } |
324 | | virtual OUString SAL_CALL getPublicId() override |
325 | 12.5k | { |
326 | 12.5k | return m_pParser->getEntity().structSource.sPublicId; |
327 | 12.5k | } |
328 | | virtual OUString SAL_CALL getSystemId() override |
329 | 25.1k | { |
330 | 25.1k | return m_pParser->getEntity().structSource.sSystemId; |
331 | 25.1k | } |
332 | | |
333 | | // XSeekable (only for getPosition) |
334 | | |
335 | | virtual void SAL_CALL seek( sal_Int64 ) override |
336 | 0 | { |
337 | 0 | } |
338 | | virtual sal_Int64 SAL_CALL getPosition() override |
339 | 0 | { |
340 | 0 | return XML_GetCurrentByteIndex( m_pParser->getEntity().pParser ); |
341 | 0 | } |
342 | | virtual ::sal_Int64 SAL_CALL getLength() override |
343 | 0 | { |
344 | 0 | return 0; |
345 | 0 | } |
346 | | |
347 | | private: |
348 | | |
349 | | SaxExpatParser_Impl *m_pParser; |
350 | | }; |
351 | | |
352 | | |
353 | | SaxExpatParser::SaxExpatParser( ) |
354 | 40.8k | { |
355 | 40.8k | m_pImpl.reset( new SaxExpatParser_Impl ); |
356 | | |
357 | 40.8k | m_pImpl->rDocumentLocator = new LocatorImpl( m_pImpl.get() ); |
358 | | |
359 | | // Performance-improvement; handing out the same object with every call of |
360 | | // the startElement callback is allowed (see sax-specification): |
361 | 40.8k | m_pImpl->rAttrList = new comphelper::AttributeList; |
362 | | |
363 | 40.8k | m_pImpl->bExceptionWasThrown = false; |
364 | 40.8k | m_pImpl->bRTExceptionWasThrown = false; |
365 | 40.8k | } |
366 | | |
367 | | // css::lang::XInitialization: |
368 | | void SAL_CALL |
369 | | SaxExpatParser::initialize(css::uno::Sequence< css::uno::Any > const& rArguments) |
370 | 12.4k | { |
371 | | // possible arguments: a string "DoSmeplease" |
372 | 12.4k | if (rArguments.hasElements()) |
373 | 12.4k | { |
374 | 12.4k | OUString str; |
375 | 12.4k | if ((rArguments[0] >>= str) && "DoSmeplease" == str) |
376 | 12.4k | { |
377 | 12.4k | std::unique_lock guard( m_pImpl->aMutex ); |
378 | 12.4k | m_pImpl->m_bEnableDoS = true; |
379 | 12.4k | } |
380 | 12.4k | } |
381 | 12.4k | } |
382 | | |
383 | | class ParserCleanup |
384 | | { |
385 | | private: |
386 | | SaxExpatParser_Impl& m_rParser; |
387 | | XML_Parser m_xmlParser; |
388 | | public: |
389 | | ParserCleanup(SaxExpatParser_Impl& rParser, XML_Parser xmlParser) |
390 | 40.8k | : m_rParser(rParser) |
391 | 40.8k | , m_xmlParser(xmlParser) |
392 | 40.8k | { |
393 | 40.8k | } |
394 | | ~ParserCleanup() |
395 | 40.8k | { |
396 | 40.8k | m_rParser.popEntity(); |
397 | | //XML_ParserFree accepts a null arg |
398 | 40.8k | XML_ParserFree(m_xmlParser); |
399 | 40.8k | } |
400 | | }; |
401 | | |
402 | | /*************** |
403 | | * |
404 | | * parseStream does Parser-startup initializations. The SaxExpatParser_Impl::parse() method does |
405 | | * the file-specific initialization work. (During a parser run, external files may be opened) |
406 | | * |
407 | | ****************/ |
408 | | void SaxExpatParser::parseStream( const InputSource& structSource) |
409 | 40.8k | { |
410 | | // Only one text at one time |
411 | 40.8k | std::unique_lock guard( m_pImpl->aMutex ); |
412 | | |
413 | | |
414 | 40.8k | struct Entity entity; |
415 | 40.8k | entity.structSource = structSource; |
416 | | |
417 | 40.8k | if( ! entity.structSource.aInputStream.is() ) |
418 | 0 | { |
419 | 0 | throw SAXException(u"No input source"_ustr, |
420 | 0 | css::uno::Reference< css::uno::XInterface > () , css::uno::Any() ); |
421 | 0 | } |
422 | | |
423 | 40.8k | entity.converter.setInputStream( entity.structSource.aInputStream ); |
424 | 40.8k | if( !entity.structSource.sEncoding.isEmpty() ) |
425 | 0 | { |
426 | 0 | entity.converter.setEncoding( |
427 | 0 | OUStringToOString( entity.structSource.sEncoding , RTL_TEXTENCODING_ASCII_US ) ); |
428 | 0 | } |
429 | | |
430 | | // create parser with proper encoding |
431 | 40.8k | entity.pParser = XML_ParserCreate( nullptr ); |
432 | 40.8k | if( ! entity.pParser ) |
433 | 0 | { |
434 | 0 | throw SAXException(u"Couldn't create parser"_ustr, |
435 | 0 | css::uno::Reference< css::uno::XInterface > (), css::uno::Any() ); |
436 | 0 | } |
437 | | |
438 | | // set all necessary C-Callbacks |
439 | 40.8k | XML_SetUserData( entity.pParser, m_pImpl.get() ); |
440 | 40.8k | XML_SetElementHandler( entity.pParser , |
441 | 40.8k | call_callbackStartElement , |
442 | 40.8k | call_callbackEndElement ); |
443 | 40.8k | XML_SetCharacterDataHandler( entity.pParser , call_callbackCharacters ); |
444 | 40.8k | XML_SetProcessingInstructionHandler(entity.pParser , |
445 | 40.8k | call_callbackProcessingInstruction ); |
446 | 40.8k | if (!m_pImpl->m_bEnableDoS) |
447 | 28.4k | { |
448 | 28.4k | XML_SetEntityDeclHandler(entity.pParser, call_callbackEntityDecl); |
449 | 28.4k | } |
450 | 40.8k | XML_SetNotationDeclHandler( entity.pParser, call_callbackNotationDecl ); |
451 | 40.8k | XML_SetExternalEntityRefHandler( entity.pParser, |
452 | 40.8k | call_callbackExternalEntityRef); |
453 | 40.8k | XML_SetUnknownEncodingHandler( entity.pParser, call_callbackUnknownEncoding ,nullptr); |
454 | | |
455 | 40.8k | if( m_pImpl->rExtendedDocumentHandler.is() ) { |
456 | | |
457 | | // These handlers just delegate calls to the ExtendedHandler. If no extended handler is |
458 | | // given, these callbacks can be ignored |
459 | 0 | XML_SetDefaultHandlerExpand( entity.pParser, call_callbackDefault ); |
460 | 0 | XML_SetCommentHandler( entity.pParser, call_callbackComment ); |
461 | 0 | XML_SetCdataSectionHandler( entity.pParser , |
462 | 0 | call_callbackStartCDATA , |
463 | 0 | call_callbackEndCDATA ); |
464 | 0 | } |
465 | | |
466 | | |
467 | 40.8k | m_pImpl->exception = SAXParseException(); |
468 | 40.8k | auto const xmlParser = entity.pParser; |
469 | 40.8k | m_pImpl->pushEntity( std::move(entity) ); |
470 | | |
471 | 40.8k | ParserCleanup aEnsureFree(*m_pImpl, xmlParser); |
472 | | |
473 | | // start the document |
474 | 40.8k | if( m_pImpl->rDocumentHandler.is() ) { |
475 | 40.8k | m_pImpl->rDocumentHandler->setDocumentLocator( m_pImpl->rDocumentLocator ); |
476 | 40.8k | m_pImpl->rDocumentHandler->startDocument(); |
477 | 40.8k | } |
478 | | |
479 | 40.8k | m_pImpl->parse(); |
480 | | |
481 | | // finish document |
482 | 40.8k | if( m_pImpl->rDocumentHandler.is() ) { |
483 | 28.3k | m_pImpl->rDocumentHandler->endDocument(); |
484 | 28.3k | } |
485 | 40.8k | } |
486 | | |
487 | | void SaxExpatParser::setDocumentHandler(const css::uno::Reference< XDocumentHandler > & xHandler) |
488 | 69.2k | { |
489 | 69.2k | m_pImpl->rDocumentHandler = xHandler; |
490 | 69.2k | m_pImpl->rExtendedDocumentHandler = |
491 | 69.2k | css::uno::Reference< XExtendedDocumentHandler >( xHandler , css::uno::UNO_QUERY ); |
492 | 69.2k | } |
493 | | |
494 | | void SaxExpatParser::setErrorHandler(const css::uno::Reference< XErrorHandler > & xHandler) |
495 | 0 | { |
496 | 0 | m_pImpl->rErrorHandler = xHandler; |
497 | 0 | } |
498 | | |
499 | | void SaxExpatParser::setDTDHandler(const css::uno::Reference< XDTDHandler > & xHandler) |
500 | 0 | { |
501 | 0 | m_pImpl->rDTDHandler = xHandler; |
502 | 0 | } |
503 | | |
504 | | void SaxExpatParser::setEntityResolver(const css::uno::Reference < XEntityResolver > & xResolver) |
505 | 0 | { |
506 | 0 | m_pImpl->rEntityResolver = xResolver; |
507 | 0 | } |
508 | | |
509 | | |
510 | | void SaxExpatParser::setLocale( const Locale & ) |
511 | 0 | { |
512 | | // not implemented |
513 | 0 | } |
514 | | |
515 | | // XServiceInfo |
516 | | OUString SaxExpatParser::getImplementationName() |
517 | 0 | { |
518 | 0 | return u"com.sun.star.comp.extensions.xml.sax.ParserExpat"_ustr; |
519 | 0 | } |
520 | | |
521 | | // XServiceInfo |
522 | | sal_Bool SaxExpatParser::supportsService(const OUString& ServiceName) |
523 | 0 | { |
524 | 0 | return cppu::supportsService(this, ServiceName); |
525 | 0 | } |
526 | | |
527 | | // XServiceInfo |
528 | | css::uno::Sequence< OUString > SaxExpatParser::getSupportedServiceNames() |
529 | 0 | { |
530 | 0 | return { u"com.sun.star.xml.sax.Parser"_ustr }; |
531 | 0 | } |
532 | | |
533 | | |
534 | | /*--------------------------------------- |
535 | | * |
536 | | * Helper functions and classes |
537 | | * |
538 | | * |
539 | | *-------------------------------------------*/ |
540 | | OUString getErrorMessage( XML_Error xmlE, std::u16string_view sSystemId , sal_Int32 nLine ) |
541 | 12.5k | { |
542 | 12.5k | OUString Message; |
543 | 12.5k | if( XML_ERROR_NONE == xmlE ) { |
544 | 14 | Message = "No"; |
545 | 14 | } |
546 | 12.5k | else if( XML_ERROR_NO_MEMORY == xmlE ) { |
547 | 0 | Message = "no memory"; |
548 | 0 | } |
549 | 12.5k | else if( XML_ERROR_SYNTAX == xmlE ) { |
550 | 84 | Message = "syntax"; |
551 | 84 | } |
552 | 12.4k | else if( XML_ERROR_NO_ELEMENTS == xmlE ) { |
553 | 1.31k | Message = "no elements"; |
554 | 1.31k | } |
555 | 11.1k | else if( XML_ERROR_INVALID_TOKEN == xmlE ) { |
556 | 2.56k | Message = "invalid token"; |
557 | 2.56k | } |
558 | 8.56k | else if( XML_ERROR_UNCLOSED_TOKEN == xmlE ) { |
559 | 8.26k | Message = "unclosed token"; |
560 | 8.26k | } |
561 | 298 | else if( XML_ERROR_PARTIAL_CHAR == xmlE ) { |
562 | 0 | Message = "partial char"; |
563 | 0 | } |
564 | 298 | else if( XML_ERROR_TAG_MISMATCH == xmlE ) { |
565 | 93 | Message = "tag mismatch"; |
566 | 93 | } |
567 | 205 | else if( XML_ERROR_DUPLICATE_ATTRIBUTE == xmlE ) { |
568 | 0 | Message = "duplicate attribute"; |
569 | 0 | } |
570 | 205 | else if( XML_ERROR_JUNK_AFTER_DOC_ELEMENT == xmlE ) { |
571 | 118 | Message = "junk after doc element"; |
572 | 118 | } |
573 | 87 | else if( XML_ERROR_PARAM_ENTITY_REF == xmlE ) { |
574 | 0 | Message = "parameter entity reference"; |
575 | 0 | } |
576 | 87 | else if( XML_ERROR_UNDEFINED_ENTITY == xmlE ) { |
577 | 1 | Message = "undefined entity"; |
578 | 1 | } |
579 | 86 | else if( XML_ERROR_RECURSIVE_ENTITY_REF == xmlE ) { |
580 | 0 | Message = "recursive entity reference"; |
581 | 0 | } |
582 | 86 | else if( XML_ERROR_ASYNC_ENTITY == xmlE ) { |
583 | 0 | Message = "async entity"; |
584 | 0 | } |
585 | 86 | else if( XML_ERROR_BAD_CHAR_REF == xmlE ) { |
586 | 0 | Message = "bad char reference"; |
587 | 0 | } |
588 | 86 | else if( XML_ERROR_BINARY_ENTITY_REF == xmlE ) { |
589 | 0 | Message = "binary entity reference"; |
590 | 0 | } |
591 | 86 | else if( XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF == xmlE ) { |
592 | 0 | Message = "attribute external entity reference"; |
593 | 0 | } |
594 | 86 | else if( XML_ERROR_MISPLACED_XML_PI == xmlE ) { |
595 | 8 | Message = "misplaced xml processing instruction"; |
596 | 8 | } |
597 | 78 | else if( XML_ERROR_UNKNOWN_ENCODING == xmlE ) { |
598 | 1 | Message = "unknown encoding"; |
599 | 1 | } |
600 | 77 | else if( XML_ERROR_INCORRECT_ENCODING == xmlE ) { |
601 | 0 | Message = "incorrect encoding"; |
602 | 0 | } |
603 | 77 | else if( XML_ERROR_UNCLOSED_CDATA_SECTION == xmlE ) { |
604 | 56 | Message = "unclosed cdata section"; |
605 | 56 | } |
606 | 21 | else if( XML_ERROR_EXTERNAL_ENTITY_HANDLING == xmlE ) { |
607 | 0 | Message = "external entity reference"; |
608 | 0 | } |
609 | 21 | else if( XML_ERROR_NOT_STANDALONE == xmlE ) { |
610 | 0 | Message = "not standalone"; |
611 | 0 | } |
612 | | |
613 | 12.5k | OUString str = OUString::Concat("[") + |
614 | 12.5k | sSystemId + |
615 | 12.5k | " line " + |
616 | 12.5k | OUString::number( nLine ) + |
617 | 12.5k | "]: " + |
618 | 12.5k | Message + |
619 | 12.5k | "error"; |
620 | | |
621 | 12.5k | return str; |
622 | 12.5k | } |
623 | | |
624 | | |
625 | | // starts parsing with actual parser ! |
626 | | void SaxExpatParser_Impl::parse( ) |
627 | 40.8k | { |
628 | 40.8k | const int nBufSize = 16*1024; |
629 | | |
630 | 40.8k | int nRead = nBufSize; |
631 | 40.8k | css::uno::Sequence< sal_Int8 > seqOut(nBufSize); |
632 | | |
633 | 78.8k | while( nRead ) { |
634 | 78.8k | nRead = getEntity().converter.readAndConvert( seqOut , nBufSize ); |
635 | | |
636 | 78.8k | bool bContinue(false); |
637 | | |
638 | 78.8k | if( ! nRead ) { |
639 | | // last call - must return OK |
640 | 37.9k | XML_Status const ret = XML_Parse( getEntity().pParser, |
641 | 37.9k | reinterpret_cast<const char *>(seqOut.getConstArray()), |
642 | 37.9k | 0 , |
643 | 37.9k | 1 ); |
644 | 37.9k | if (ret == XML_STATUS_OK) { |
645 | 28.3k | break; |
646 | 28.3k | } |
647 | 40.8k | } else { |
648 | 40.8k | bContinue = ( XML_Parse( getEntity().pParser, |
649 | 40.8k | reinterpret_cast<const char *>(seqOut.getConstArray()), |
650 | 40.8k | nRead, |
651 | 40.8k | 0 ) != XML_STATUS_ERROR ); |
652 | 40.8k | } |
653 | | |
654 | 50.4k | if( ! bContinue || bExceptionWasThrown ) { |
655 | | |
656 | 12.5k | if ( bRTExceptionWasThrown ) |
657 | 0 | throw rtexception; |
658 | | |
659 | | // Error during parsing ! |
660 | 12.5k | XML_Error xmlE = XML_GetErrorCode( getEntity().pParser ); |
661 | 12.5k | OUString sSystemId = rDocumentLocator->getSystemId(); |
662 | 12.5k | sal_Int32 nLine = rDocumentLocator->getLineNumber(); |
663 | | |
664 | 12.5k | SAXParseException aExcept( |
665 | 12.5k | getErrorMessage(xmlE , sSystemId, nLine) , |
666 | 12.5k | css::uno::Reference< css::uno::XInterface >(), |
667 | 12.5k | css::uno::Any( &exception , cppu::UnoType<decltype(exception)>::get() ), |
668 | 12.5k | rDocumentLocator->getPublicId(), |
669 | 12.5k | rDocumentLocator->getSystemId(), |
670 | 12.5k | rDocumentLocator->getLineNumber(), |
671 | 12.5k | rDocumentLocator->getColumnNumber() |
672 | 12.5k | ); |
673 | | |
674 | 12.5k | if( rErrorHandler.is() ) { |
675 | | |
676 | | // error handler is set, so the handler may throw the exception |
677 | 0 | css::uno::Any a; |
678 | 0 | a <<= aExcept; |
679 | 0 | rErrorHandler->fatalError( a ); |
680 | 0 | } |
681 | | |
682 | | // Error handler has not thrown an exception, but parsing cannot go on, |
683 | | // so an exception MUST be thrown. |
684 | 12.5k | throw aExcept; |
685 | 12.5k | } // if( ! bContinue ) |
686 | 50.4k | } // while |
687 | 40.8k | } |
688 | | |
689 | | |
690 | | // The C-Callbacks |
691 | | |
692 | | |
693 | | void SaxExpatParser_Impl::callbackStartElement( void *pvThis , |
694 | | const XML_Char *pwName , |
695 | | const XML_Char **awAttributes ) |
696 | 306k | { |
697 | 306k | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
698 | | |
699 | 306k | if( !pImpl->rDocumentHandler.is() ) |
700 | 0 | return; |
701 | | |
702 | 306k | int i = 0; |
703 | 306k | pImpl->rAttrList->Clear(); |
704 | | |
705 | 916k | while( awAttributes[i] ) { |
706 | 609k | assert(awAttributes[i+1]); |
707 | 609k | pImpl->rAttrList->AddAttribute( |
708 | 609k | XML_CHAR_TO_OUSTRING( awAttributes[i] ) , |
709 | 609k | XML_CHAR_TO_OUSTRING( awAttributes[i+1] ) ); |
710 | 609k | i +=2; |
711 | 609k | } |
712 | | |
713 | 306k | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( |
714 | 306k | pImpl , |
715 | 306k | rDocumentHandler->startElement( XML_CHAR_TO_OUSTRING( pwName ) , |
716 | 306k | pImpl->rAttrList ) ); |
717 | 306k | } |
718 | | |
719 | | void SaxExpatParser_Impl::callbackEndElement( void *pvThis , const XML_Char *pwName ) |
720 | 290k | { |
721 | 290k | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
722 | | |
723 | 290k | if( pImpl->rDocumentHandler.is() ) { |
724 | 290k | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, |
725 | 290k | rDocumentHandler->endElement( XML_CHAR_TO_OUSTRING( pwName ) ) ); |
726 | 290k | } |
727 | 290k | } |
728 | | |
729 | | |
730 | | void SaxExpatParser_Impl::callbackCharacters( void *pvThis , const XML_Char *s , int nLen ) |
731 | 36.2k | { |
732 | 36.2k | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
733 | | |
734 | 36.2k | if( pImpl->rDocumentHandler.is() ) { |
735 | 36.2k | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl , |
736 | 36.2k | rDocumentHandler->characters( XML_CHAR_N_TO_USTRING(s,nLen) ) ); |
737 | 36.2k | } |
738 | 36.2k | } |
739 | | |
740 | | void SaxExpatParser_Impl::callbackProcessingInstruction( void *pvThis, |
741 | | const XML_Char *sTarget , |
742 | | const XML_Char *sData ) |
743 | 945 | { |
744 | 945 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
745 | 945 | if( pImpl->rDocumentHandler.is() ) { |
746 | 945 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( |
747 | 945 | pImpl , |
748 | 945 | rDocumentHandler->processingInstruction( XML_CHAR_TO_OUSTRING( sTarget ), |
749 | 945 | XML_CHAR_TO_OUSTRING( sData ) ) ); |
750 | 945 | } |
751 | 945 | } |
752 | | |
753 | | |
754 | | void SaxExpatParser_Impl::callbackEntityDecl( |
755 | | void *pvThis, const XML_Char *entityName, |
756 | | SAL_UNUSED_PARAMETER int /*is_parameter_entity*/, |
757 | | const XML_Char *value, SAL_UNUSED_PARAMETER int /*value_length*/, |
758 | | SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId, |
759 | | const XML_Char *publicId, const XML_Char *notationName) |
760 | 2 | { |
761 | 2 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
762 | 2 | if (value) { // value != 0 means internal entity |
763 | 2 | SAL_INFO("sax","SaxExpatParser: internal entity declaration, stopping"); |
764 | 2 | XML_StopParser(pImpl->getEntity().pParser, XML_FALSE); |
765 | 2 | pImpl->exception = SAXParseException( |
766 | 2 | u"SaxExpatParser: internal entity declaration, stopping"_ustr, |
767 | 2 | nullptr, css::uno::Any(), |
768 | 2 | pImpl->rDocumentLocator->getPublicId(), |
769 | 2 | pImpl->rDocumentLocator->getSystemId(), |
770 | 2 | pImpl->rDocumentLocator->getLineNumber(), |
771 | 2 | pImpl->rDocumentLocator->getColumnNumber() ); |
772 | 2 | pImpl->bExceptionWasThrown = true; |
773 | 2 | } else { |
774 | 0 | if( pImpl->rDTDHandler.is() ) { |
775 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( |
776 | 0 | pImpl , |
777 | 0 | rDTDHandler->unparsedEntityDecl( |
778 | 0 | XML_CHAR_TO_OUSTRING( entityName ), |
779 | 0 | XML_CHAR_TO_OUSTRING( publicId ) , |
780 | 0 | XML_CHAR_TO_OUSTRING( systemId ) , |
781 | 0 | XML_CHAR_TO_OUSTRING( notationName ) ) ); |
782 | 0 | } |
783 | 0 | } |
784 | 2 | } |
785 | | |
786 | | void SaxExpatParser_Impl::callbackNotationDecl( |
787 | | void *pvThis, const XML_Char *notationName, |
788 | | SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId, |
789 | | const XML_Char *publicId) |
790 | 0 | { |
791 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
792 | 0 | if( pImpl->rDTDHandler.is() ) { |
793 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, |
794 | 0 | rDTDHandler->notationDecl( XML_CHAR_TO_OUSTRING( notationName ) , |
795 | 0 | XML_CHAR_TO_OUSTRING( publicId ) , |
796 | 0 | XML_CHAR_TO_OUSTRING( systemId ) ) ); |
797 | 0 | } |
798 | |
|
799 | 0 | } |
800 | | |
801 | | |
802 | | bool SaxExpatParser_Impl::callbackExternalEntityRef( |
803 | | XML_Parser parser, const XML_Char *context, |
804 | | SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId, |
805 | | const XML_Char *publicId) |
806 | 0 | { |
807 | 0 | bool bOK = true; |
808 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(XML_GetUserData( parser )); |
809 | |
|
810 | 0 | struct Entity entity; |
811 | |
|
812 | 0 | if( pImpl->rEntityResolver.is() ) { |
813 | 0 | try |
814 | 0 | { |
815 | 0 | entity.structSource = pImpl->rEntityResolver->resolveEntity( |
816 | 0 | XML_CHAR_TO_OUSTRING( publicId ) , |
817 | 0 | XML_CHAR_TO_OUSTRING( systemId ) ); |
818 | 0 | } |
819 | 0 | catch( const SAXParseException & e ) |
820 | 0 | { |
821 | 0 | pImpl->exception = e; |
822 | 0 | bOK = false; |
823 | 0 | } |
824 | 0 | catch( const SAXException & e ) |
825 | 0 | { |
826 | 0 | pImpl->exception = SAXParseException( |
827 | 0 | e.Message , e.Context , e.WrappedException , |
828 | 0 | pImpl->rDocumentLocator->getPublicId(), |
829 | 0 | pImpl->rDocumentLocator->getSystemId(), |
830 | 0 | pImpl->rDocumentLocator->getLineNumber(), |
831 | 0 | pImpl->rDocumentLocator->getColumnNumber() ); |
832 | 0 | bOK = false; |
833 | 0 | } |
834 | 0 | } |
835 | |
|
836 | 0 | if( entity.structSource.aInputStream.is() ) { |
837 | 0 | entity.pParser = XML_ExternalEntityParserCreate( parser , context, nullptr ); |
838 | 0 | if( ! entity.pParser ) |
839 | 0 | { |
840 | 0 | return false; |
841 | 0 | } |
842 | | |
843 | 0 | entity.converter.setInputStream( entity.structSource.aInputStream ); |
844 | 0 | auto const xmlParser = entity.pParser; |
845 | 0 | pImpl->pushEntity( std::move(entity) ); |
846 | 0 | try |
847 | 0 | { |
848 | 0 | pImpl->parse(); |
849 | 0 | } |
850 | 0 | catch( const SAXParseException & e ) |
851 | 0 | { |
852 | 0 | pImpl->exception = e; |
853 | 0 | bOK = false; |
854 | 0 | } |
855 | 0 | catch( const IOException &e ) |
856 | 0 | { |
857 | 0 | pImpl->exception.WrappedException <<= e; |
858 | 0 | bOK = false; |
859 | 0 | } |
860 | 0 | catch( const css::uno::RuntimeException &e ) |
861 | 0 | { |
862 | 0 | pImpl->exception.WrappedException <<=e; |
863 | 0 | bOK = false; |
864 | 0 | } |
865 | |
|
866 | 0 | pImpl->popEntity(); |
867 | |
|
868 | 0 | XML_ParserFree( xmlParser ); |
869 | 0 | } |
870 | | |
871 | 0 | return bOK; |
872 | 0 | } |
873 | | |
874 | | int SaxExpatParser_Impl::callbackUnknownEncoding( |
875 | | SAL_UNUSED_PARAMETER void * /*encodingHandlerData*/, |
876 | | SAL_UNUSED_PARAMETER const XML_Char * /*name*/, |
877 | | SAL_UNUSED_PARAMETER XML_Encoding * /*info*/) |
878 | 1 | { |
879 | 1 | return 0; |
880 | 1 | } |
881 | | |
882 | | void SaxExpatParser_Impl::callbackDefault( void *pvThis, const XML_Char *s, int len) |
883 | 0 | { |
884 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
885 | |
|
886 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, |
887 | 0 | rExtendedDocumentHandler->unknown( XML_CHAR_N_TO_USTRING( s ,len) ) ); |
888 | 0 | } |
889 | | |
890 | | void SaxExpatParser_Impl::callbackComment( void *pvThis , const XML_Char *s ) |
891 | 0 | { |
892 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
893 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, |
894 | 0 | rExtendedDocumentHandler->comment( XML_CHAR_TO_OUSTRING( s ) ) ); |
895 | 0 | } |
896 | | |
897 | | void SaxExpatParser_Impl::callbackStartCDATA( void *pvThis ) |
898 | 0 | { |
899 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
900 | |
|
901 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS( pImpl, rExtendedDocumentHandler->startCDATA() ); |
902 | 0 | } |
903 | | |
904 | | |
905 | | void SaxExpatParser_Impl::callErrorHandler( SaxExpatParser_Impl *pImpl , |
906 | | const SAXParseException & e ) |
907 | 28 | { |
908 | 28 | try |
909 | 28 | { |
910 | 28 | if( pImpl->rErrorHandler.is() ) { |
911 | 0 | css::uno::Any a; |
912 | 0 | a <<= e; |
913 | 0 | pImpl->rErrorHandler->error( a ); |
914 | 0 | } |
915 | 28 | else { |
916 | 28 | pImpl->exception = e; |
917 | 28 | pImpl->bExceptionWasThrown = true; |
918 | 28 | } |
919 | 28 | } |
920 | 28 | catch( const SAXParseException & ex ) { |
921 | 0 | pImpl->exception = ex; |
922 | 0 | pImpl->bExceptionWasThrown = true; |
923 | 0 | } |
924 | 28 | catch( const SAXException & ex ) { |
925 | 0 | pImpl->exception = SAXParseException( |
926 | 0 | ex.Message, |
927 | 0 | ex.Context, |
928 | 0 | ex.WrappedException, |
929 | 0 | pImpl->rDocumentLocator->getPublicId(), |
930 | 0 | pImpl->rDocumentLocator->getSystemId(), |
931 | 0 | pImpl->rDocumentLocator->getLineNumber(), |
932 | 0 | pImpl->rDocumentLocator->getColumnNumber() |
933 | 0 | ); |
934 | 0 | pImpl->bExceptionWasThrown = true; |
935 | 0 | } |
936 | 28 | } |
937 | | |
938 | | void SaxExpatParser_Impl::callbackEndCDATA( void *pvThis ) |
939 | 0 | { |
940 | 0 | SaxExpatParser_Impl *pImpl = static_cast<SaxExpatParser_Impl*>(pvThis); |
941 | |
|
942 | 0 | CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS(pImpl,rExtendedDocumentHandler->endCDATA() ); |
943 | 0 | } |
944 | | |
945 | | } // namespace |
946 | | |
947 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * |
948 | | com_sun_star_comp_extensions_xml_sax_ParserExpat_get_implementation( |
949 | | css::uno::XComponentContext *, |
950 | | css::uno::Sequence<css::uno::Any> const &) |
951 | 40.8k | { |
952 | 40.8k | return cppu::acquire(new SaxExpatParser); |
953 | 40.8k | } |
954 | | |
955 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |