Line data Source code
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 "sax/fastparser.hxx"
21 : #include "sax/fastattribs.hxx"
22 : #include "xml2utf.hxx"
23 :
24 : #include <com/sun/star/lang/DisposedException.hpp>
25 : #include <com/sun/star/uno/XComponentContext.hpp>
26 : #include <com/sun/star/xml/sax/FastToken.hpp>
27 : #include <com/sun/star/xml/sax/SAXParseException.hpp>
28 : #include <com/sun/star/xml/sax/XFastContextHandler.hpp>
29 : #include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
30 : #include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
31 : #include <cppuhelper/supportsservice.hxx>
32 : #include <cppuhelper/exc_hlp.hxx>
33 : #include <osl/conditn.hxx>
34 : #include <osl/diagnose.h>
35 : #include <rtl/ref.hxx>
36 : #include <rtl/ustrbuf.hxx>
37 : #include <sal/log.hxx>
38 : #include <salhelper/thread.hxx>
39 :
40 : #include <boost/optional.hpp>
41 : #include <boost/scoped_ptr.hpp>
42 : #include <boost/shared_ptr.hpp>
43 : #include <stack>
44 : #include <unordered_map>
45 : #include <vector>
46 : #include <queue>
47 : #include <cassert>
48 : #include <cstring>
49 : #include <libxml/parser.h>
50 :
51 : // Inverse of libxml's BAD_CAST.
52 : #define XML_CAST( str ) reinterpret_cast< const sal_Char* >( str )
53 :
54 : using namespace ::std;
55 : using namespace ::osl;
56 : using namespace ::cppu;
57 : using namespace ::com::sun::star::uno;
58 : using namespace ::com::sun::star::lang;
59 : using namespace ::com::sun::star::xml::sax;
60 : using namespace ::com::sun::star::io;
61 : using namespace com::sun::star;
62 : using namespace sax_fastparser;
63 :
64 : namespace {
65 :
66 : struct Event;
67 : class FastLocatorImpl;
68 : struct NamespaceDefine;
69 : struct Entity;
70 :
71 : typedef ::boost::shared_ptr< NamespaceDefine > NamespaceDefineRef;
72 :
73 : typedef std::unordered_map< OUString, sal_Int32,
74 : OUStringHash, ::std::equal_to< OUString > > NamespaceMap;
75 :
76 : typedef std::vector<Event> EventList;
77 :
78 : enum CallbackType { INVALID, START_ELEMENT, END_ELEMENT, CHARACTERS, DONE, EXCEPTION };
79 :
80 3717276 : struct Event
81 : {
82 : CallbackType maType;
83 : sal_Int32 mnElementToken;
84 : OUString msNamespace;
85 : OUString msElementName;
86 : rtl::Reference< FastAttributeList > mxAttributes;
87 : OUString msChars;
88 : };
89 :
90 7296051 : struct NameWithToken
91 : {
92 : OUString msName;
93 : sal_Int32 mnToken;
94 :
95 2432017 : NameWithToken(const OUString& sName, const sal_Int32& nToken) :
96 2432017 : msName(sName), mnToken(nToken) {}
97 : };
98 :
99 7296045 : struct SaxContext
100 : {
101 : Reference< XFastContextHandler > mxContext;
102 : sal_Int32 mnElementToken;
103 : OUString maNamespace;
104 : OUString maElementName;
105 :
106 2432018 : SaxContext( sal_Int32 nElementToken, const OUString& aNamespace, const OUString& aElementName ):
107 2432018 : mnElementToken(nElementToken)
108 : {
109 2432018 : if (nElementToken == FastToken::DONTKNOW)
110 : {
111 7443 : maNamespace = aNamespace;
112 7443 : maElementName = aElementName;
113 : }
114 2432018 : }
115 : };
116 :
117 :
118 44638 : struct ParserData
119 : {
120 : ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler > mxDocumentHandler;
121 : ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler > mxTokenHandler;
122 : FastTokenHandlerBase *mpTokenHandler;
123 : ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XErrorHandler > mxErrorHandler;
124 : ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XEntityResolver > mxEntityResolver;
125 : ::com::sun::star::lang::Locale maLocale;
126 :
127 : ParserData();
128 : ~ParserData();
129 : };
130 :
131 106393 : struct NamespaceDefine
132 : {
133 : OString maPrefix;
134 : sal_Int32 mnToken;
135 : OUString maNamespaceURL;
136 :
137 106393 : NamespaceDefine( const OString& rPrefix, sal_Int32 nToken, const OUString& rNamespaceURL ) : maPrefix( rPrefix ), mnToken( nToken ), maNamespaceURL( rNamespaceURL ) {}
138 : };
139 :
140 : // Entity binds all information needed for a single file | single call of parseStream
141 : struct Entity : public ParserData
142 : {
143 : // Amount of work producer sends to consumer in one iteration:
144 : static const size_t mnEventListSize = 1000;
145 :
146 : // unique for each Entity instance:
147 :
148 : // Number of valid events in mpProducedEvents:
149 : size_t mnProducedEventsSize;
150 : EventList *mpProducedEvents;
151 : std::queue< EventList * > maPendingEvents;
152 : std::queue< EventList * > maUsedEvents;
153 : osl::Mutex maEventProtector;
154 :
155 : static const size_t mnEventLowWater = 4;
156 : static const size_t mnEventHighWater = 8;
157 : osl::Condition maConsumeResume;
158 : osl::Condition maProduceResume;
159 : // Event we use to store data if threading is disabled:
160 : Event maSharedEvent;
161 :
162 : // copied in copy constructor:
163 :
164 : // Allow to disable threading for small documents:
165 : bool mbEnableThreads;
166 : ::com::sun::star::xml::sax::InputSource maStructSource;
167 : xmlParserCtxtPtr mpParser;
168 : ::sax_expatwrap::XMLFile2UTFConverter maConverter;
169 :
170 : // Exceptions cannot be thrown through the C-XmlParser (possible
171 : // resource leaks), therefore any exception thrown by a UNO callback
172 : // must be saved somewhere until the C-XmlParser is stopped.
173 : ::com::sun::star::uno::Any maSavedException;
174 : void saveException( const Any & e );
175 : void throwException( const ::rtl::Reference< FastLocatorImpl > &xDocumentLocator,
176 : bool mbDuringParse );
177 :
178 : ::std::stack< NameWithToken > maNamespaceStack;
179 : /* Context for main thread consuming events.
180 : * startElement() stores the data, which characters() and endElement() uses
181 : */
182 : ::std::stack< SaxContext> maContextStack;
183 : // Determines which elements of maNamespaceDefines are valid in current context
184 : ::std::stack< sal_uInt32 > maNamespaceCount;
185 : ::std::vector< NamespaceDefineRef > maNamespaceDefines;
186 :
187 : explicit Entity( const ParserData& rData );
188 : Entity( const Entity& rEntity );
189 : ~Entity();
190 : void startElement( Event *pEvent );
191 : void characters( const OUString& sChars );
192 : void endElement();
193 : EventList* getEventList();
194 : Event& getEvent( CallbackType aType );
195 : };
196 :
197 : } // namespace
198 :
199 : namespace sax_fastparser {
200 :
201 : class FastSaxParserImpl
202 : {
203 : public:
204 : FastSaxParserImpl( FastSaxParser* pFront );
205 : ~FastSaxParserImpl();
206 :
207 : // XFastParser
208 : void parseStream( const ::com::sun::star::xml::sax::InputSource& aInputSource ) throw (::com::sun::star::xml::sax::SAXException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception);
209 : void setFastDocumentHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastDocumentHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
210 : void setTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
211 : void registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
212 : OUString getNamespaceURL( const OUString& rPrefix ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
213 : void setErrorHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XErrorHandler >& Handler ) throw (::com::sun::star::uno::RuntimeException);
214 : void setEntityResolver( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XEntityResolver >& Resolver ) throw (::com::sun::star::uno::RuntimeException);
215 : void setLocale( const ::com::sun::star::lang::Locale& rLocale ) throw (::com::sun::star::uno::RuntimeException);
216 :
217 : // called by the C callbacks of the expat parser
218 : void callbackStartElement( const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
219 : int numNamespaces, const xmlChar** namespaces, int numAttributes, int defaultedAttributes, const xmlChar **attributes );
220 : void callbackEndElement( const xmlChar* localName, const xmlChar* prefix, const xmlChar* URI );
221 : void callbackCharacters( const xmlChar* s, int nLen );
222 : #if 0
223 : bool callbackExternalEntityRef( XML_Parser parser, const xmlChar *openEntityNames, const xmlChar *base, const xmlChar *systemId, const xmlChar *publicId);
224 : void callbackEntityDecl(const xmlChar *entityName, int is_parameter_entity,
225 : const xmlChar *value, int value_length, const xmlChar *base,
226 : const xmlChar *systemId, const xmlChar *publicId,
227 : const xmlChar *notationName);
228 : #endif
229 :
230 : void pushEntity( const Entity& rEntity );
231 : void popEntity();
232 24936891 : Entity& getEntity() { return *mpTop; }
233 0 : const Entity& getEntity() const { return *mpTop; }
234 : void parse();
235 : void produce( bool bForceFlush = false );
236 :
237 : bool hasNamespaceURL( const OUString& rPrefix ) const;
238 :
239 : private:
240 : bool consume(EventList *);
241 : void deleteUsedEvents();
242 : void sendPendingCharacters();
243 :
244 : sal_Int32 GetToken( const xmlChar* pName, sal_Int32 nameLen );
245 : sal_Int32 GetTokenWithPrefix( const xmlChar* pPrefix, int prefixLen, const xmlChar* pName, int nameLen ) throw (::com::sun::star::xml::sax::SAXException);
246 : OUString GetNamespaceURL( const OString& rPrefix ) throw (::com::sun::star::xml::sax::SAXException);
247 : sal_Int32 GetNamespaceToken( const OUString& rNamespaceURL );
248 : sal_Int32 GetTokenWithContextNamespace( sal_Int32 nNamespaceToken, const xmlChar* pName, int nNameLen );
249 : void DefineNamespace( const OString& rPrefix, const OUString& namespaceURL );
250 :
251 : private:
252 : #if 0
253 : FastSaxParser* mpFront;
254 : #endif
255 : osl::Mutex maMutex; ///< Protecting whole parseStream() execution
256 : ::rtl::Reference< FastLocatorImpl > mxDocumentLocator;
257 : NamespaceMap maNamespaceMap;
258 :
259 : ParserData maData; /// Cached parser configuration for next call of parseStream().
260 :
261 : Entity *mpTop; /// std::stack::top() is amazingly slow => cache this.
262 : ::std::stack< Entity > maEntities; /// Entity stack for each call of parseStream().
263 : OUString pendingCharacters; /// Data from characters() callback that needs to be sent.
264 : };
265 :
266 : } // namespace sax_fastparser
267 :
268 : namespace {
269 :
270 3136 : class ParserThread: public salhelper::Thread
271 : {
272 : FastSaxParserImpl *mpParser;
273 : public:
274 1568 : ParserThread(FastSaxParserImpl *pParser): Thread("Parser"), mpParser(pParser) {}
275 : private:
276 1568 : virtual void execute() SAL_OVERRIDE
277 : {
278 : try
279 : {
280 1568 : mpParser->parse();
281 : }
282 0 : catch (const Exception &)
283 : {
284 0 : Entity &rEntity = mpParser->getEntity();
285 0 : rEntity.getEvent( EXCEPTION );
286 0 : mpParser->produce( true );
287 : }
288 1568 : }
289 : };
290 :
291 : extern "C" {
292 :
293 2432018 : static void call_callbackStartElement(void *userData, const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
294 : int numNamespaces, const xmlChar** namespaces, int numAttributes, int defaultedAttributes, const xmlChar **attributes)
295 : {
296 2432018 : FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
297 2432018 : pFastParser->callbackStartElement( localName, prefix, URI, numNamespaces, namespaces, numAttributes, defaultedAttributes, attributes );
298 2432018 : }
299 :
300 2432011 : static void call_callbackEndElement(void *userData, const xmlChar* localName, const xmlChar* prefix, const xmlChar* URI)
301 : {
302 2432011 : FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
303 2432011 : pFastParser->callbackEndElement( localName, prefix, URI );
304 2432011 : }
305 :
306 179028 : static void call_callbackCharacters( void *userData , const xmlChar *s , int nLen )
307 : {
308 179028 : FastSaxParserImpl* pFastParser = static_cast<FastSaxParserImpl*>( userData );
309 179028 : pFastParser->callbackCharacters( s, nLen );
310 179028 : }
311 :
312 : #if 0
313 : static void call_callbackEntityDecl(void *userData, const xmlChar *entityName,
314 : int is_parameter_entity, const xmlChar *value, int value_length,
315 : const xmlChar *base, const xmlChar *systemId,
316 : const xmlChar *publicId, const xmlChar *notationName)
317 : {
318 : FastSaxParserImpl* pFastParser = reinterpret_cast<FastSaxParserImpl*>(userData);
319 : pFastParser->callbackEntityDecl(entityName, is_parameter_entity, value,
320 : value_length, base, systemId, publicId, notationName);
321 : }
322 :
323 : static int call_callbackExternalEntityRef( XML_Parser parser,
324 : const xmlChar *openEntityNames, const xmlChar *base, const xmlChar *systemId, const xmlChar *publicId )
325 : {
326 : FastSaxParserImpl* pFastParser = reinterpret_cast<FastSaxParserImpl*>( XML_GetUserData( parser ) );
327 : return pFastParser->callbackExternalEntityRef( parser, openEntityNames, base, systemId, publicId );
328 : }
329 : #endif
330 : }
331 :
332 60010 : class FastLocatorImpl : public WeakImplHelper1< XLocator >
333 : {
334 : public:
335 30005 : FastLocatorImpl( FastSaxParserImpl *p ) : mpParser(p) {}
336 :
337 30005 : void dispose() { mpParser = 0; }
338 12 : void checkDispose() throw (RuntimeException) { if( !mpParser ) throw DisposedException(); }
339 :
340 : //XLocator
341 : virtual sal_Int32 SAL_CALL getColumnNumber() throw (RuntimeException, std::exception) SAL_OVERRIDE;
342 : virtual sal_Int32 SAL_CALL getLineNumber() throw (RuntimeException, std::exception) SAL_OVERRIDE;
343 : virtual OUString SAL_CALL getPublicId() throw (RuntimeException, std::exception) SAL_OVERRIDE;
344 : virtual OUString SAL_CALL getSystemId() throw (RuntimeException, std::exception) SAL_OVERRIDE;
345 :
346 : private:
347 : FastSaxParserImpl *mpParser;
348 : };
349 :
350 2 : sal_Int32 SAL_CALL FastLocatorImpl::getColumnNumber() throw (RuntimeException, std::exception)
351 : {
352 2 : checkDispose();
353 2 : return xmlSAX2GetColumnNumber( mpParser->getEntity().mpParser );
354 : }
355 :
356 4 : sal_Int32 SAL_CALL FastLocatorImpl::getLineNumber() throw (RuntimeException, std::exception)
357 : {
358 4 : checkDispose();
359 4 : return xmlSAX2GetLineNumber( mpParser->getEntity().mpParser );
360 : }
361 :
362 2 : OUString SAL_CALL FastLocatorImpl::getPublicId() throw (RuntimeException, std::exception)
363 : {
364 2 : checkDispose();
365 2 : return mpParser->getEntity().maStructSource.sPublicId;
366 : }
367 :
368 4 : OUString SAL_CALL FastLocatorImpl::getSystemId() throw (RuntimeException, std::exception)
369 : {
370 4 : checkDispose();
371 4 : return mpParser->getEntity().maStructSource.sSystemId;
372 : }
373 :
374 30005 : ParserData::ParserData()
375 30005 : : mpTokenHandler( NULL )
376 30005 : {}
377 :
378 74643 : ParserData::~ParserData()
379 74643 : {}
380 :
381 22427 : Entity::Entity(const ParserData& rData)
382 : : ParserData(rData)
383 : , mnProducedEventsSize(0)
384 : , mpProducedEvents(NULL)
385 : , mbEnableThreads(false)
386 22427 : , mpParser(NULL)
387 : {
388 22427 : }
389 :
390 22211 : Entity::Entity(const Entity& e)
391 : : ParserData(e)
392 : , mnProducedEventsSize(0)
393 : , mpProducedEvents(NULL)
394 : , mbEnableThreads(e.mbEnableThreads)
395 : , maStructSource(e.maStructSource)
396 : , mpParser(e.mpParser)
397 : , maConverter(e.maConverter)
398 : , maSavedException(e.maSavedException)
399 : , maNamespaceStack(e.maNamespaceStack)
400 : , maContextStack(e.maContextStack)
401 : , maNamespaceCount(e.maNamespaceCount)
402 22211 : , maNamespaceDefines(e.maNamespaceDefines)
403 : {
404 22211 : }
405 :
406 44638 : Entity::~Entity()
407 : {
408 44638 : }
409 :
410 2432015 : void Entity::startElement( Event *pEvent )
411 : {
412 2432015 : const sal_Int32& nElementToken = pEvent->mnElementToken;
413 2432015 : const OUString& aNamespace = pEvent->msNamespace;
414 2432015 : const OUString& aElementName = pEvent->msElementName;
415 :
416 : // Use un-wrapped pointers to avoid significant acquire/release overhead
417 2432015 : XFastContextHandler *pParentContext = NULL;
418 2432015 : if( !maContextStack.empty() )
419 : {
420 2409806 : pParentContext = maContextStack.top().mxContext.get();
421 2409807 : if( !pParentContext )
422 : {
423 83657 : maContextStack.push( SaxContext(nElementToken, aNamespace, aElementName) );
424 2515675 : return;
425 : }
426 : }
427 :
428 2348361 : maContextStack.push( SaxContext( nElementToken, aNamespace, aElementName ) );
429 :
430 : try
431 : {
432 2348358 : Reference< XFastAttributeList > xAttr( pEvent->mxAttributes.get() );
433 4696722 : Reference< XFastContextHandler > xContext;
434 2348361 : if( nElementToken == FastToken::DONTKNOW )
435 : {
436 6452 : if( pParentContext )
437 5953 : xContext = pParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr );
438 499 : else if( mxDocumentHandler.is() )
439 497 : xContext = mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
440 :
441 6452 : if( xContext.is() )
442 : {
443 6136 : xContext->startUnknownElement( aNamespace, aElementName, xAttr );
444 : }
445 : }
446 : else
447 : {
448 2341909 : if( pParentContext )
449 2320197 : xContext = pParentContext->createFastChildContext( nElementToken, xAttr );
450 21712 : else if( mxDocumentHandler.is() )
451 21712 : xContext = mxDocumentHandler->createFastChildContext( nElementToken, xAttr );
452 :
453 2341907 : if( xContext.is() )
454 2268221 : xContext->startFastElement( nElementToken, xAttr );
455 : }
456 : // swap the reference we own in to avoid referencing thrash.
457 2348360 : maContextStack.top().mxContext.set( static_cast<XFastContextHandler *>( xContext.get() ) );
458 4696720 : xContext.set( NULL, UNO_REF_NO_ACQUIRE );
459 : }
460 1 : catch (const Exception&)
461 : {
462 1 : saveException( ::cppu::getCaughtException() );
463 : }
464 : }
465 :
466 173437 : void Entity::characters( const OUString& sChars )
467 : {
468 173437 : if (maContextStack.empty())
469 : {
470 : // Malformed XML stream !?
471 173437 : return;
472 : }
473 :
474 173437 : const Reference< XFastContextHandler >& xContext( maContextStack.top().mxContext );
475 173437 : if( xContext.is() ) try
476 : {
477 168427 : xContext->characters( sChars );
478 : }
479 0 : catch (const Exception&)
480 : {
481 0 : saveException( ::cppu::getCaughtException() );
482 : }
483 : }
484 :
485 2432010 : void Entity::endElement()
486 : {
487 2432010 : if (maContextStack.empty())
488 : {
489 : // Malformed XML stream !?
490 2432011 : return;
491 : }
492 :
493 2432009 : const SaxContext& aContext = maContextStack.top();
494 2432011 : const Reference< XFastContextHandler >& xContext( aContext.mxContext );
495 2432011 : if( xContext.is() ) try
496 : {
497 2274349 : sal_Int32 nElementToken = aContext.mnElementToken;
498 2274349 : if( nElementToken != FastToken::DONTKNOW )
499 2268213 : xContext->endFastElement( nElementToken );
500 : else
501 6136 : xContext->endUnknownElement( aContext.maNamespace, aContext.maElementName );
502 : }
503 0 : catch (const Exception&)
504 : {
505 0 : saveException( ::cppu::getCaughtException() );
506 : }
507 2432008 : maContextStack.pop();
508 : }
509 :
510 1150196 : EventList* Entity::getEventList()
511 : {
512 1150196 : if (!mpProducedEvents)
513 : {
514 1904 : osl::ResettableMutexGuard aGuard(maEventProtector);
515 1904 : if (!maUsedEvents.empty())
516 : {
517 90 : mpProducedEvents = maUsedEvents.front();
518 90 : maUsedEvents.pop();
519 90 : aGuard.clear(); // unlock
520 90 : mnProducedEventsSize = 0;
521 : }
522 1904 : if (!mpProducedEvents)
523 : {
524 1814 : mpProducedEvents = new EventList();
525 1814 : mpProducedEvents->resize(mnEventListSize);
526 1814 : mnProducedEventsSize = 0;
527 1904 : }
528 : }
529 1150196 : return mpProducedEvents;
530 : }
531 :
532 5059675 : Event& Entity::getEvent( CallbackType aType )
533 : {
534 5059675 : if (!mbEnableThreads)
535 3909479 : return maSharedEvent;
536 :
537 1150196 : EventList* pEventList = getEventList();
538 1150196 : Event& rEvent = (*pEventList)[mnProducedEventsSize++];
539 1150196 : rEvent.maType = aType;
540 1150196 : return rEvent;
541 : }
542 :
543 2 : OUString lclGetErrorMessage( xmlParserCtxtPtr ctxt, const OUString& sSystemId, sal_Int32 nLine )
544 : {
545 : const sal_Char* pMessage;
546 2 : xmlErrorPtr error = xmlCtxtGetLastError( ctxt );
547 2 : if( error && error->message )
548 2 : pMessage = error->message;
549 : else
550 0 : pMessage = "unknown error";
551 2 : OUStringBuffer aBuffer( "[" );
552 2 : aBuffer.append( sSystemId );
553 2 : aBuffer.append( " line " );
554 2 : aBuffer.append( nLine );
555 2 : aBuffer.append( "]: " );
556 2 : aBuffer.appendAscii( pMessage );
557 2 : return aBuffer.makeStringAndClear();
558 : }
559 :
560 : // throw an exception, but avoid callback if
561 : // during a threaded produce
562 2 : void Entity::throwException( const ::rtl::Reference< FastLocatorImpl > &xDocumentLocator,
563 : bool mbDuringParse )
564 : {
565 : // Error during parsing !
566 : SAXParseException aExcept(
567 : lclGetErrorMessage( mpParser,
568 2 : xDocumentLocator->getSystemId(),
569 2 : xDocumentLocator->getLineNumber() ),
570 : Reference< XInterface >(),
571 2 : Any( &maSavedException, cppu::UnoType<decltype(maSavedException)>::get() ),
572 2 : xDocumentLocator->getPublicId(),
573 2 : xDocumentLocator->getSystemId(),
574 2 : xDocumentLocator->getLineNumber(),
575 2 : xDocumentLocator->getColumnNumber()
576 14 : );
577 :
578 : // error handler is set, it may throw the exception
579 2 : if( !mbDuringParse || !mbEnableThreads )
580 : {
581 2 : if (mxErrorHandler.is() )
582 0 : mxErrorHandler->fatalError( Any( aExcept ) );
583 : }
584 :
585 : // error handler has not thrown, but parsing must stop => throw ourselves
586 2 : throw aExcept;
587 : }
588 :
589 : // In the single threaded case we emit events via our C
590 : // callbacks, so any exception caught must be queued up until
591 : // we can safely re-throw it from our C++ parent of parse()
592 :
593 : // If multi-threaded, we need to push an EXCEPTION event, at
594 : // which point we transfer ownership of maSavedException to
595 : // the consuming thread.
596 1 : void Entity::saveException( const Any & e )
597 : {
598 : // fdo#81214 - allow the parser to run on after an exception,
599 : // unexpectedly some 'startElements' produce an UNO_QUERY_THROW
600 : // for XComponent; and yet expect to continue parsing.
601 : SAL_WARN("sax", "Unexpected exception from XML parser "
602 : << e.get<Exception>().Message);
603 1 : maSavedException = e;
604 1 : }
605 :
606 : } // namespace
607 :
608 : namespace sax_fastparser {
609 :
610 30005 : FastSaxParserImpl::FastSaxParserImpl( FastSaxParser* ) :
611 : #if 0
612 : mpFront(pFront),
613 : #endif
614 30005 : mpTop(NULL)
615 : {
616 30005 : mxDocumentLocator.set( new FastLocatorImpl( this ) );
617 30005 : }
618 :
619 60010 : FastSaxParserImpl::~FastSaxParserImpl()
620 : {
621 30005 : if( mxDocumentLocator.is() )
622 30005 : mxDocumentLocator->dispose();
623 30005 : }
624 :
625 106393 : void FastSaxParserImpl::DefineNamespace( const OString& rPrefix, const OUString& namespaceURL )
626 : {
627 106393 : Entity& rEntity = getEntity();
628 : assert(!rEntity.maNamespaceCount.empty()); // need a context!
629 :
630 106393 : sal_uInt32 nOffset = rEntity.maNamespaceCount.top()++;
631 106393 : if( rEntity.maNamespaceDefines.size() <= nOffset )
632 22211 : rEntity.maNamespaceDefines.resize( rEntity.maNamespaceDefines.size() + 64 );
633 :
634 106393 : rEntity.maNamespaceDefines[nOffset].reset( new NamespaceDefine( rPrefix, GetNamespaceToken( namespaceURL ), namespaceURL ) );
635 106393 : }
636 :
637 5687878 : sal_Int32 FastSaxParserImpl::GetToken( const xmlChar* pName, sal_Int32 nameLen /* = 0 */ )
638 : {
639 5687877 : return FastTokenHandlerBase::getTokenFromChars( getEntity().mxTokenHandler,
640 5687878 : getEntity().mpTokenHandler,
641 17063632 : XML_CAST( pName ), nameLen ); // uses utf-8
642 : }
643 :
644 4787166 : sal_Int32 FastSaxParserImpl::GetTokenWithPrefix( const xmlChar* pPrefix, int nPrefixLen, const xmlChar* pName, int nNameLen ) throw (SAXException)
645 : {
646 4787166 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
647 :
648 4787166 : Entity& rEntity = getEntity();
649 4787166 : if (rEntity.maNamespaceCount.empty())
650 0 : return nNamespaceToken;
651 :
652 4787166 : sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
653 21733218 : while( nNamespace-- )
654 : {
655 16946052 : const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix );
656 22353262 : if( (rPrefix.getLength() == nPrefixLen) &&
657 5407210 : (strncmp( rPrefix.getStr(), XML_CAST( pPrefix ), nPrefixLen ) == 0 ) )
658 : {
659 4787166 : nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken;
660 4787166 : break;
661 : }
662 :
663 12158886 : if( !nNamespace )
664 0 : throw SAXException("No namespace defined for " + OUString(XML_CAST(pPrefix),
665 0 : nPrefixLen, RTL_TEXTENCODING_UTF8), Reference< XInterface >(), Any());
666 : }
667 :
668 4787166 : if( nNamespaceToken != FastToken::DONTKNOW )
669 : {
670 4777119 : sal_Int32 nNameToken = GetToken( pName, nNameLen );
671 4777119 : if( nNameToken != FastToken::DONTKNOW )
672 4762821 : return nNamespaceToken | nNameToken;
673 : }
674 :
675 24345 : return FastToken::DONTKNOW;
676 : }
677 :
678 1489940 : sal_Int32 FastSaxParserImpl::GetNamespaceToken( const OUString& rNamespaceURL )
679 : {
680 1489940 : NamespaceMap::iterator aIter( maNamespaceMap.find( rNamespaceURL ) );
681 1489940 : if( aIter != maNamespaceMap.end() )
682 96316 : return (*aIter).second;
683 : else
684 1393624 : return FastToken::DONTKNOW;
685 : }
686 :
687 0 : OUString FastSaxParserImpl::GetNamespaceURL( const OString& rPrefix ) throw (SAXException)
688 : {
689 0 : Entity& rEntity = getEntity();
690 0 : if( !rEntity.maNamespaceCount.empty() )
691 : {
692 0 : sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
693 0 : while( nNamespace-- )
694 0 : if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix )
695 0 : return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL;
696 : }
697 :
698 0 : throw SAXException("No namespace defined for " + OUString::fromUtf8(rPrefix),
699 0 : Reference< XInterface >(), Any());
700 : }
701 :
702 109353 : sal_Int32 FastSaxParserImpl::GetTokenWithContextNamespace( sal_Int32 nNamespaceToken, const xmlChar* pName, int nNameLen )
703 : {
704 109353 : if( nNamespaceToken != FastToken::DONTKNOW )
705 : {
706 107547 : sal_Int32 nNameToken = GetToken( pName, nNameLen );
707 107547 : if( nNameToken != FastToken::DONTKNOW )
708 107546 : return nNamespaceToken | nNameToken;
709 : }
710 :
711 1807 : return FastToken::DONTKNOW;
712 : }
713 :
714 : /***************
715 : *
716 : * parseStream does Parser-startup initializations. The FastSaxParser::parse() method does
717 : * the file-specific initialization work. (During a parser run, external files may be opened)
718 : *
719 : ****************/
720 22427 : void FastSaxParserImpl::parseStream(const InputSource& maStructSource)
721 : throw (SAXException, IOException, RuntimeException, std::exception)
722 : {
723 22427 : xmlInitParser();
724 :
725 : // Only one text at one time
726 22427 : MutexGuard guard( maMutex );
727 :
728 44854 : Entity entity( maData );
729 22427 : entity.maStructSource = maStructSource;
730 :
731 22427 : if( !entity.mxTokenHandler.is() )
732 0 : throw SAXException("No token handler, use setTokenHandler()", Reference< XInterface >(), Any() );
733 :
734 22427 : if( !entity.maStructSource.aInputStream.is() )
735 216 : throw SAXException("No input source", Reference< XInterface >(), Any() );
736 :
737 22211 : entity.maConverter.setInputStream( entity.maStructSource.aInputStream );
738 22211 : if( !entity.maStructSource.sEncoding.isEmpty() )
739 0 : entity.maConverter.setEncoding( OUStringToOString( entity.maStructSource.sEncoding, RTL_TEXTENCODING_ASCII_US ) );
740 :
741 22211 : pushEntity( entity );
742 22211 : Entity& rEntity = getEntity();
743 : try
744 : {
745 : // start the document
746 22211 : if( rEntity.mxDocumentHandler.is() )
747 : {
748 22209 : Reference< XLocator > xLoc( mxDocumentLocator.get() );
749 22209 : rEntity.mxDocumentHandler->setDocumentLocator( xLoc );
750 22209 : rEntity.mxDocumentHandler->startDocument();
751 : }
752 :
753 22211 : rEntity.mbEnableThreads = (rEntity.maStructSource.aInputStream->available() > 10000);
754 :
755 22211 : if (rEntity.mbEnableThreads)
756 : {
757 1568 : rtl::Reference<ParserThread> xParser;
758 1568 : xParser = new ParserThread(this);
759 1568 : xParser->launch();
760 1568 : bool done = false;
761 1647 : do {
762 1647 : rEntity.maConsumeResume.wait();
763 1647 : rEntity.maConsumeResume.reset();
764 :
765 1647 : osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
766 5198 : while (!rEntity.maPendingEvents.empty())
767 : {
768 1904 : if (rEntity.maPendingEvents.size() <= rEntity.mnEventLowWater)
769 1883 : rEntity.maProduceResume.set(); // start producer again
770 :
771 1904 : EventList *pEventList = rEntity.maPendingEvents.front();
772 1904 : rEntity.maPendingEvents.pop();
773 1904 : aGuard.clear(); // unlock
774 :
775 1904 : if (!consume(pEventList))
776 1568 : done = true;
777 :
778 1904 : aGuard.reset(); // lock
779 1904 : rEntity.maUsedEvents.push(pEventList);
780 1647 : }
781 1647 : } while (!done);
782 1568 : xParser->join();
783 1568 : deleteUsedEvents();
784 : }
785 : else
786 : {
787 20643 : parse();
788 : }
789 :
790 : // finish document
791 22209 : if( rEntity.mxDocumentHandler.is() )
792 : {
793 22208 : rEntity.mxDocumentHandler->endDocument();
794 : }
795 : }
796 4 : catch (const SAXException&)
797 : {
798 : // TODO free mpParser.myDoc ?
799 2 : xmlFreeParserCtxt( rEntity.mpParser );
800 2 : popEntity();
801 2 : throw;
802 : }
803 0 : catch (const IOException&)
804 : {
805 0 : xmlFreeParserCtxt( rEntity.mpParser );
806 0 : popEntity();
807 0 : throw;
808 : }
809 0 : catch (const RuntimeException&)
810 : {
811 0 : xmlFreeParserCtxt( rEntity.mpParser );
812 0 : popEntity();
813 0 : throw;
814 : }
815 :
816 22209 : xmlFreeParserCtxt( rEntity.mpParser );
817 44636 : popEntity();
818 22209 : }
819 :
820 28567 : void FastSaxParserImpl::setFastDocumentHandler( const Reference< XFastDocumentHandler >& Handler ) throw (RuntimeException)
821 : {
822 28567 : maData.mxDocumentHandler = Handler;
823 28567 : }
824 :
825 30003 : void FastSaxParserImpl::setTokenHandler( const Reference< XFastTokenHandler >& xHandler ) throw (RuntimeException)
826 : {
827 30003 : maData.mxTokenHandler = xHandler;
828 30003 : maData.mpTokenHandler = dynamic_cast< FastTokenHandlerBase *>( xHandler.get() );
829 30003 : }
830 :
831 1368704 : void FastSaxParserImpl::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (IllegalArgumentException, RuntimeException)
832 : {
833 1368704 : if( NamespaceToken >= FastToken::NAMESPACE )
834 : {
835 1368704 : if( GetNamespaceToken( NamespaceURL ) == FastToken::DONTKNOW )
836 : {
837 1368704 : maNamespaceMap[ NamespaceURL ] = NamespaceToken;
838 2737408 : return;
839 : }
840 : }
841 0 : throw IllegalArgumentException();
842 : }
843 :
844 0 : OUString FastSaxParserImpl::getNamespaceURL( const OUString& rPrefix ) throw(IllegalArgumentException, RuntimeException)
845 : {
846 : try
847 : {
848 0 : return GetNamespaceURL( OUStringToOString( rPrefix, RTL_TEXTENCODING_UTF8 ) );
849 : }
850 0 : catch (const Exception&)
851 : {
852 : }
853 0 : throw IllegalArgumentException();
854 : }
855 :
856 0 : void FastSaxParserImpl::setErrorHandler(const Reference< XErrorHandler > & Handler) throw (RuntimeException)
857 : {
858 0 : maData.mxErrorHandler = Handler;
859 0 : }
860 :
861 0 : void FastSaxParserImpl::setEntityResolver(const Reference < XEntityResolver > & Resolver) throw (RuntimeException)
862 : {
863 0 : maData.mxEntityResolver = Resolver;
864 0 : }
865 :
866 0 : void FastSaxParserImpl::setLocale( const lang::Locale & Locale ) throw (RuntimeException)
867 : {
868 0 : maData.maLocale = Locale;
869 0 : }
870 :
871 1568 : void FastSaxParserImpl::deleteUsedEvents()
872 : {
873 1568 : Entity& rEntity = getEntity();
874 1568 : osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
875 :
876 4950 : while (!rEntity.maUsedEvents.empty())
877 : {
878 1814 : EventList *pEventList = rEntity.maUsedEvents.front();
879 1814 : rEntity.maUsedEvents.pop();
880 :
881 1814 : aGuard.clear(); // unlock
882 :
883 1814 : delete pEventList;
884 :
885 1814 : aGuard.reset(); // lock
886 1568 : }
887 1568 : }
888 :
889 1150196 : void FastSaxParserImpl::produce( bool bForceFlush )
890 : {
891 1150196 : Entity& rEntity = getEntity();
892 2298824 : if (bForceFlush ||
893 1148628 : rEntity.mnProducedEventsSize == rEntity.mnEventListSize)
894 : {
895 1904 : osl::ResettableMutexGuard aGuard(rEntity.maEventProtector);
896 :
897 3813 : while (rEntity.maPendingEvents.size() >= rEntity.mnEventHighWater)
898 : { // pause parsing for a bit
899 5 : aGuard.clear(); // unlock
900 5 : rEntity.maProduceResume.wait();
901 5 : rEntity.maProduceResume.reset();
902 5 : aGuard.reset(); // lock
903 : }
904 :
905 1904 : rEntity.maPendingEvents.push(rEntity.mpProducedEvents);
906 1904 : rEntity.mpProducedEvents = 0;
907 :
908 1904 : aGuard.clear(); // unlock
909 :
910 1904 : rEntity.maConsumeResume.set();
911 : }
912 1150196 : }
913 :
914 129 : bool FastSaxParserImpl::hasNamespaceURL( const OUString& rPrefix ) const
915 : {
916 129 : if (maEntities.empty())
917 129 : return false;
918 :
919 0 : const Entity& rEntity = getEntity();
920 :
921 0 : if (rEntity.maNamespaceCount.empty())
922 0 : return false;
923 :
924 0 : OString aPrefix = OUStringToOString(rPrefix, RTL_TEXTENCODING_UTF8);
925 0 : sal_uInt32 nNamespace = rEntity.maNamespaceCount.top();
926 0 : while (nNamespace--)
927 : {
928 0 : if (rEntity.maNamespaceDefines[nNamespace]->maPrefix == aPrefix)
929 0 : return true;
930 : }
931 :
932 0 : return false;
933 : }
934 :
935 1904 : bool FastSaxParserImpl::consume(EventList *pEventList)
936 : {
937 1904 : Entity& rEntity = getEntity();
938 3451568 : for (EventList::iterator aEventIt = pEventList->begin();
939 2301047 : aEventIt != pEventList->end(); ++aEventIt)
940 : {
941 1150184 : switch ((*aEventIt).maType)
942 : {
943 : case START_ELEMENT:
944 555728 : rEntity.startElement( &(*aEventIt) );
945 555731 : break;
946 : case END_ELEMENT:
947 555730 : rEntity.endElement();
948 555731 : break;
949 : case CHARACTERS:
950 37165 : rEntity.characters( (*aEventIt).msChars );
951 37166 : break;
952 : case DONE:
953 3136 : return false;
954 : case EXCEPTION:
955 0 : rEntity.throwException( mxDocumentLocator, false );
956 0 : return false;
957 : default:
958 : assert(false);
959 0 : return false;
960 : }
961 : }
962 336 : return true;
963 : }
964 :
965 22211 : void FastSaxParserImpl::pushEntity( const Entity& rEntity )
966 : {
967 22211 : maEntities.push( rEntity );
968 22211 : mpTop = &maEntities.top();
969 22211 : }
970 :
971 22211 : void FastSaxParserImpl::popEntity()
972 : {
973 22211 : maEntities.pop();
974 22211 : mpTop = !maEntities.empty() ? &maEntities.top() : NULL;
975 22211 : }
976 :
977 : // starts parsing with actual parser !
978 22211 : void FastSaxParserImpl::parse()
979 : {
980 22211 : const int BUFFER_SIZE = 16 * 1024;
981 22211 : Sequence< sal_Int8 > seqOut( BUFFER_SIZE );
982 :
983 22211 : Entity& rEntity = getEntity();
984 :
985 : // set all necessary C-Callbacks
986 : static xmlSAXHandler callbacks;
987 22211 : callbacks.startElementNs = call_callbackStartElement;
988 22211 : callbacks.endElementNs = call_callbackEndElement;
989 22211 : callbacks.characters = call_callbackCharacters;
990 22211 : callbacks.initialized = XML_SAX2_MAGIC;
991 : #if 0
992 : XML_SetEntityDeclHandler(entity.mpParser, call_callbackEntityDecl);
993 : XML_SetExternalEntityRefHandler( entity.mpParser, call_callbackExternalEntityRef );
994 : #endif
995 22211 : int nRead = 0;
996 25385 : do
997 : {
998 47596 : nRead = rEntity.maConverter.readAndConvert( seqOut, BUFFER_SIZE );
999 47596 : if( nRead <= 0 )
1000 : {
1001 22211 : if( rEntity.mpParser != NULL )
1002 : {
1003 22211 : if( xmlParseChunk( rEntity.mpParser, reinterpret_cast<const char*>(seqOut.getConstArray()), 0, 1 ) != XML_ERR_OK )
1004 2 : rEntity.throwException( mxDocumentLocator, true );
1005 : }
1006 22209 : break;
1007 : }
1008 :
1009 25385 : bool bContinue = true;
1010 25385 : if( rEntity.mpParser == NULL )
1011 : {
1012 : // create parser with proper encoding (needs the first chunk of data)
1013 : rEntity.mpParser = xmlCreatePushParserCtxt( &callbacks, this,
1014 22211 : reinterpret_cast<const char*>(seqOut.getConstArray()), nRead, NULL );
1015 22211 : if( !rEntity.mpParser )
1016 0 : throw SAXException("Couldn't create parser", Reference< XInterface >(), Any() );
1017 :
1018 : // Tell libxml2 parser to decode entities in attribute values.
1019 22211 : xmlCtxtUseOptions(rEntity.mpParser, XML_PARSE_NOENT);
1020 : }
1021 : else
1022 : {
1023 3174 : bContinue = xmlParseChunk( rEntity.mpParser, reinterpret_cast<const char*>(seqOut.getConstArray()), nRead, 0 )
1024 3174 : == XML_ERR_OK;
1025 : }
1026 :
1027 : // callbacks used inside XML_Parse may have caught an exception
1028 25385 : if( !bContinue || rEntity.maSavedException.hasValue() )
1029 0 : rEntity.throwException( mxDocumentLocator, true );
1030 : } while( nRead > 0 );
1031 22209 : rEntity.getEvent( DONE );
1032 22209 : if( rEntity.mbEnableThreads )
1033 1570 : produce( true );
1034 22209 : }
1035 :
1036 : // The C-Callbacks
1037 2432018 : void FastSaxParserImpl::callbackStartElement(const xmlChar *localName , const xmlChar* prefix, const xmlChar* URI,
1038 : int numNamespaces, const xmlChar** namespaces, int numAttributes, int /*defaultedAttributes*/, const xmlChar **attributes)
1039 : {
1040 2432018 : if( !pendingCharacters.isEmpty())
1041 47245 : sendPendingCharacters();
1042 2432018 : Entity& rEntity = getEntity();
1043 2432018 : if( rEntity.maNamespaceCount.empty() )
1044 : {
1045 22211 : rEntity.maNamespaceCount.push(0);
1046 22211 : DefineNamespace( OString("xml"), OUString( "http://www.w3.org/XML/1998/namespace" ));
1047 : }
1048 : else
1049 : {
1050 2409807 : rEntity.maNamespaceCount.push( rEntity.maNamespaceCount.top() );
1051 : }
1052 :
1053 : // create attribute map and process namespace instructions
1054 2432018 : Event& rEvent = getEntity().getEvent( START_ELEMENT );
1055 2432018 : if (rEvent.mxAttributes.is())
1056 1872159 : rEvent.mxAttributes->clear();
1057 : else
1058 : rEvent.mxAttributes.set(
1059 : new FastAttributeList( rEntity.mxTokenHandler,
1060 559859 : rEntity.mpTokenHandler ) );
1061 :
1062 2432018 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
1063 2432018 : if (!rEntity.maNamespaceStack.empty())
1064 : {
1065 2409807 : rEvent.msNamespace = rEntity.maNamespaceStack.top().msName;
1066 2409807 : nNamespaceToken = rEntity.maNamespaceStack.top().mnToken;
1067 : }
1068 :
1069 : try
1070 : {
1071 : /* #158414# Each element may define new namespaces, also for attribues.
1072 : First, process all namespaces, second, process the attributes after namespaces
1073 : have been initialized. */
1074 :
1075 : // #158414# first: get namespaces
1076 2525410 : for (int i = 0; i < numNamespaces * 2; i += 2)
1077 : {
1078 : // namespaces[] is (prefix/URI)
1079 93392 : if( namespaces[ i ] != NULL )
1080 : {
1081 84182 : DefineNamespace( OString( XML_CAST( namespaces[ i ] )),
1082 168364 : OUString( XML_CAST( namespaces[ i + 1 ] ), strlen( XML_CAST( namespaces[ i + 1 ] )), RTL_TEXTENCODING_UTF8 ));
1083 : }
1084 : else
1085 : {
1086 : // default namespace
1087 9210 : rEvent.msNamespace = OUString( XML_CAST( namespaces[ i + 1 ] ), strlen( XML_CAST( namespaces[ i + 1 ] )), RTL_TEXTENCODING_UTF8 );
1088 9210 : nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
1089 : }
1090 : }
1091 :
1092 : // #158414# second: fill attribute list with other attributes
1093 5699732 : for (int i = 0; i < numAttributes * 5; i += 5)
1094 : {
1095 3267714 : if( attributes[ i + 1 ] != NULL )
1096 : {
1097 2464512 : sal_Int32 nAttributeToken = GetTokenWithPrefix( attributes[ i + 1 ], strlen( XML_CAST( attributes[ i + 1 ] )), attributes[ i ], strlen( XML_CAST( attributes[ i ] )));
1098 2464512 : if( nAttributeToken != FastToken::DONTKNOW )
1099 2445800 : rEvent.mxAttributes->add( nAttributeToken, XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] );
1100 : else
1101 37424 : rEvent.mxAttributes->addUnknown( OUString( XML_CAST( attributes[ i + 2 ] ), strlen( XML_CAST( attributes[ i + 2 ] )), RTL_TEXTENCODING_UTF8 ),
1102 56136 : OString( XML_CAST( attributes[ i ] )), OString( XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] ));
1103 : }
1104 : else
1105 : {
1106 803202 : sal_Int32 nAttributeToken = GetToken( attributes[ i ], strlen( XML_CAST( attributes[ i ] )));
1107 803201 : if( nAttributeToken != FastToken::DONTKNOW )
1108 801359 : rEvent.mxAttributes->add( nAttributeToken, XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] );
1109 : else
1110 1842 : rEvent.mxAttributes->addUnknown( XML_CAST( attributes[ i ] ),
1111 3684 : OString( XML_CAST( attributes[ i + 3 ] ), attributes[ i + 4 ] - attributes[ i + 3 ] ));
1112 : }
1113 : }
1114 :
1115 2432018 : if( prefix != NULL )
1116 2322654 : rEvent.mnElementToken = GetTokenWithPrefix( prefix, strlen( XML_CAST( prefix )), localName, strlen( XML_CAST( localName )));
1117 109364 : else if( !rEvent.msNamespace.isEmpty() )
1118 109353 : rEvent.mnElementToken = GetTokenWithContextNamespace( nNamespaceToken, localName, strlen( XML_CAST( localName )));
1119 : else
1120 11 : rEvent.mnElementToken = GetToken( localName, strlen( XML_CAST( localName )));
1121 :
1122 2432017 : if( rEvent.mnElementToken == FastToken::DONTKNOW )
1123 : {
1124 7443 : if( prefix != NULL )
1125 : {
1126 5633 : rEvent.msNamespace = OUString( XML_CAST( URI ), strlen( XML_CAST( URI )), RTL_TEXTENCODING_UTF8 );
1127 5633 : nNamespaceToken = GetNamespaceToken( rEvent.msNamespace );
1128 : }
1129 7443 : rEvent.msElementName = OUString( XML_CAST( localName ), strlen( XML_CAST( localName )), RTL_TEXTENCODING_UTF8 );
1130 : }
1131 : else // token is always preferred.
1132 2424574 : rEvent.msElementName.clear();
1133 :
1134 2432017 : rEntity.maNamespaceStack.push( NameWithToken(rEvent.msNamespace, nNamespaceToken) );
1135 2432018 : if (rEntity.mbEnableThreads)
1136 555731 : produce();
1137 : else
1138 1876287 : rEntity.startElement( &rEvent );
1139 : }
1140 0 : catch (const Exception&)
1141 : {
1142 0 : rEntity.saveException( ::cppu::getCaughtException() );
1143 : }
1144 2432018 : }
1145 :
1146 2432011 : void FastSaxParserImpl::callbackEndElement( const xmlChar*, const xmlChar*, const xmlChar* )
1147 : {
1148 2432011 : if( !pendingCharacters.isEmpty())
1149 126192 : sendPendingCharacters();
1150 2432011 : Entity& rEntity = getEntity();
1151 : SAL_WARN_IF(rEntity.maNamespaceCount.empty(), "sax", "Empty NamespaceCount");
1152 2432011 : if( !rEntity.maNamespaceCount.empty() )
1153 2432011 : rEntity.maNamespaceCount.pop();
1154 :
1155 : SAL_WARN_IF(rEntity.maNamespaceStack.empty(), "sax", "Empty NamespaceStack");
1156 2432011 : if( !rEntity.maNamespaceStack.empty() )
1157 2432011 : rEntity.maNamespaceStack.pop();
1158 :
1159 2432011 : rEntity.getEvent( END_ELEMENT );
1160 2432011 : if (rEntity.mbEnableThreads)
1161 555731 : produce();
1162 : else
1163 1876280 : rEntity.endElement();
1164 2432011 : }
1165 :
1166 179028 : void FastSaxParserImpl::callbackCharacters( const xmlChar* s, int nLen )
1167 : {
1168 : // SAX interface allows that the characters callback splits content of one XML node
1169 : // (e.g. because there's an entity that needs decoding), however for consumers it's
1170 : // simpler FastSaxParser's character callback provides the whole string at once,
1171 : // so merge data from possible multiple calls and send them at once (before the element
1172 : // ends or another one starts).
1173 179028 : pendingCharacters += OUString( XML_CAST( s ), nLen, RTL_TEXTENCODING_UTF8 );
1174 179028 : }
1175 :
1176 173437 : void FastSaxParserImpl::sendPendingCharacters()
1177 : {
1178 173437 : Entity& rEntity = getEntity();
1179 173437 : Event& rEvent = rEntity.getEvent( CHARACTERS );
1180 173437 : rEvent.msChars = pendingCharacters;
1181 173437 : pendingCharacters.clear();
1182 173437 : if (rEntity.mbEnableThreads)
1183 37166 : produce();
1184 : else
1185 136271 : rEntity.characters( rEvent.msChars );
1186 173437 : }
1187 :
1188 : #if 0
1189 : void FastSaxParserImpl::callbackEntityDecl(
1190 : SAL_UNUSED_PARAMETER const xmlChar * /*entityName*/,
1191 : SAL_UNUSED_PARAMETER int /*is_parameter_entity*/,
1192 : const xmlChar *value, SAL_UNUSED_PARAMETER int /*value_length*/,
1193 : SAL_UNUSED_PARAMETER const xmlChar * /*base*/,
1194 : SAL_UNUSED_PARAMETER const xmlChar * /*systemId*/,
1195 : SAL_UNUSED_PARAMETER const xmlChar * /*publicId*/,
1196 : SAL_UNUSED_PARAMETER const xmlChar * /*notationName*/)
1197 : {
1198 : if (value) { // value != 0 means internal entity
1199 : SAL_INFO("sax", "FastSaxParser: internal entity declaration, stopping");
1200 : XML_StopParser(getEntity().mpParser, XML_FALSE);
1201 : getEntity().saveException( SAXParseException(
1202 : "FastSaxParser: internal entity declaration, stopping",
1203 : static_cast<OWeakObject*>(mpFront), Any(),
1204 : mxDocumentLocator->getPublicId(),
1205 : mxDocumentLocator->getSystemId(),
1206 : mxDocumentLocator->getLineNumber(),
1207 : mxDocumentLocator->getColumnNumber() ) );
1208 : } else {
1209 : SAL_INFO("sax", "FastSaxParser: ignoring external entity declaration");
1210 : }
1211 : }
1212 :
1213 : bool FastSaxParserImpl::callbackExternalEntityRef(
1214 : XML_Parser parser, const xmlChar *context,
1215 : SAL_UNUSED_PARAMETER const xmlChar * /*base*/, const xmlChar *systemId,
1216 : const xmlChar *publicId )
1217 : {
1218 : bool bOK = true;
1219 : InputSource source;
1220 :
1221 : Entity& rCurrEntity = getEntity();
1222 : Entity aNewEntity( rCurrEntity );
1223 :
1224 : if( rCurrEntity.mxEntityResolver.is() ) try
1225 : {
1226 : aNewEntity.maStructSource = rCurrEntity.mxEntityResolver->resolveEntity(
1227 : OUString( publicId, strlen( publicId ), RTL_TEXTENCODING_UTF8 ) ,
1228 : OUString( systemId, strlen( systemId ), RTL_TEXTENCODING_UTF8 ) );
1229 : }
1230 : catch (const SAXParseException & e)
1231 : {
1232 : rCurrEntity.saveException( e );
1233 : bOK = false;
1234 : }
1235 : catch (const SAXException& e)
1236 : {
1237 : rCurrEntity.saveException( SAXParseException(
1238 : e.Message, e.Context, e.WrappedException,
1239 : mxDocumentLocator->getPublicId(),
1240 : mxDocumentLocator->getSystemId(),
1241 : mxDocumentLocator->getLineNumber(),
1242 : mxDocumentLocator->getColumnNumber() ) );
1243 : bOK = false;
1244 : }
1245 :
1246 : if( aNewEntity.maStructSource.aInputStream.is() )
1247 : {
1248 : aNewEntity.mpParser = XML_ExternalEntityParserCreate( parser, context, 0 );
1249 : if( !aNewEntity.mpParser )
1250 : {
1251 : return false;
1252 : }
1253 :
1254 : aNewEntity.maConverter.setInputStream( aNewEntity.maStructSource.aInputStream );
1255 : pushEntity( aNewEntity );
1256 : try
1257 : {
1258 : parse();
1259 : }
1260 : catch (const SAXParseException& e)
1261 : {
1262 : rCurrEntity.saveException( e );
1263 : bOK = false;
1264 : }
1265 : catch (const IOException& e)
1266 : {
1267 : SAXException aEx;
1268 : aEx.WrappedException <<= e;
1269 : rCurrEntity.saveException( aEx );
1270 : bOK = false;
1271 : }
1272 : catch (const RuntimeException& e)
1273 : {
1274 : SAXException aEx;
1275 : aEx.WrappedException <<= e;
1276 : rCurrEntity.saveException( aEx );
1277 : bOK = false;
1278 : }
1279 :
1280 : popEntity();
1281 : XML_ParserFree( aNewEntity.mpParser );
1282 : }
1283 :
1284 : return bOK;
1285 : }
1286 : #endif
1287 :
1288 30005 : FastSaxParser::FastSaxParser() : mpImpl(new FastSaxParserImpl(this)) {}
1289 :
1290 90014 : FastSaxParser::~FastSaxParser()
1291 : {
1292 30005 : delete mpImpl;
1293 60009 : }
1294 :
1295 22427 : void FastSaxParser::parseStream( const xml::sax::InputSource& aInputSource )
1296 : throw (xml::sax::SAXException, io::IOException,
1297 : uno::RuntimeException, std::exception)
1298 : {
1299 22427 : mpImpl->parseStream(aInputSource);
1300 22209 : }
1301 :
1302 28567 : void FastSaxParser::setFastDocumentHandler( const uno::Reference<xml::sax::XFastDocumentHandler>& Handler )
1303 : throw (uno::RuntimeException, std::exception)
1304 : {
1305 28567 : mpImpl->setFastDocumentHandler(Handler);
1306 28567 : }
1307 :
1308 30003 : void FastSaxParser::setTokenHandler( const uno::Reference<xml::sax::XFastTokenHandler>& Handler )
1309 : throw (uno::RuntimeException, std::exception)
1310 : {
1311 30003 : mpImpl->setTokenHandler(Handler);
1312 30003 : }
1313 :
1314 1368704 : void FastSaxParser::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken )
1315 : throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
1316 : {
1317 1368704 : mpImpl->registerNamespace(NamespaceURL, NamespaceToken);
1318 1368704 : }
1319 :
1320 0 : OUString FastSaxParser::getNamespaceURL( const OUString& rPrefix )
1321 : throw(lang::IllegalArgumentException, uno::RuntimeException, std::exception)
1322 : {
1323 0 : return mpImpl->getNamespaceURL(rPrefix);
1324 : }
1325 :
1326 0 : void FastSaxParser::setErrorHandler( const uno::Reference< xml::sax::XErrorHandler >& Handler )
1327 : throw (uno::RuntimeException, std::exception)
1328 : {
1329 0 : mpImpl->setErrorHandler(Handler);
1330 0 : }
1331 :
1332 0 : void FastSaxParser::setEntityResolver( const uno::Reference< xml::sax::XEntityResolver >& Resolver )
1333 : throw (uno::RuntimeException, std::exception)
1334 : {
1335 0 : mpImpl->setEntityResolver(Resolver);
1336 0 : }
1337 :
1338 0 : void FastSaxParser::setLocale( const lang::Locale& rLocale )
1339 : throw (uno::RuntimeException, std::exception)
1340 : {
1341 0 : mpImpl->setLocale(rLocale);
1342 0 : }
1343 :
1344 1 : OUString FastSaxParser::getImplementationName()
1345 : throw (uno::RuntimeException, std::exception)
1346 : {
1347 1 : return OUString("com.sun.star.comp.extensions.xml.sax.FastParser");
1348 : }
1349 :
1350 0 : sal_Bool FastSaxParser::supportsService( const OUString& ServiceName )
1351 : throw (uno::RuntimeException, std::exception)
1352 : {
1353 0 : return cppu::supportsService(this, ServiceName);
1354 : }
1355 :
1356 1 : uno::Sequence<OUString> FastSaxParser::getSupportedServiceNames()
1357 : throw (uno::RuntimeException, std::exception)
1358 : {
1359 1 : Sequence<OUString> seq(1);
1360 1 : seq[0] = "com.sun.star.xml.sax.FastParser";
1361 1 : return seq;
1362 : }
1363 :
1364 129 : bool FastSaxParser::hasNamespaceURL( const OUString& rPrefix ) const
1365 : {
1366 129 : return mpImpl->hasNamespaceURL(rPrefix);
1367 : }
1368 :
1369 : } // namespace sax_fastparser
1370 :
1371 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
1372 30004 : com_sun_star_comp_extensions_xml_sax_FastParser_get_implementation(
1373 : css::uno::XComponentContext *,
1374 : css::uno::Sequence<css::uno::Any> const &)
1375 : {
1376 30004 : return cppu::acquire(new FastSaxParser);
1377 : }
1378 :
1379 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|