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