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