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 <boost/scoped_ptr.hpp>
21 :
22 : #include <osl/diagnose.h>
23 : #include <rtl/ustrbuf.hxx>
24 :
25 : #include <com/sun/star/lang/DisposedException.hpp>
26 : #include <com/sun/star/xml/sax/XFastContextHandler.hpp>
27 : #include <com/sun/star/xml/sax/SAXParseException.hpp>
28 : #include <com/sun/star/xml/sax/FastToken.hpp>
29 :
30 : #include "fastparser.hxx"
31 :
32 : #include <string.h>
33 :
34 : using namespace ::std;
35 : using namespace ::osl;
36 : using namespace ::cppu;
37 : using namespace ::com::sun::star::uno;
38 : using namespace ::com::sun::star::lang;
39 : using namespace ::com::sun::star::xml::sax;
40 : using namespace ::com::sun::star::io;
41 :
42 : namespace sax_fastparser {
43 :
44 : // --------------------------------------------------------------------
45 :
46 112475 : struct SaxContextImpl
47 : {
48 : Reference< XFastContextHandler > mxContext;
49 : sal_uInt32 mnNamespaceCount;
50 : sal_Int32 mnElementToken;
51 : OUString maNamespace;
52 : OUString maElementName;
53 :
54 1811 : SaxContextImpl() { mnNamespaceCount = 0; mnElementToken = 0; }
55 110664 : SaxContextImpl( const SaxContextImplPtr& p ) { mnNamespaceCount = p->mnNamespaceCount; mnElementToken = p->mnElementToken; maNamespace = p->maNamespace; }
56 : };
57 :
58 : // --------------------------------------------------------------------
59 :
60 7685 : struct NamespaceDefine
61 : {
62 : OString maPrefix;
63 : sal_Int32 mnToken;
64 : OUString maNamespaceURL;
65 :
66 7685 : NamespaceDefine( const OString& rPrefix, sal_Int32 nToken, const OUString& rNamespaceURL ) : maPrefix( rPrefix ), mnToken( nToken ), maNamespaceURL( rNamespaceURL ) {}
67 : };
68 :
69 : // --------------------------------------------------------------------
70 : // FastLocatorImpl
71 : // --------------------------------------------------------------------
72 :
73 : class FastSaxParser;
74 :
75 4034 : class FastLocatorImpl : public WeakImplHelper1< XLocator >
76 : {
77 : public:
78 2017 : FastLocatorImpl( FastSaxParser *p ) : mpParser(p) {}
79 :
80 2017 : void dispose() { mpParser = 0; }
81 6 : void checkDispose() throw (RuntimeException) { if( !mpParser ) throw DisposedException(); }
82 :
83 : //XLocator
84 : virtual sal_Int32 SAL_CALL getColumnNumber(void) throw (RuntimeException);
85 : virtual sal_Int32 SAL_CALL getLineNumber(void) throw (RuntimeException);
86 : virtual OUString SAL_CALL getPublicId(void) throw (RuntimeException);
87 : virtual OUString SAL_CALL getSystemId(void) throw (RuntimeException);
88 :
89 : private:
90 : FastSaxParser *mpParser;
91 : };
92 :
93 : // --------------------------------------------------------------------
94 : // FastSaxParser
95 : // --------------------------------------------------------------------
96 :
97 : //---------------------------------------------
98 : // the implementation part
99 : //---------------------------------------------
100 :
101 : extern "C" {
102 :
103 112475 : static void call_callbackStartElement(void *userData, const XML_Char *name , const XML_Char **atts)
104 : {
105 112475 : FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData );
106 112475 : pFastParser->callbackStartElement( name, atts );
107 112475 : }
108 :
109 112469 : static void call_callbackEndElement(void *userData, const XML_Char *name)
110 : {
111 112469 : FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData );
112 112469 : pFastParser->callbackEndElement( name );
113 112469 : }
114 :
115 21067 : static void call_callbackCharacters( void *userData , const XML_Char *s , int nLen )
116 : {
117 21067 : FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( userData );
118 21067 : pFastParser->callbackCharacters( s, nLen );
119 21067 : }
120 :
121 0 : static void call_callbackEntityDecl(void *userData, const XML_Char *entityName,
122 : int is_parameter_entity, const XML_Char *value, int value_length,
123 : const XML_Char *base, const XML_Char *systemId,
124 : const XML_Char *publicId, const XML_Char *notationName)
125 : {
126 0 : FastSaxParser* pFastParser = reinterpret_cast<FastSaxParser*>(userData);
127 : pFastParser->callbackEntityDecl(entityName, is_parameter_entity, value,
128 0 : value_length, base, systemId, publicId, notationName);
129 0 : }
130 :
131 0 : static int call_callbackExternalEntityRef( XML_Parser parser,
132 : const XML_Char *openEntityNames, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId )
133 : {
134 0 : FastSaxParser* pFastParser = reinterpret_cast< FastSaxParser* >( XML_GetUserData( parser ) );
135 0 : return pFastParser->callbackExternalEntityRef( parser, openEntityNames, base, systemId, publicId );
136 : }
137 :
138 : } // extern "C"
139 :
140 : // --------------------------------------------------------------------
141 : // FastLocatorImpl implementation
142 : // --------------------------------------------------------------------
143 :
144 1 : sal_Int32 SAL_CALL FastLocatorImpl::getColumnNumber(void) throw (RuntimeException)
145 : {
146 1 : checkDispose();
147 1 : return XML_GetCurrentColumnNumber( mpParser->getEntity().mpParser );
148 : }
149 :
150 : // --------------------------------------------------------------------
151 :
152 2 : sal_Int32 SAL_CALL FastLocatorImpl::getLineNumber(void) throw (RuntimeException)
153 : {
154 2 : checkDispose();
155 2 : return XML_GetCurrentLineNumber( mpParser->getEntity().mpParser );
156 : }
157 :
158 : // --------------------------------------------------------------------
159 :
160 1 : OUString SAL_CALL FastLocatorImpl::getPublicId(void) throw (RuntimeException)
161 : {
162 1 : checkDispose();
163 1 : return mpParser->getEntity().maStructSource.sPublicId;
164 : }
165 : // --------------------------------------------------------------------
166 :
167 2 : OUString SAL_CALL FastLocatorImpl::getSystemId(void) throw (RuntimeException)
168 : {
169 2 : checkDispose();
170 2 : return mpParser->getEntity().maStructSource.sSystemId;
171 : }
172 :
173 : // --------------------------------------------------------------------
174 :
175 2017 : ParserData::ParserData()
176 : {
177 2017 : }
178 :
179 5711 : ParserData::~ParserData()
180 : {
181 5711 : }
182 :
183 : // --------------------------------------------------------------------
184 :
185 1883 : Entity::Entity( const ParserData& rData ) :
186 1883 : ParserData( rData )
187 : {
188 : // performance-improvement. Reference is needed when calling the startTag callback.
189 : // Handing out the same object with every call is allowed (see sax-specification)
190 1883 : mxAttributes.set( new FastAttributeList( mxTokenHandler ) );
191 1883 : }
192 :
193 3694 : Entity::~Entity()
194 : {
195 3694 : }
196 :
197 : // --------------------------------------------------------------------
198 : // FastSaxParser implementation
199 : // --------------------------------------------------------------------
200 :
201 2017 : FastSaxParser::FastSaxParser()
202 : {
203 2017 : mxDocumentLocator.set( new FastLocatorImpl( this ) );
204 2017 : }
205 :
206 : // --------------------------------------------------------------------
207 :
208 6051 : FastSaxParser::~FastSaxParser()
209 : {
210 2017 : if( mxDocumentLocator.is() )
211 2017 : mxDocumentLocator->dispose();
212 4034 : }
213 :
214 : // --------------------------------------------------------------------
215 :
216 112475 : void FastSaxParser::pushContext()
217 : {
218 112475 : Entity& rEntity = getEntity();
219 112475 : if( rEntity.maContextStack.empty() )
220 : {
221 1811 : rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl ) );
222 1811 : DefineNamespace( OString("xml"), "http://www.w3.org/XML/1998/namespace");
223 : }
224 : else
225 : {
226 110664 : rEntity.maContextStack.push( SaxContextImplPtr( new SaxContextImpl( rEntity.maContextStack.top() ) ) );
227 : }
228 112475 : }
229 :
230 : // --------------------------------------------------------------------
231 :
232 112469 : void FastSaxParser::popContext()
233 : {
234 112469 : Entity& rEntity = getEntity();
235 : assert(!rEntity.maContextStack.empty()); // pop without push?
236 112469 : if( !rEntity.maContextStack.empty() )
237 112469 : rEntity.maContextStack.pop();
238 112469 : }
239 :
240 : // --------------------------------------------------------------------
241 :
242 7685 : void FastSaxParser::DefineNamespace( const OString& rPrefix, const sal_Char* pNamespaceURL )
243 : {
244 7685 : Entity& rEntity = getEntity();
245 : assert(!rEntity.maContextStack.empty()); // need a context!
246 7685 : if( !rEntity.maContextStack.empty() )
247 : {
248 7685 : sal_uInt32 nOffset = rEntity.maContextStack.top()->mnNamespaceCount++;
249 :
250 7685 : if( rEntity.maNamespaceDefines.size() <= nOffset )
251 1811 : rEntity.maNamespaceDefines.resize( rEntity.maNamespaceDefines.size() + 64 );
252 :
253 7685 : const OUString aNamespaceURL( pNamespaceURL, strlen( pNamespaceURL ), RTL_TEXTENCODING_UTF8 );
254 7685 : rEntity.maNamespaceDefines[nOffset].reset( new NamespaceDefine( rPrefix, GetNamespaceToken( aNamespaceURL ), aNamespaceURL ) );
255 : }
256 7685 : }
257 :
258 : // --------------------------------------------------------------------
259 :
260 44715 : sal_Int32 FastSaxParser::GetToken( const OString& rToken )
261 : {
262 44715 : Sequence< sal_Int8 > aSeq( (sal_Int8*)rToken.getStr(), rToken.getLength() );
263 :
264 44715 : return getEntity().mxTokenHandler->getTokenFromUTF8( aSeq );
265 : }
266 :
267 152101 : sal_Int32 FastSaxParser::GetToken( const sal_Char* pToken, sal_Int32 nLen /* = 0 */ )
268 : {
269 152101 : if( !nLen )
270 4 : nLen = strlen( pToken );
271 :
272 152101 : Sequence< sal_Int8 > aSeq( (sal_Int8*)pToken, nLen );
273 :
274 152101 : return getEntity().mxTokenHandler->getTokenFromUTF8( aSeq );
275 : }
276 :
277 : // --------------------------------------------------------------------
278 :
279 62452 : sal_Int32 FastSaxParser::GetTokenWithPrefix( const OString& rPrefix, const OString& rName ) throw (SAXException)
280 : {
281 62452 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
282 :
283 62452 : Entity& rEntity = getEntity();
284 62452 : sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount;
285 209858 : while( nNamespace-- )
286 : {
287 147406 : if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix )
288 : {
289 62452 : nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken;
290 62452 : break;
291 : }
292 :
293 84954 : if( !nNamespace )
294 0 : throw SAXException(); // prefix that has no defined namespace url
295 : }
296 :
297 62452 : if( nNamespaceToken != FastToken::DONTKNOW )
298 : {
299 61949 : sal_Int32 nNameToken = GetToken( rName.getStr(), rName.getLength() );
300 61949 : if( nNameToken != FastToken::DONTKNOW )
301 61949 : return nNamespaceToken | nNameToken;
302 : }
303 :
304 503 : return FastToken::DONTKNOW;
305 : }
306 :
307 80300 : sal_Int32 FastSaxParser::GetTokenWithPrefix( const sal_Char*pPrefix, int nPrefixLen, const sal_Char* pName, int nNameLen ) throw (SAXException)
308 : {
309 80300 : sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
310 :
311 80300 : Entity& rEntity = getEntity();
312 80300 : sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount;
313 256118 : while( nNamespace-- )
314 : {
315 175818 : const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix );
316 277433 : if( (rPrefix.getLength() == nPrefixLen) &&
317 101615 : (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) )
318 : {
319 80300 : nNamespaceToken = rEntity.maNamespaceDefines[nNamespace]->mnToken;
320 80300 : break;
321 : }
322 :
323 95518 : if( !nNamespace )
324 0 : throw SAXException(); // prefix that has no defined namespace url
325 : }
326 :
327 80300 : if( nNamespaceToken != FastToken::DONTKNOW )
328 : {
329 80266 : sal_Int32 nNameToken = GetToken( pName, nNameLen );
330 80266 : if( nNameToken != FastToken::DONTKNOW )
331 80266 : return nNamespaceToken | nNameToken;
332 : }
333 :
334 34 : return FastToken::DONTKNOW;
335 : }
336 :
337 : // --------------------------------------------------------------------
338 :
339 45596 : sal_Int32 FastSaxParser::GetNamespaceToken( const OUString& rNamespaceURL )
340 : {
341 45596 : NamespaceMap::iterator aIter( maNamespaceMap.find( rNamespaceURL ) );
342 45596 : if( aIter != maNamespaceMap.end() )
343 15528 : return (*aIter).second;
344 : else
345 30068 : return FastToken::DONTKNOW;
346 : }
347 :
348 : // --------------------------------------------------------------------
349 :
350 509 : OUString FastSaxParser::GetNamespaceURL( const OString& rPrefix ) throw (SAXException)
351 : {
352 509 : Entity& rEntity = getEntity();
353 509 : if( !rEntity.maContextStack.empty() )
354 : {
355 509 : sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount;
356 1305 : while( nNamespace-- )
357 796 : if( rEntity.maNamespaceDefines[nNamespace]->maPrefix == rPrefix )
358 1018 : return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL;
359 : }
360 :
361 0 : throw SAXException(); // prefix that has no defined namespace url
362 : }
363 :
364 34 : OUString FastSaxParser::GetNamespaceURL( const sal_Char*pPrefix, int nPrefixLen ) throw(SAXException)
365 : {
366 34 : Entity& rEntity = getEntity();
367 34 : if( pPrefix && !rEntity.maContextStack.empty() )
368 : {
369 34 : sal_uInt32 nNamespace = rEntity.maContextStack.top()->mnNamespaceCount;
370 86 : while( nNamespace-- )
371 : {
372 52 : const OString& rPrefix( rEntity.maNamespaceDefines[nNamespace]->maPrefix );
373 87 : if( (rPrefix.getLength() == nPrefixLen) &&
374 35 : (strncmp( rPrefix.getStr(), pPrefix, nPrefixLen ) == 0 ) )
375 : {
376 68 : return rEntity.maNamespaceDefines[nNamespace]->maNamespaceURL;
377 : }
378 : }
379 : }
380 :
381 0 : throw SAXException(); // prefix that has no defined namespace url
382 : }
383 :
384 : // --------------------------------------------------------------------
385 :
386 9882 : sal_Int32 FastSaxParser::GetTokenWithNamespaceURL( const OUString& rNamespaceURL, const sal_Char* pName, int nNameLen )
387 : {
388 9882 : sal_Int32 nNamespaceToken = GetNamespaceToken( rNamespaceURL );
389 :
390 9882 : if( nNamespaceToken != FastToken::DONTKNOW )
391 : {
392 9882 : sal_Int32 nNameToken = GetToken( pName, nNameLen );
393 9882 : if( nNameToken != FastToken::DONTKNOW )
394 9882 : return nNamespaceToken | nNameToken;
395 : }
396 :
397 0 : return FastToken::DONTKNOW;
398 : }
399 :
400 : // --------------------------------------------------------------------
401 :
402 203972 : void FastSaxParser::splitName( const XML_Char *pwName, const XML_Char *&rpPrefix, sal_Int32 &rPrefixLen, const XML_Char *&rpName, sal_Int32 &rNameLen )
403 : {
404 : XML_Char *p;
405 1603562 : for( p = const_cast< XML_Char* >( pwName ), rNameLen = 0, rPrefixLen = 0; *p; p++ )
406 : {
407 1399590 : if( *p == ':' )
408 : {
409 148626 : rPrefixLen = p - pwName;
410 148626 : rNameLen = 0;
411 : }
412 : else
413 : {
414 1250964 : rNameLen++;
415 : }
416 : }
417 203972 : if( rPrefixLen )
418 : {
419 148626 : rpPrefix = pwName;
420 148626 : rpName = &pwName[ rPrefixLen + 1 ];
421 : }
422 : else
423 : {
424 55346 : rpPrefix = 0;
425 55346 : rpName = pwName;
426 : }
427 203972 : }
428 :
429 : /***************
430 : *
431 : * parseStream does Parser-startup initializations. The FastSaxParser::parse() method does
432 : * the file-specific initialization work. (During a parser run, external files may be opened)
433 : *
434 : ****************/
435 1883 : void FastSaxParser::parseStream( const InputSource& maStructSource) throw (SAXException, IOException, RuntimeException)
436 : {
437 : // Only one text at one time
438 1883 : MutexGuard guard( maMutex );
439 :
440 3766 : Entity entity( maData );
441 1883 : entity.maStructSource = maStructSource;
442 :
443 1883 : if( !entity.maStructSource.aInputStream.is() )
444 72 : throw SAXException("No input source", Reference< XInterface >(), Any() );
445 :
446 1811 : entity.maConverter.setInputStream( entity.maStructSource.aInputStream );
447 1811 : if( !entity.maStructSource.sEncoding.isEmpty() )
448 0 : entity.maConverter.setEncoding( OUStringToOString( entity.maStructSource.sEncoding, RTL_TEXTENCODING_ASCII_US ) );
449 :
450 : // create parser with proper encoding
451 1811 : entity.mpParser = XML_ParserCreate( 0 );
452 1811 : if( !entity.mpParser )
453 0 : throw SAXException("Couldn't create parser", Reference< XInterface >(), Any() );
454 :
455 : // set all necessary C-Callbacks
456 1811 : XML_SetUserData( entity.mpParser, this );
457 1811 : XML_SetElementHandler( entity.mpParser, call_callbackStartElement, call_callbackEndElement );
458 1811 : XML_SetCharacterDataHandler( entity.mpParser, call_callbackCharacters );
459 1811 : XML_SetEntityDeclHandler(entity.mpParser, call_callbackEntityDecl);
460 1811 : XML_SetExternalEntityRefHandler( entity.mpParser, call_callbackExternalEntityRef );
461 :
462 1811 : pushEntity( entity );
463 : try
464 : {
465 : // start the document
466 1811 : if( entity.mxDocumentHandler.is() )
467 : {
468 1811 : Reference< XLocator > xLoc( mxDocumentLocator.get() );
469 1811 : entity.mxDocumentHandler->setDocumentLocator( xLoc );
470 1811 : entity.mxDocumentHandler->startDocument();
471 : }
472 :
473 1811 : parse();
474 :
475 : // finish document
476 1810 : if( entity.mxDocumentHandler.is() )
477 : {
478 1810 : entity.mxDocumentHandler->endDocument();
479 : }
480 : }
481 2 : catch (const SAXException&)
482 : {
483 1 : popEntity();
484 1 : XML_ParserFree( entity.mpParser );
485 1 : throw;
486 : }
487 0 : catch (const IOException&)
488 : {
489 0 : popEntity();
490 0 : XML_ParserFree( entity.mpParser );
491 0 : throw;
492 : }
493 0 : catch (const RuntimeException&)
494 : {
495 0 : popEntity();
496 0 : XML_ParserFree( entity.mpParser );
497 0 : throw;
498 : }
499 :
500 1810 : popEntity();
501 3693 : XML_ParserFree( entity.mpParser );
502 1810 : }
503 :
504 2168 : void FastSaxParser::setFastDocumentHandler( const Reference< XFastDocumentHandler >& Handler ) throw (RuntimeException)
505 : {
506 2168 : maData.mxDocumentHandler = Handler;
507 2168 : }
508 :
509 2017 : void SAL_CALL FastSaxParser::setTokenHandler( const Reference< XFastTokenHandler >& Handler ) throw (RuntimeException)
510 : {
511 2017 : maData.mxTokenHandler = Handler;
512 2017 : }
513 :
514 28029 : void SAL_CALL FastSaxParser::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) throw (IllegalArgumentException, RuntimeException)
515 : {
516 28029 : if( NamespaceToken >= FastToken::NAMESPACE )
517 : {
518 28029 : if( GetNamespaceToken( NamespaceURL ) == FastToken::DONTKNOW )
519 : {
520 28029 : maNamespaceMap[ NamespaceURL ] = NamespaceToken;
521 56058 : return;
522 : }
523 : }
524 0 : throw IllegalArgumentException();
525 : }
526 :
527 6 : OUString SAL_CALL FastSaxParser::getNamespaceURL( const OUString& rPrefix ) throw(IllegalArgumentException, RuntimeException)
528 : {
529 : try
530 : {
531 12 : return GetNamespaceURL( OUStringToOString( rPrefix, RTL_TEXTENCODING_UTF8 ) );
532 : }
533 0 : catch (const Exception&)
534 : {
535 : }
536 0 : throw IllegalArgumentException();
537 : }
538 :
539 0 : void FastSaxParser::setErrorHandler(const Reference< XErrorHandler > & Handler) throw (RuntimeException)
540 : {
541 0 : maData.mxErrorHandler = Handler;
542 0 : }
543 :
544 0 : void FastSaxParser::setEntityResolver(const Reference < XEntityResolver > & Resolver) throw (RuntimeException)
545 : {
546 0 : maData.mxEntityResolver = Resolver;
547 0 : }
548 :
549 0 : void FastSaxParser::setLocale( const Locale & Locale ) throw (RuntimeException)
550 : {
551 0 : maData.maLocale = Locale;
552 0 : }
553 :
554 13 : Sequence< OUString > FastSaxParser::getSupportedServiceNames_Static(void)
555 : {
556 13 : Sequence<OUString> aRet(1);
557 13 : aRet.getArray()[0] = OUString( PARSER_SERVICE_NAME );
558 13 : return aRet;
559 : }
560 :
561 : // XServiceInfo
562 0 : OUString FastSaxParser::getImplementationName() throw (RuntimeException)
563 : {
564 0 : return OUString( PARSER_IMPLEMENTATION_NAME );
565 : }
566 :
567 : // XServiceInfo
568 0 : sal_Bool FastSaxParser::supportsService(const OUString& ServiceName) throw (RuntimeException)
569 : {
570 0 : Sequence< OUString > aSNL = getSupportedServiceNames();
571 0 : const OUString * pArray = aSNL.getConstArray();
572 :
573 0 : for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
574 0 : if( pArray[i] == ServiceName )
575 0 : return sal_True;
576 :
577 0 : return sal_False;
578 : }
579 :
580 : // XServiceInfo
581 0 : Sequence< OUString > FastSaxParser::getSupportedServiceNames(void) throw (RuntimeException)
582 : {
583 :
584 0 : Sequence<OUString> seq(1);
585 0 : seq.getArray()[0] = OUString( PARSER_SERVICE_NAME );
586 0 : return seq;
587 : }
588 :
589 :
590 : /*---------------------------------------
591 : *
592 : * Helper functions and classes
593 : *
594 : *-------------------------------------------*/
595 :
596 : namespace {
597 :
598 1 : OUString lclGetErrorMessage( XML_Error xmlE, const OUString& sSystemId, sal_Int32 nLine )
599 : {
600 1 : const sal_Char* pMessage = "";
601 1 : switch( xmlE )
602 : {
603 0 : case XML_ERROR_NONE: pMessage = "No"; break;
604 0 : case XML_ERROR_NO_MEMORY: pMessage = "no memory"; break;
605 0 : case XML_ERROR_SYNTAX: pMessage = "syntax"; break;
606 0 : case XML_ERROR_NO_ELEMENTS: pMessage = "no elements"; break;
607 0 : case XML_ERROR_INVALID_TOKEN: pMessage = "invalid token"; break;
608 0 : case XML_ERROR_UNCLOSED_TOKEN: pMessage = "unclosed token"; break;
609 0 : case XML_ERROR_PARTIAL_CHAR: pMessage = "partial char"; break;
610 1 : case XML_ERROR_TAG_MISMATCH: pMessage = "tag mismatch"; break;
611 0 : case XML_ERROR_DUPLICATE_ATTRIBUTE: pMessage = "duplicate attribute"; break;
612 0 : case XML_ERROR_JUNK_AFTER_DOC_ELEMENT: pMessage = "junk after doc element"; break;
613 0 : case XML_ERROR_PARAM_ENTITY_REF: pMessage = "parameter entity reference"; break;
614 0 : case XML_ERROR_UNDEFINED_ENTITY: pMessage = "undefined entity"; break;
615 0 : case XML_ERROR_RECURSIVE_ENTITY_REF: pMessage = "recursive entity reference"; break;
616 0 : case XML_ERROR_ASYNC_ENTITY: pMessage = "async entity"; break;
617 0 : case XML_ERROR_BAD_CHAR_REF: pMessage = "bad char reference"; break;
618 0 : case XML_ERROR_BINARY_ENTITY_REF: pMessage = "binary entity reference"; break;
619 0 : case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF: pMessage = "attribute external entity reference"; break;
620 0 : case XML_ERROR_MISPLACED_XML_PI: pMessage = "misplaced xml processing instruction"; break;
621 0 : case XML_ERROR_UNKNOWN_ENCODING: pMessage = "unknown encoding"; break;
622 0 : case XML_ERROR_INCORRECT_ENCODING: pMessage = "incorrect encoding"; break;
623 0 : case XML_ERROR_UNCLOSED_CDATA_SECTION: pMessage = "unclosed cdata section"; break;
624 0 : case XML_ERROR_EXTERNAL_ENTITY_HANDLING: pMessage = "external entity reference"; break;
625 0 : case XML_ERROR_NOT_STANDALONE: pMessage = "not standalone"; break;
626 : default:;
627 : }
628 :
629 1 : OUStringBuffer aBuffer( sal_Unicode( '[' ) );
630 1 : aBuffer.append( sSystemId );
631 1 : aBuffer.append( " line " );
632 1 : aBuffer.append( nLine );
633 1 : aBuffer.append( "]: " );
634 1 : aBuffer.append( pMessage );
635 1 : aBuffer.append( " error" );
636 1 : return aBuffer.makeStringAndClear();
637 : }
638 :
639 : } // namespace
640 :
641 : // starts parsing with actual parser !
642 1811 : void FastSaxParser::parse()
643 : {
644 1811 : const int BUFFER_SIZE = 16 * 1024;
645 1811 : Sequence< sal_Int8 > seqOut( BUFFER_SIZE );
646 :
647 1811 : Entity& rEntity = getEntity();
648 1811 : int nRead = 0;
649 1884 : do
650 : {
651 3695 : nRead = rEntity.maConverter.readAndConvert( seqOut, BUFFER_SIZE );
652 3695 : if( nRead <= 0 )
653 : {
654 1810 : XML_Parse( rEntity.mpParser, (const char*) seqOut.getConstArray(), 0, 1 );
655 1810 : break;
656 : }
657 :
658 : bool const bContinue = XML_STATUS_ERROR != XML_Parse(rEntity.mpParser,
659 1885 : reinterpret_cast<const char*>(seqOut.getConstArray()), nRead, 0);
660 : // callbacks used inside XML_Parse may have caught an exception
661 1885 : if( !bContinue || rEntity.maSavedException.hasValue() )
662 : {
663 : // Error during parsing !
664 1 : XML_Error xmlE = XML_GetErrorCode( rEntity.mpParser );
665 1 : OUString sSystemId = mxDocumentLocator->getSystemId();
666 1 : sal_Int32 nLine = mxDocumentLocator->getLineNumber();
667 :
668 : SAXParseException aExcept(
669 : lclGetErrorMessage( xmlE, sSystemId, nLine ),
670 : Reference< XInterface >(),
671 1 : Any( &rEntity.maSavedException, getCppuType( &rEntity.maSavedException ) ),
672 1 : mxDocumentLocator->getPublicId(),
673 1 : mxDocumentLocator->getSystemId(),
674 1 : mxDocumentLocator->getLineNumber(),
675 1 : mxDocumentLocator->getColumnNumber()
676 6 : );
677 :
678 : // error handler is set, it may throw the exception
679 1 : if( rEntity.mxErrorHandler.is() )
680 0 : rEntity.mxErrorHandler->fatalError( Any( aExcept ) );
681 :
682 : // error handler has not thrown, but parsing cannot go on, the
683 : // exception MUST be thrown
684 2 : throw aExcept;
685 : }
686 : }
687 1811 : while( nRead > 0 );
688 1810 : }
689 :
690 : //------------------------------------------
691 : //
692 : // The C-Callbacks
693 : //
694 : //-----------------------------------------
695 :
696 : namespace {
697 :
698 327778 : struct AttributeData
699 : {
700 : OString maPrefix;
701 : OString maName;
702 : OString maValue;
703 : };
704 :
705 : } // namespace
706 :
707 112475 : void FastSaxParser::callbackStartElement( const XML_Char* pwName, const XML_Char** awAttributes )
708 : {
709 112475 : Reference< XFastContextHandler > xParentContext;
710 112475 : Entity& rEntity = getEntity();
711 112475 : if( !rEntity.maContextStack.empty() )
712 : {
713 110664 : xParentContext = rEntity.maContextStack.top()->mxContext;
714 110664 : if( !xParentContext.is() )
715 : {
716 : // we ignore current elements, so no processing needed
717 22289 : pushContext();
718 134764 : return;
719 : }
720 : }
721 :
722 90186 : pushContext();
723 :
724 90186 : rEntity.mxAttributes->clear();
725 :
726 : // create attribute map and process namespace instructions
727 90186 : int i = 0;
728 : sal_Int32 nNameLen, nPrefixLen;
729 : const XML_Char *pName;
730 : const XML_Char *pPrefix;
731 :
732 : try
733 : {
734 : /* #158414# Each element may define new namespaces, also for attribues.
735 : First, process all namespace attributes and cache other attributes in a
736 : vector. Second, process the attributes after namespaces have been
737 : initialized. */
738 90186 : ::std::vector< AttributeData > aAttribs;
739 :
740 : // #158414# first: get namespaces
741 203972 : for( ; awAttributes[i]; i += 2 )
742 : {
743 : assert(awAttributes[i+1]);
744 :
745 113786 : splitName( awAttributes[i], pPrefix, nPrefixLen, pName, nNameLen );
746 113786 : if( nPrefixLen )
747 : {
748 68326 : if( (nPrefixLen == 5) && (strncmp( pPrefix, "xmlns", 5 ) == 0) )
749 : {
750 5874 : DefineNamespace( OString( pName, nNameLen ), awAttributes[i+1] );
751 : }
752 : else
753 : {
754 62452 : aAttribs.resize( aAttribs.size() + 1 );
755 62452 : aAttribs.back().maPrefix = OString( pPrefix, nPrefixLen );
756 62452 : aAttribs.back().maName = OString( pName, nNameLen );
757 62452 : aAttribs.back().maValue = OString( awAttributes[i+1] );
758 : }
759 : }
760 : else
761 : {
762 45460 : if( (nNameLen == 5) && (strcmp( pName, "xmlns" ) == 0) )
763 : {
764 : // namespace of the element found
765 745 : rEntity.maContextStack.top()->maNamespace = OUString( awAttributes[i+1], strlen( awAttributes[i+1] ), RTL_TEXTENCODING_UTF8 );
766 : }
767 : else
768 : {
769 44715 : aAttribs.resize( aAttribs.size() + 1 );
770 44715 : aAttribs.back().maName = OString( pName, nNameLen );
771 44715 : aAttribs.back().maValue = OString( awAttributes[i+1] );
772 : }
773 : }
774 : }
775 :
776 : // #158414# second: fill attribute list with other attributes
777 197353 : for( ::std::vector< AttributeData >::const_iterator aIt = aAttribs.begin(), aEnd = aAttribs.end(); aIt != aEnd; ++aIt )
778 : {
779 107167 : if( !aIt->maPrefix.isEmpty() )
780 : {
781 62452 : sal_Int32 nAttributeToken = GetTokenWithPrefix( aIt->maPrefix, aIt->maName );
782 62452 : if( nAttributeToken != FastToken::DONTKNOW )
783 61949 : rEntity.mxAttributes->add( nAttributeToken, aIt->maValue );
784 : else
785 503 : rEntity.mxAttributes->addUnknown( GetNamespaceURL( aIt->maPrefix ), aIt->maName, aIt->maValue );
786 : }
787 : else
788 : {
789 44715 : sal_Int32 nAttributeToken = GetToken( aIt->maName );
790 44715 : if( nAttributeToken != FastToken::DONTKNOW )
791 44715 : rEntity.mxAttributes->add( nAttributeToken, aIt->maValue );
792 : else
793 0 : rEntity.mxAttributes->addUnknown( aIt->maName, aIt->maValue );
794 : }
795 : }
796 :
797 : sal_Int32 nElementToken;
798 90186 : splitName( pwName, pPrefix, nPrefixLen, pName, nNameLen );
799 90186 : if( nPrefixLen > 0 )
800 80300 : nElementToken = GetTokenWithPrefix( pPrefix, nPrefixLen, pName, nNameLen );
801 9886 : else if( !rEntity.maContextStack.top()->maNamespace.isEmpty() )
802 9882 : nElementToken = GetTokenWithNamespaceURL( rEntity.maContextStack.top()->maNamespace, pName, nNameLen );
803 : else
804 4 : nElementToken = GetToken( pName );
805 90186 : rEntity.maContextStack.top()->mnElementToken = nElementToken;
806 :
807 180372 : Reference< XFastAttributeList > xAttr( rEntity.mxAttributes.get() );
808 180372 : Reference< XFastContextHandler > xContext;
809 90186 : if( nElementToken == FastToken::DONTKNOW )
810 : {
811 34 : if( nPrefixLen > 0 )
812 34 : rEntity.maContextStack.top()->maNamespace = GetNamespaceURL( pPrefix, nPrefixLen );
813 :
814 34 : const OUString aNamespace( rEntity.maContextStack.top()->maNamespace );
815 68 : const OUString aElementName( pName, nNameLen, RTL_TEXTENCODING_UTF8 );
816 34 : rEntity.maContextStack.top()->maElementName = aElementName;
817 :
818 34 : if( xParentContext.is() )
819 34 : xContext = xParentContext->createUnknownChildContext( aNamespace, aElementName, xAttr );
820 : else
821 0 : xContext = rEntity.mxDocumentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
822 :
823 34 : if( xContext.is() )
824 : {
825 19 : rEntity.maContextStack.top()->mxContext = xContext;
826 19 : xContext->startUnknownElement( aNamespace, aElementName, xAttr );
827 34 : }
828 : }
829 : else
830 : {
831 90152 : if( xParentContext.is() )
832 88341 : xContext = xParentContext->createFastChildContext( nElementToken, xAttr );
833 : else
834 1811 : xContext = rEntity.mxDocumentHandler->createFastChildContext( nElementToken, xAttr );
835 :
836 :
837 90152 : if( xContext.is() )
838 : {
839 85284 : rEntity.maContextStack.top()->mxContext = xContext;
840 85284 : xContext->startFastElement( nElementToken, xAttr );
841 : }
842 90186 : }
843 : }
844 0 : catch (const Exception& e)
845 : {
846 0 : rEntity.maSavedException <<= e;
847 90186 : }
848 : }
849 :
850 112469 : void FastSaxParser::callbackEndElement( SAL_UNUSED_PARAMETER const XML_Char* )
851 : {
852 112469 : Entity& rEntity = getEntity();
853 : assert(!rEntity.maContextStack.empty()); // no context?
854 112469 : if( !rEntity.maContextStack.empty() )
855 : {
856 112469 : SaxContextImplPtr pContext = rEntity.maContextStack.top();
857 112469 : const Reference< XFastContextHandler >& xContext( pContext->mxContext );
858 112469 : if( xContext.is() ) try
859 : {
860 85297 : sal_Int32 nElementToken = pContext->mnElementToken;
861 85297 : if( nElementToken != FastToken::DONTKNOW )
862 85278 : xContext->endFastElement( nElementToken );
863 : else
864 19 : xContext->endUnknownElement( pContext->maNamespace, pContext->maElementName );
865 : }
866 0 : catch (const Exception& e)
867 : {
868 0 : rEntity.maSavedException <<= e;
869 : }
870 :
871 112469 : popContext();
872 : }
873 112469 : }
874 :
875 :
876 21067 : void FastSaxParser::callbackCharacters( const XML_Char* s, int nLen )
877 : {
878 21067 : Entity& rEntity = getEntity();
879 21067 : const Reference< XFastContextHandler >& xContext( rEntity.maContextStack.top()->mxContext );
880 21067 : if( xContext.is() ) try
881 : {
882 20648 : xContext->characters( OUString( s, nLen, RTL_TEXTENCODING_UTF8 ) );
883 : }
884 0 : catch (const Exception& e)
885 : {
886 0 : rEntity.maSavedException <<= e;
887 : }
888 21067 : }
889 :
890 0 : void FastSaxParser::callbackEntityDecl(
891 : SAL_UNUSED_PARAMETER const XML_Char * /*entityName*/,
892 : SAL_UNUSED_PARAMETER int /*is_parameter_entity*/,
893 : const XML_Char *value, SAL_UNUSED_PARAMETER int /*value_length*/,
894 : SAL_UNUSED_PARAMETER const XML_Char * /*base*/,
895 : SAL_UNUSED_PARAMETER const XML_Char * /*systemId*/,
896 : SAL_UNUSED_PARAMETER const XML_Char * /*publicId*/,
897 : SAL_UNUSED_PARAMETER const XML_Char * /*notationName*/)
898 : {
899 0 : if (value) { // value != 0 means internal entity
900 : SAL_INFO("sax", "FastSaxParser: internal entity declaration, stopping");
901 0 : XML_StopParser(getEntity().mpParser, XML_FALSE);
902 0 : getEntity().maSavedException <<= SAXParseException(
903 : "FastSaxParser: internal entity declaration, stopping",
904 : static_cast<OWeakObject*>(this), Any(),
905 0 : mxDocumentLocator->getPublicId(),
906 0 : mxDocumentLocator->getSystemId(),
907 0 : mxDocumentLocator->getLineNumber(),
908 0 : mxDocumentLocator->getColumnNumber() );
909 : } else {
910 : SAL_INFO("sax", "FastSaxParser: ignoring external entity declaration");
911 : }
912 0 : }
913 :
914 0 : int FastSaxParser::callbackExternalEntityRef(
915 : XML_Parser parser, const XML_Char *context,
916 : SAL_UNUSED_PARAMETER const XML_Char * /*base*/, const XML_Char *systemId,
917 : const XML_Char *publicId )
918 : {
919 0 : bool bOK = true;
920 0 : InputSource source;
921 :
922 0 : Entity& rCurrEntity = getEntity();
923 0 : Entity aNewEntity( rCurrEntity );
924 :
925 0 : if( rCurrEntity.mxEntityResolver.is() ) try
926 : {
927 0 : aNewEntity.maStructSource = rCurrEntity.mxEntityResolver->resolveEntity(
928 0 : OUString( publicId, strlen( publicId ), RTL_TEXTENCODING_UTF8 ) ,
929 0 : OUString( systemId, strlen( systemId ), RTL_TEXTENCODING_UTF8 ) );
930 : }
931 0 : catch (const SAXParseException & e)
932 : {
933 0 : rCurrEntity.maSavedException <<= e;
934 0 : bOK = false;
935 : }
936 0 : catch (const SAXException& e)
937 : {
938 0 : rCurrEntity.maSavedException <<= SAXParseException(
939 : e.Message, e.Context, e.WrappedException,
940 0 : mxDocumentLocator->getPublicId(),
941 0 : mxDocumentLocator->getSystemId(),
942 0 : mxDocumentLocator->getLineNumber(),
943 0 : mxDocumentLocator->getColumnNumber() );
944 0 : bOK = false;
945 : }
946 :
947 0 : if( aNewEntity.maStructSource.aInputStream.is() )
948 : {
949 0 : aNewEntity.mpParser = XML_ExternalEntityParserCreate( parser, context, 0 );
950 0 : if( !aNewEntity.mpParser )
951 : {
952 0 : return false;
953 : }
954 :
955 0 : aNewEntity.maConverter.setInputStream( aNewEntity.maStructSource.aInputStream );
956 0 : pushEntity( aNewEntity );
957 : try
958 : {
959 0 : parse();
960 : }
961 0 : catch (const SAXParseException& e)
962 : {
963 0 : rCurrEntity.maSavedException <<= e;
964 0 : bOK = false;
965 : }
966 0 : catch (const IOException& e)
967 : {
968 0 : SAXException aEx;
969 0 : aEx.WrappedException <<= e;
970 0 : rCurrEntity.maSavedException <<= aEx;
971 0 : bOK = false;
972 : }
973 0 : catch (const RuntimeException& e)
974 : {
975 0 : SAXException aEx;
976 0 : aEx.WrappedException <<= e;
977 0 : rCurrEntity.maSavedException <<= aEx;
978 0 : bOK = false;
979 : }
980 :
981 0 : popEntity();
982 0 : XML_ParserFree( aNewEntity.mpParser );
983 : }
984 :
985 0 : return bOK;
986 : }
987 :
988 : } // namespace sax_fastparser
989 :
990 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|