1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmlsecurity.hxx"
30 
31 #include "saxeventkeeperimpl.hxx"
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
34 #include <com/sun/star/xml/crypto/sax/ConstOfSecurityId.hpp>
35 
36 namespace cssu = com::sun::star::uno;
37 namespace cssl = com::sun::star::lang;
38 namespace cssxc = com::sun::star::xml::crypto;
39 namespace cssxcsax = com::sun::star::xml::csax;
40 namespace cssxw = com::sun::star::xml::wrapper;
41 namespace cssxs = com::sun::star::xml::sax;
42 
43 #define SERVICE_NAME "com.sun.star.xml.crypto.sax.SAXEventKeeper"
44 #define IMPLEMENTATION_NAME "com.sun.star.xml.security.framework.SAXEventKeeperImpl"
45 
46 #define _USECOMPRESSEDDOCUMENTHANDLER
47 
48 SAXEventKeeperImpl::SAXEventKeeperImpl( )
49 	:m_pRootBufferNode(NULL),
50 	 m_pCurrentBufferNode(NULL),
51      m_nNextElementMarkId(1),
52 	 m_pNewBlocker(NULL),
53 	 m_pCurrentBlockingBufferNode(NULL),
54 	 m_bIsReleasing(false),
55 	 m_bIsForwarding(false)
56 {
57 	m_vElementMarkBuffers.reserve(2);
58 	m_vNewElementCollectors.reserve(2);
59 	m_vReleasedElementMarkBuffers.reserve(2);
60 }
61 
62 SAXEventKeeperImpl::~SAXEventKeeperImpl()
63 {
64 	/*
65 	 * delete the BufferNode tree
66 	 */
67 	if (m_pRootBufferNode != NULL)
68 	{
69         m_pRootBufferNode->freeAllChildren();
70 		delete m_pRootBufferNode;
71 	}
72 
73 	m_pRootBufferNode = m_pCurrentBufferNode = m_pCurrentBlockingBufferNode = NULL;
74 
75 	/*
76 	 * delete all unfreed ElementMarks
77 	 */
78 	m_vNewElementCollectors.clear();
79 	m_pNewBlocker = NULL;
80 
81 	std::vector< const ElementMark* >::const_iterator ii = m_vElementMarkBuffers.begin();
82 	for( ; ii != m_vElementMarkBuffers.end(); ++ii )
83 	{
84 		delete (*ii);
85 	}
86 	m_vElementMarkBuffers.clear();
87 }
88 
89 void SAXEventKeeperImpl::setCurrentBufferNode(BufferNode* pBufferNode)
90 /****** SAXEventKeeperImpl/setCurrentBufferNode ******************************
91  *
92  *   NAME
93  *	setCurrentBufferNode -- set a new active BufferNode.
94  *
95  *   SYNOPSIS
96  *	setCurrentBufferNode( pBufferNode );
97  *
98  *   FUNCTION
99  *	connects this BufferNode into the BufferNode tree as a child of the
100  *	current active BufferNode. Then makes this BufferNode as the current
101  *	active BufferNode.
102  *	If the previous active BufferNode points to the root
103  *	BufferNode, which means that no buffering operation was proceeding,
104  *	then notifies the status change listener that buffering  operation
105  *	will begin at once.
106  *
107  *   INPUTS
108  *	pBufferNode - a BufferNode which will be the new active BufferNode
109  *
110  *   RESULT
111  *	empty
112  *
113  *   HISTORY
114  *	05.01.2004 -	implemented
115  *
116  *   AUTHOR
117  *	Michael Mi
118  *	Email: michael.mi@sun.com
119  ******************************************************************************/
120 {
121 	if (pBufferNode != m_pCurrentBufferNode)
122 	{
123 		if ( m_pCurrentBufferNode == m_pRootBufferNode &&
124 		     m_xSAXEventKeeperStatusChangeListener.is())
125 		{
126 			m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(sal_True);
127 		}
128 
129 		if (pBufferNode->getParent() == NULL)
130 		{
131 			m_pCurrentBufferNode->addChild(pBufferNode);
132 			pBufferNode->setParent(m_pCurrentBufferNode);
133 		}
134 
135 		m_pCurrentBufferNode = pBufferNode;
136 	}
137 }
138 
139 BufferNode* SAXEventKeeperImpl::addNewElementMarkBuffers()
140 /****** SAXEventKeeperImpl/addNewElementMarkBuffers **************************
141  *
142  *   NAME
143  *	addNewElementMarkBuffers -- add new ElementCollectors and new Blocker.
144  *
145  *   SYNOPSIS
146  *	pBufferNode = addNewElementMarkBuffers( );
147  *
148  *   FUNCTION
149  *	if there are new ElementCollector or new Blocker to be added, then
150  *	connect all of them with the current BufferNode. In case of the
151  *	current BufferNode doesn't exist, creates one.
152  *	Clears up the new ElementCollector list and the new Blocker pointer.
153  *
154  *   INPUTS
155  *	empty
156  *
157  *   RESULT
158  *	pBufferNode - the BufferNode that has been connected with both new
159  *	              ElementCollectors and new Blocker.
160  *
161  *   HISTORY
162  *	05.01.2004 -	implemented
163  *
164  *   AUTHOR
165  *	Michael Mi
166  *	Email: michael.mi@sun.com
167  ******************************************************************************/
168 {
169 	BufferNode* pBufferNode = NULL;
170 
171 	if ( (m_vNewElementCollectors.size()>0) ||
172 	     (m_pNewBlocker != NULL))
173 	{
174 		/*
175 		 * When the current BufferNode is right pointing to the current
176 		 * working element in the XMLDocumentWrapper component, then
177 		 * no new BufferNode is needed to create.
178 		 * This situation can only happen in the "Forwarding" mode.
179 		 */
180 		if ( (m_pCurrentBufferNode != NULL) &&
181 		     (m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement())))
182 		{
183 			pBufferNode = m_pCurrentBufferNode;
184 		}
185 		else
186 		{
187 			pBufferNode = new BufferNode(m_xXMLDocument->getCurrentElement());
188 		}
189 
190 		if (m_pNewBlocker != NULL)
191 		{
192 			pBufferNode->setBlocker(m_pNewBlocker);
193 
194 			/*
195 			 * If no blocking before, then notify the status change listener that
196 			 * the SAXEventKeeper has entered "blocking" status, during which, no
197 			 * SAX events will be forwarded to the next document handler.
198 			 */
199 			if (m_pCurrentBlockingBufferNode == NULL)
200 			{
201 				m_pCurrentBlockingBufferNode = pBufferNode;
202 
203 				if (m_xSAXEventKeeperStatusChangeListener.is())
204 				{
205 					m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(sal_True);
206 				}
207 			}
208 
209 			m_pNewBlocker = NULL;
210 		}
211 
212 		if (m_vNewElementCollectors.size()>0)
213 		{
214 			std::vector< const ElementCollector* >::const_iterator ii = m_vNewElementCollectors.begin();
215 
216 			for( ; ii != m_vNewElementCollectors.end(); ++ii )
217 			{
218 				pBufferNode->addElementCollector(*ii);
219 			}
220 
221 			m_vNewElementCollectors.clear();
222 		}
223 	}
224 
225 	return pBufferNode;
226 }
227 
228 ElementMark* SAXEventKeeperImpl::findElementMarkBuffer(sal_Int32 nId) const
229 /****** SAXEventKeeperImpl/findElementMarkBuffer *****************************
230  *
231  *   NAME
232  *	findElementMarkBuffer -- finds an ElementMark.
233  *
234  *   SYNOPSIS
235  *	pElementMark = findElementMarkBuffer( nId );
236  *
237  *   FUNCTION
238  *	searches an ElementMark with the particular Id in the ElementMark
239  *	list.
240  *
241  *   INPUTS
242  *	nId - the Id of the ElementMark to be searched.
243  *
244  *   RESULT
245  *	pElementMark - the ElementMark with the particular Id, or NULL when
246  *	               no such Id exists.
247  *
248  *   HISTORY
249  *	05.01.2004 -	implemented
250  *
251  *   AUTHOR
252  *	Michael Mi
253  *	Email: michael.mi@sun.com
254  ******************************************************************************/
255 {
256 	ElementMark* pElementMark = NULL;
257 
258 	std::vector< const ElementMark* >::const_iterator ii = m_vElementMarkBuffers.begin();
259 
260 	for( ; ii != m_vElementMarkBuffers.end(); ++ii )
261 	{
262 		if ( nId == (*ii)->getBufferId())
263 		{
264 			pElementMark = (ElementMark*)*ii;
265 			break;
266 		}
267 	}
268 
269 	return pElementMark;
270 }
271 
272 void SAXEventKeeperImpl::removeElementMarkBuffer(sal_Int32 nId)
273 /****** SAXEventKeeperImpl/removeElementMarkBuffer ***************************
274  *
275  *   NAME
276  *	removeElementMarkBuffer -- removes an ElementMark
277  *
278  *   SYNOPSIS
279  *	removeElementMarkBuffer( nId );
280  *
281  *   FUNCTION
282  *	removes an ElementMark with the particular Id in the ElementMark list.
283  *
284  *   INPUTS
285  *	nId - the Id of the ElementMark to be removed.
286  *
287  *   RESULT
288  *	empty
289  *
290  *   HISTORY
291  *	05.01.2004 -	implemented
292  *
293  *   AUTHOR
294  *	Michael Mi
295  *	Email: michael.mi@sun.com
296  ******************************************************************************/
297 {
298 	std::vector< const ElementMark* >::iterator ii = m_vElementMarkBuffers.begin();
299 
300 	for( ; ii != m_vElementMarkBuffers.end(); ++ii )
301 	{
302 		if ( nId == (*ii)->getBufferId())
303 		{
304 			/*
305 			 * checks whether this ElementMark still in the new ElementCollect array
306 			 */
307 			std::vector< const ElementCollector* >::iterator jj = m_vNewElementCollectors.begin();
308 			for( ; jj != m_vNewElementCollectors.end(); ++jj )
309 			{
310 				if ((*ii) == (*jj))
311 				{
312 					m_vNewElementCollectors.erase(jj);
313 					break;
314 				}
315 			}
316 
317 			/*
318 			 * checks whether this ElementMark is the new Blocker
319 			 */
320 			if ((*ii) == m_pNewBlocker)
321 			{
322 				m_pNewBlocker = NULL;
323 			}
324 
325 			/*
326 			 * destory the ElementMark
327 			 */
328 			delete (*ii);
329 
330 			m_vElementMarkBuffers.erase( ii );
331 			break;
332 		}
333 	}
334 }
335 
336 rtl::OUString SAXEventKeeperImpl::printBufferNode(
337 	BufferNode* pBufferNode, sal_Int32 nIndent) const
338 /****** SAXEventKeeperImpl/printBufferNode ***********************************
339  *
340  *   NAME
341  *	printBufferNode -- retrieves the information of a BufferNode and its
342  *	branch.
343  *
344  *   SYNOPSIS
345  *	info = printBufferNode( pBufferNode, nIndent );
346  *
347  *   FUNCTION
348  *	all retrieved information includes:
349  *	1. whether it is the current BufferNode;
350  *	2. whether it is the current blocking BufferNode;
351  *	3. the name of the parent element;
352  *	4. the name of this element;
353  *	5. all ElementCollectors working on this BufferNode;
354  *	6. the Blocker working on this BufferNode;
355  *	7. all child BufferNodes' information.
356  *
357  *   INPUTS
358  *	pBufferNode - 	the BufferNode from where information will be retrieved.
359  *	nIndent - 	how many space characters prefixed before the output
360  *	          	message.
361  *
362  *   RESULT
363  *	info - the information string
364  *
365  *   HISTORY
366  *	05.01.2004 -	implemented
367  *
368  *   AUTHOR
369  *	Michael Mi
370  *	Email: michael.mi@sun.com
371  ******************************************************************************/
372 {
373 	rtl::OUString rc;
374 
375 	for ( int i=0; i<nIndent; ++i )
376 	{
377 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " " ));
378 	}
379 
380 	if (pBufferNode == m_pCurrentBufferNode)
381 	{
382 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "[%]" ));
383 	}
384 
385 	if (pBufferNode == m_pCurrentBlockingBufferNode)
386 	{
387 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "[B]" ));
388 	}
389 
390 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " " ));
391 	rc += m_xXMLDocument->getNodeName(pBufferNode->getXMLElement());
392 
393 	BufferNode* pParent = (BufferNode*)pBufferNode->getParent();
394 	if (pParent != NULL)
395 	{
396 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "[" ));
397 		rc += m_xXMLDocument->getNodeName(pParent->getXMLElement());
398 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "]" ));
399 	}
400 
401 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ":EC=" ));
402 	rc += pBufferNode->printChildren();
403 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " BR=" ));
404 
405 	ElementMark * pBlocker = pBufferNode->getBlocker();
406 	if (pBlocker != NULL)
407 	{
408 		rc += rtl::OUString::valueOf( pBlocker->getBufferId() );
409 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "(SecId=" ));
410 		rc += rtl::OUString::valueOf( pBlocker->getSecurityId() );
411 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ")" ));
412 		rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " " ));
413 	}
414 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "\n" ));
415 
416 	std::vector< const BufferNode* >* vChildren = pBufferNode->getChildren();
417 	std::vector< const BufferNode* >::const_iterator jj = vChildren->begin();
418 	for( ; jj != vChildren->end(); ++jj )
419 	{
420 		rc += printBufferNode((BufferNode *)*jj, nIndent+4);
421 	}
422 
423 	delete vChildren;
424 
425 	return rc;
426 }
427 
428 cssu::Sequence< cssu::Reference< cssxw::XXMLElementWrapper > >
429 	SAXEventKeeperImpl::collectChildWorkingElement(BufferNode* pBufferNode) const
430 /****** SAXEventKeeperImpl/collectChildWorkingElement ************************
431  *
432  *   NAME
433  *	collectChildWorkingElement -- collects a BufferNode's all child
434  *	Elements.
435  *
436  *   SYNOPSIS
437  *	list = collectChildWorkingElement( pBufferNode );
438  *
439  *   FUNCTION
440  *	see NAME.
441  *
442  *   INPUTS
443  *	pBufferNode - the BufferNode whose child Elements will be collected.
444  *
445  *   RESULT
446  *	list - the child Elements list.
447  *
448  *   HISTORY
449  *	05.01.2004 -	implemented
450  *
451  *   AUTHOR
452  *	Michael Mi
453  *	Email: michael.mi@sun.com
454  ******************************************************************************/
455 {
456 	std::vector< const BufferNode* >* vChildren = pBufferNode->getChildren();
457 
458 	cssu::Sequence < cssu::Reference<
459 		cssxw::XXMLElementWrapper > > aChildrenCollection ( vChildren->size());
460 
461 	std::vector< const BufferNode* >::const_iterator ii = vChildren->begin();
462 
463 	sal_Int32 nIndex = 0;
464 	for( ; ii != vChildren->end(); ++ii )
465 	{
466 		aChildrenCollection[nIndex] = (*ii)->getXMLElement();
467 		nIndex++;
468 	}
469 
470 	delete vChildren;
471 
472 	return aChildrenCollection;
473 }
474 
475 void SAXEventKeeperImpl::smashBufferNode(
476 	BufferNode* pBufferNode, bool bClearRoot) const
477 /****** SAXEventKeeperImpl/smashBufferNode ***********************************
478  *
479  *   NAME
480  *	smashBufferNode -- removes a BufferNode along with its working
481  *	element.
482  *
483  *   SYNOPSIS
484  *	smashBufferNode( pBufferNode, bClearRoot );
485  *
486  *   FUNCTION
487  *	removes the BufferNode's working element from the DOM document, while
488  *	reserves all ancestor paths for its child BufferNodes.
489  *	when any of the BufferNode's ancestor element is useless, removes it
490  *	too.
491  *	removes the BufferNode from the BufferNode tree.
492  *
493  *   INPUTS
494  *	pBufferNode - 	the BufferNode to be removed
495  *	bClearRoot - 	whether the root element also needs to be cleared up.
496  *
497  *   RESULT
498  *	empty
499  *
500  *   NOTES
501  *	when removeing a Blocker's BufferNode, the bClearRoot flag should be
502  *	true. Because a Blocker can buffer many SAX events which are not used
503  *	by any other ElementCollector or Blocker.
504  *	When the bClearRoot is set to true, the root BufferNode will be first
505  *	cleared, with a stop flag seting at the next Blocking BufferNode. This
506  *	operation can delete all useless bufferred SAX events which are only
507  *	needed by the Blocker to be deleted.
508  *
509  *   HISTORY
510  *	05.01.2004 -	implemented
511  *
512  *   AUTHOR
513  *	Michael Mi
514  *	Email: michael.mi@sun.com
515  ******************************************************************************/
516 {
517 	if (!pBufferNode->hasAnything())
518 	{
519 		BufferNode* pParent = (BufferNode*)pBufferNode->getParent();
520 
521 	        /*
522 	         * delete the XML data
523 	         */
524 		if (pParent == m_pRootBufferNode)
525 		{
526 			bool bIsNotBlocking = (m_pCurrentBlockingBufferNode == NULL);
527 			bool bIsBlockInside = false;
528 			bool bIsBlockingAfterward = false;
529 
530 		        /*
531 		         * If this is a blocker, then remove any out-element data
532 		         * which caused by blocking. The removal process will stop
533 		         * at the next blokcer to avoid removing any useful data.
534 		         */
535 			if (bClearRoot)
536 			{
537 				cssu::Sequence< cssu::Reference< cssxw::XXMLElementWrapper > >
538 					aChildElements = collectChildWorkingElement(m_pRootBufferNode);
539 
540 			        /*
541 			         * the clearUselessData only clearup the content in the
542 			         * node, not the node itself.
543 			         */
544 				m_xXMLDocument->clearUselessData(m_pRootBufferNode->getXMLElement(),
545 					aChildElements,
546 					bIsNotBlocking?(NULL):
547 					               (m_pCurrentBlockingBufferNode->getXMLElement()));
548 
549 			        /*
550 			         * remove the node if it is empty, then if its parent is also
551 			         * empty, remove it, then if the next parent is also empty,
552 			         * remove it,..., until parent become null.
553 			         */
554 				m_xXMLDocument->collapse( m_pRootBufferNode->getXMLElement() );
555 			}
556 
557 			/*
558 			 * if blocking, check the relationship between this BufferNode and
559 			 * the current blocking BufferNode.
560 			 */
561 			if ( !bIsNotBlocking )
562 			{
563 				/*
564 				 * the current blocking BufferNode is a descendant of this BufferNode.
565 				 */
566 				bIsBlockInside = (NULL != pBufferNode->isAncestor(m_pCurrentBlockingBufferNode));
567 
568 				/*
569 				 * the current blocking BufferNode locates behind this BufferNode in tree
570 				 * order.
571 				 */
572 				bIsBlockingAfterward = pBufferNode->isPrevious(m_pCurrentBlockingBufferNode);
573 			}
574 
575 			/*
576 			 * this BufferNode's working element needs to be deleted only when
577 			 * 1. there is no blocking, or
578 			 * 2. the current blocking BufferNode is a descendant of this BufferNode,
579 			 *    (then in the BufferNode's working element, the useless data before the blocking
580 			 *     element should be deleted.) or
581 			 * 3. the current blocking BufferNode is locates behind this BufferNode in tree,
582 			 *    (then the useless data between the blocking element and the working element
583 			 *     should be deleted.).
584 			 * Otherwise, this working element should not be deleted.
585 			 */
586 			if ( bIsNotBlocking || bIsBlockInside || bIsBlockingAfterward )
587 			{
588 				cssu::Sequence< cssu::Reference< cssxw::XXMLElementWrapper > >
589 					aChildElements = collectChildWorkingElement(pBufferNode);
590 
591 			        /*
592 			         * the clearUselessData only clearup the content in the
593 			         * node, not the node itself.
594 			         */
595 				m_xXMLDocument->clearUselessData(pBufferNode->getXMLElement(),
596 					aChildElements,
597 					bIsBlockInside?(m_pCurrentBlockingBufferNode->getXMLElement()):
598 						       (NULL));
599 
600 			        /*
601 			         * remove the node if it is empty, then if its parent is also
602 			         * empty, remove it, then if the next parent is also empty,
603 			         * remove it,..., until parent become null.
604 			         */
605 				m_xXMLDocument->collapse( pBufferNode->getXMLElement() );
606 			}
607 		}
608 
609 		sal_Int32 nIndex = pParent->indexOfChild(pBufferNode);
610 
611 		std::vector< const BufferNode* >* vChildren = pBufferNode->getChildren();
612 		pParent->removeChild(pBufferNode);
613 		pBufferNode->setParent(NULL);
614 
615 		std::vector< const BufferNode * >::const_iterator ii = vChildren->begin();
616 		for( ; ii != vChildren->end(); ++ii )
617 		{
618 			((BufferNode *)(*ii))->setParent(pParent);
619 			pParent->addChild(*ii, nIndex);
620 			nIndex++;
621 		}
622 
623 		delete vChildren;
624 
625 		/*
626 		 * delete the BufferNode
627 		 */
628 		delete pBufferNode;
629 	}
630 }
631 
632 BufferNode* SAXEventKeeperImpl::findNextBlockingBufferNode(
633 	BufferNode* pStartBufferNode) const
634 /****** SAXEventKeeperImpl/findNextBlockingBufferNode ************************
635  *
636  *   NAME
637  *	findNextBlockingBufferNode -- finds the next blocking BufferNode
638  *	behind the particular BufferNode.
639  *
640  *   SYNOPSIS
641  *	pBufferNode = findNextBlockingBufferNode( pStartBufferNode );
642  *
643  *   FUNCTION
644  *	see NAME.
645  *
646  *   INPUTS
647  *	pStartBufferNode - the BufferNode from where to search the next
648  *	                   blocking BufferNode.
649  *
650  *   RESULT
651  *	pBufferNode - the next blocking BufferNode, or NULL if no such
652  *	              BufferNode exists.
653  *
654  *   HISTORY
655  *	05.01.2004 -	implemented
656  *
657  *   AUTHOR
658  *	Michael Mi
659  *	Email: michael.mi@sun.com
660  ******************************************************************************/
661 {
662 	BufferNode* pNext = NULL;
663 
664 	if (pStartBufferNode != NULL)
665 	{
666 		pNext = pStartBufferNode;
667 
668 		while (NULL != (pNext = (BufferNode*)pNext->getNextNodeByTreeOrder()))
669 		{
670 			if (pNext->getBlocker() != NULL)
671 			{
672 				break;
673 			}
674 		}
675 	}
676 
677 	return pNext;
678 }
679 
680 void SAXEventKeeperImpl::diffuse(BufferNode* pBufferNode) const
681 /****** SAXEventKeeperImpl/diffuse *******************************************
682  *
683  *   NAME
684  *	diffuse -- diffuse the notification.
685  *
686  *   SYNOPSIS
687  *	diffuse( pBufferNode );
688  *
689  *   FUNCTION
690  *	diffuse the collecting completion notification from the specific
691  *	BufferNode along its parent link, until an ancestor which is not
692  *	completely received is met.
693  *
694  *   INPUTS
695  *	pBufferNode - the BufferNode from which the notification will be
696  *	              diffused.
697  *
698  *   RESULT
699  *	empty
700  *
701  *   HISTORY
702  *	05.01.2004 -	implemented
703  *
704  *   AUTHOR
705  *	Michael Mi
706  *	Email: michael.mi@sun.com
707  ******************************************************************************/
708 {
709 	BufferNode* pParent = pBufferNode;
710 
711 	while(pParent->isAllReceived())
712 	{
713 		pParent->elementCollectorNotify();
714 		pParent = (BufferNode*)pParent->getParent();
715 	}
716 }
717 
718 void SAXEventKeeperImpl::releaseElementMarkBuffer()
719 /****** SAXEventKeeperImpl/releaseElementMarkBuffer **************************
720  *
721  *   NAME
722  *	releaseElementMarkBuffer -- releases useless ElementMarks
723  *
724  *   SYNOPSIS
725  *	releaseElementMarkBuffer( );
726  *
727  *   FUNCTION
728  *	releases each ElementMark in the releasing list
729  *	m_vReleasedElementMarkBuffers.
730  *	The operation differs between an ElementCollector and a Blocker.
731  *
732  *   INPUTS
733  *	empty
734  *
735  *   RESULT
736  *	empty
737  *
738  *   HISTORY
739  *	05.01.2004 -	implemented
740  *
741  *   AUTHOR
742  *	Michael Mi
743  *	Email: michael.mi@sun.com
744  ******************************************************************************/
745 {
746 	m_bIsReleasing = true;
747 	while (m_vReleasedElementMarkBuffers.size()>0)
748 	{
749 		std::vector< sal_Int32 >::iterator pId = m_vReleasedElementMarkBuffers.begin();
750 		sal_Int32 nId = *pId;
751 		m_vReleasedElementMarkBuffers.erase( pId );
752 
753 		ElementMark* pElementMark = findElementMarkBuffer(nId);
754 
755 		if (pElementMark != NULL)
756 		{
757 			if (cssxc::sax::ElementMarkType_ELEMENTCOLLECTOR
758 				== pElementMark->getType())
759 			/*
760 			 * it is a EC
761 			 */
762 			{
763 				ElementCollector* pElementCollector = (ElementCollector*)pElementMark;
764 
765 				cssxc::sax::ElementMarkPriority nPriority = pElementCollector->getPriority();
766 				bool bToModify = pElementCollector->getModify();
767 
768 				/*
769 			         * Delete the EC from the buffer node.
770 			         */
771 				BufferNode* pBufferNode = pElementCollector->getBufferNode();
772 				pBufferNode->removeElementCollector(pElementCollector);
773 
774 				if ( nPriority == cssxc::sax::ElementMarkPriority_BEFOREMODIFY)
775 				{
776 					pBufferNode->notifyBranch();
777 				}
778 
779 				if (bToModify)
780 				{
781 					pBufferNode->notifyAncestor();
782 				}
783 
784 				/*
785 				 * delete the ElementMark
786 				 */
787 				pElementCollector = NULL;
788 				pElementMark = NULL;
789 				removeElementMarkBuffer(nId);
790 
791 				/*
792 				 * delete the BufferNode
793 				 */
794 				diffuse(pBufferNode);
795 				smashBufferNode(pBufferNode, false);
796 			}
797 			else
798 			/*
799 			 * it is a Blocker
800 			 */
801 			{
802 			        /*
803 			         * Delete the TH from the buffer node.
804 			         */
805 				BufferNode *pBufferNode = pElementMark->getBufferNode();
806 				pBufferNode->setBlocker(NULL);
807 
808 			        /*
809 			         * If there is a following handler and no blocking now, then
810 			         * forward this event
811 			         */
812 				if (m_pCurrentBlockingBufferNode == pBufferNode)
813 				{
814 				        /*
815 				         * Before forwarding, the next blocking point needs to be
816 				         * found.
817 				         */
818 					m_pCurrentBlockingBufferNode = findNextBlockingBufferNode(pBufferNode);
819 
820 				        /*
821 				         * Forward the blocked events between these two STHs.
822 				         */
823 	       				if (m_xNextHandler.is())
824 	       				{
825        						BufferNode* pTempCurrentBufferNode = m_pCurrentBufferNode;
826        						BufferNode* pTempCurrentBlockingBufferNode = m_pCurrentBlockingBufferNode;
827 
828        						m_pCurrentBufferNode = pBufferNode;
829        						m_pCurrentBlockingBufferNode = NULL;
830 
831 						m_bIsForwarding = true;
832 
833 						m_xXMLDocument->generateSAXEvents(
834 							m_xNextHandler,
835 							this,
836 							pBufferNode->getXMLElement(),
837 							(pTempCurrentBlockingBufferNode == NULL)?NULL:(pTempCurrentBlockingBufferNode->getXMLElement()));
838 
839 						m_bIsForwarding = false;
840 
841 						m_pCurrentBufferNode = pTempCurrentBufferNode;
842 						if (m_pCurrentBlockingBufferNode == NULL)
843 						{
844 							m_pCurrentBlockingBufferNode = pTempCurrentBlockingBufferNode;
845 						}
846 					}
847 
848 					if (m_pCurrentBlockingBufferNode == NULL &&
849 					    m_xSAXEventKeeperStatusChangeListener.is())
850 					{
851 						m_xSAXEventKeeperStatusChangeListener->blockingStatusChanged(sal_False);
852 					}
853 				}
854 
855 				/*
856 				 * delete the ElementMark
857 				 */
858 				pElementMark = NULL;
859 				removeElementMarkBuffer(nId);
860 
861 				/*
862 				 * delete the BufferNode
863 				 */
864 				diffuse(pBufferNode);
865 				smashBufferNode(pBufferNode, true);
866 			}
867 		}
868 	}
869 
870 	m_bIsReleasing = false;
871 
872 	if (!m_pRootBufferNode->hasAnything() &&
873 		!m_pRootBufferNode->hasChildren() &&
874 		m_xSAXEventKeeperStatusChangeListener.is())
875 	{
876 		m_xSAXEventKeeperStatusChangeListener->bufferStatusChanged(sal_True);
877 	}
878 }
879 
880 void SAXEventKeeperImpl::markElementMarkBuffer(sal_Int32 nId)
881 /****** SAXEventKeeperImpl/markElementMarkBuffer *****************************
882  *
883  *   NAME
884  *	markElementMarkBuffer -- marks an ElementMark to be released
885  *
886  *   SYNOPSIS
887  *	markElementMarkBuffer( nId );
888  *
889  *   FUNCTION
890  *	puts the ElementMark with the particular Id into the releasing list,
891  *	checks whether the releasing process is runing, if not then launch
892  *	this process.
893  *
894  *   INPUTS
895  *	nId - the Id of the ElementMark which will be released
896  *
897  *   RESULT
898  *	empty
899  *
900  *   HISTORY
901  *	05.01.2004 -	implemented
902  *
903  *   AUTHOR
904  *	Michael Mi
905  *	Email: michael.mi@sun.com
906  ******************************************************************************/
907 {
908 	m_vReleasedElementMarkBuffers.push_back( nId );
909 	if ( !m_bIsReleasing )
910 	{
911 		releaseElementMarkBuffer();
912 	}
913 }
914 
915 sal_Int32 SAXEventKeeperImpl::createElementCollector(
916 	sal_Int32 nSecurityId,
917 	cssxc::sax::ElementMarkPriority nPriority,
918 	bool bModifyElement,
919 	const cssu::Reference< cssxc::sax::XReferenceResolvedListener >& xReferenceResolvedListener)
920 /****** SAXEventKeeperImpl/createElementCollector ****************************
921  *
922  *   NAME
923  *	createElementCollector -- creates a new ElementCollector on the
924  *	incoming element.
925  *
926  *   SYNOPSIS
927  *	nId = createElementCollector( nSecurityId, nPriority,
928  *	                             bModifyElement,
929  *	                             xReferenceResolvedListener );
930  *
931  *   FUNCTION
932  *	allocs a new Id, then create an ElementCollector with this Id value.
933  *	Add the new created ElementCollector to the new ElementCollecotor list.
934  *
935  *   INPUTS
936  *	nSecurityId - 	the security Id of the new ElementCollector
937  *	nPriority - 	the prirority of the new ElementCollector
938  *	bModifyElement -whether this BufferNode will modify the content of
939  *	                the corresponding element it works on
940  *	xReferenceResolvedListener - the listener for the new ElementCollector.
941  *
942  *   RESULT
943  *	nId - the Id of the new ElementCollector
944  *
945  *   HISTORY
946  *	05.01.2004 -	implemented
947  *
948  *   AUTHOR
949  *	Michael Mi
950  *	Email: michael.mi@sun.com
951  ******************************************************************************/
952 {
953 	sal_Int32 nId = m_nNextElementMarkId;
954 	m_nNextElementMarkId ++;
955 
956 	ElementCollector* pElementCollector
957 		= new ElementCollector(
958 			nSecurityId,
959 			nId,
960 			nPriority,
961 			bModifyElement,
962 			xReferenceResolvedListener);
963 
964 	m_vElementMarkBuffers.push_back( pElementCollector );
965 
966         /*
967          * All the new EC to initial EC array.
968          */
969 	m_vNewElementCollectors.push_back( pElementCollector );
970 
971 	return nId;
972 }
973 
974 
975 sal_Int32 SAXEventKeeperImpl::createBlocker(sal_Int32 nSecurityId)
976 /****** SAXEventKeeperImpl/createBlocker *************************************
977  *
978  *   NAME
979  *	createBlocker -- creates a new Blocker on the incoming element.
980  *
981  *   SYNOPSIS
982  *	nId = createBlocker( nSecurityId );
983  *
984  *   FUNCTION
985  *	see NAME.
986  *
987  *   INPUTS
988  *	nSecurityId - 	the security Id of the new Blocker
989  *
990  *   RESULT
991  *	nId - the Id of the new Blocker
992  *
993  *   HISTORY
994  *	05.01.2004 -	implemented
995  *
996  *   AUTHOR
997  *	Michael Mi
998  *	Email: michael.mi@sun.com
999  ******************************************************************************/
1000 {
1001 	sal_Int32 nId = m_nNextElementMarkId;
1002 	m_nNextElementMarkId ++;
1003 
1004 	OSL_ASSERT(m_pNewBlocker == NULL);
1005 
1006 	m_pNewBlocker = new ElementMark(nSecurityId, nId);
1007 	m_vElementMarkBuffers.push_back( m_pNewBlocker );
1008 
1009 	return nId;
1010 }
1011 
1012 /* XSAXEventKeeper */
1013 sal_Int32 SAL_CALL SAXEventKeeperImpl::addElementCollector(  )
1014 	throw (cssu::RuntimeException)
1015 {
1016 	return createElementCollector(
1017 		cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID,
1018 		cssxc::sax::ElementMarkPriority_AFTERMODIFY,
1019 		false,
1020 		NULL);
1021 }
1022 
1023 void SAL_CALL SAXEventKeeperImpl::removeElementCollector( sal_Int32 id )
1024 	throw (cssu::RuntimeException)
1025 {
1026 	markElementMarkBuffer(id);
1027 }
1028 
1029 sal_Int32 SAL_CALL SAXEventKeeperImpl::addBlocker(  )
1030 	throw (cssu::RuntimeException)
1031 {
1032 	return createBlocker(cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID);
1033 }
1034 
1035 void SAL_CALL SAXEventKeeperImpl::removeBlocker( sal_Int32 id )
1036 	throw (cssu::RuntimeException)
1037 {
1038 	markElementMarkBuffer(id);
1039 }
1040 
1041 sal_Bool SAL_CALL SAXEventKeeperImpl::isBlocking(  )
1042 	throw (cssu::RuntimeException)
1043 {
1044 	return (m_pCurrentBlockingBufferNode != NULL);
1045 }
1046 
1047 cssu::Reference< cssxw::XXMLElementWrapper > SAL_CALL
1048 	SAXEventKeeperImpl::getElement( sal_Int32 id )
1049 	throw (cssu::RuntimeException)
1050 {
1051 	cssu::Reference< cssxw::XXMLElementWrapper > rc;
1052 
1053 	ElementMark* pElementMark = findElementMarkBuffer(id);
1054 	if (pElementMark != NULL)
1055 	{
1056 		rc = pElementMark->getBufferNode()->getXMLElement();
1057 	}
1058 
1059 	return rc;
1060 }
1061 
1062 void SAL_CALL SAXEventKeeperImpl::setElement(
1063 	sal_Int32 id,
1064 	const cssu::Reference< cssxw::XXMLElementWrapper >& aElement )
1065 	throw (cssu::RuntimeException)
1066 {
1067 	if (aElement.is())
1068 	{
1069 		m_xXMLDocument->rebuildIDLink(aElement);
1070 
1071 		ElementMark* pElementMark = findElementMarkBuffer(id);
1072 
1073 		if (pElementMark != NULL)
1074 		{
1075 			BufferNode* pBufferNode = pElementMark->getBufferNode();
1076 			if (pBufferNode != NULL)
1077 			{
1078 			        bool bIsCurrent = m_xXMLDocument->isCurrent(pBufferNode->getXMLElement());
1079 				pBufferNode->setXMLElement(aElement);
1080 
1081 				if (bIsCurrent)
1082 				{
1083 					m_xXMLDocument->setCurrentElement(aElement);
1084 				}
1085 			}
1086 		}
1087 	}
1088 	else
1089 	{
1090 		removeElementCollector( id );
1091 	}
1092 }
1093 
1094 cssu::Reference< cssxs::XDocumentHandler > SAL_CALL SAXEventKeeperImpl::setNextHandler(
1095 	const cssu::Reference< cssxs::XDocumentHandler >& xNewHandler )
1096 	throw (cssu::RuntimeException)
1097 {
1098 	cssu::Reference< cssxs::XDocumentHandler > xOldHandler = m_xNextHandler;
1099 
1100 	m_xNextHandler = xNewHandler;
1101 	return xOldHandler;
1102 }
1103 
1104 rtl::OUString SAL_CALL SAXEventKeeperImpl::printBufferNodeTree()
1105 	throw (cssu::RuntimeException)
1106 {
1107 	rtl::OUString rc;
1108 
1109 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ElementMarkBuffers: size = " ));
1110 	rc += rtl::OUString::valueOf((sal_Int32)m_vElementMarkBuffers.size());
1111 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "\nCurrentBufferNode: " ));
1112 	rc += m_xXMLDocument->getNodeName(m_pCurrentBufferNode->getXMLElement());
1113 	rc += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "\n" ));
1114 	rc += printBufferNode(m_pRootBufferNode, 0);
1115 
1116 	return rc;
1117 }
1118 
1119 cssu::Reference< cssxw::XXMLElementWrapper > SAL_CALL SAXEventKeeperImpl::getCurrentBlockingNode()
1120 	throw (cssu::RuntimeException)
1121 {
1122 	cssu::Reference< cssxw::XXMLElementWrapper > rc;
1123 
1124 	if (m_pCurrentBlockingBufferNode != NULL)
1125 	{
1126 		rc = m_pCurrentBlockingBufferNode->getXMLElement();
1127 	}
1128 
1129 	return rc;
1130 }
1131 
1132 /* XSecuritySAXEventKeeper */
1133 sal_Int32 SAL_CALL SAXEventKeeperImpl::addSecurityElementCollector(
1134 	cssxc::sax::ElementMarkPriority priority,
1135 	sal_Bool modifyElement )
1136 	throw (cssu::RuntimeException)
1137 {
1138 	return createElementCollector(
1139 		cssxc::sax::ConstOfSecurityId::UNDEFINEDSECURITYID,
1140 		priority,
1141 		modifyElement,
1142 		NULL);
1143 }
1144 
1145 sal_Int32 SAL_CALL SAXEventKeeperImpl::cloneElementCollector(
1146 	sal_Int32 referenceId,
1147 	cssxc::sax::ElementMarkPriority priority )
1148 	throw (cssu::RuntimeException)
1149 {
1150 	sal_Int32 nId = -1;
1151 
1152 	ElementCollector* pElementCollector = (ElementCollector*)findElementMarkBuffer(referenceId);
1153 	if (pElementCollector != NULL)
1154 	{
1155 		nId = m_nNextElementMarkId;
1156 		m_nNextElementMarkId ++;
1157 
1158 		ElementCollector* pClonedOne
1159 			= pElementCollector->clone(nId, priority);
1160 
1161 	        /*
1162 	         * add this EC into the security data buffer array.
1163 	         */
1164 		m_vElementMarkBuffers.push_back(pClonedOne);
1165 
1166 	        /*
1167 	         * If the reference EC is still in initial EC array, add
1168 	         * this cloned one into the initial EC array too.
1169 	         */
1170 	        if (pElementCollector->getBufferNode() == NULL)
1171 		{
1172 			m_vNewElementCollectors.push_back(pClonedOne);
1173 		}
1174 	}
1175 
1176 	return nId;
1177 }
1178 
1179 void SAL_CALL SAXEventKeeperImpl::setSecurityId( sal_Int32 id, sal_Int32 securityId )
1180 	throw (cssu::RuntimeException)
1181 {
1182 	ElementMark* pElementMark = findElementMarkBuffer(id);
1183 	if (pElementMark != NULL)
1184 	{
1185 		pElementMark->setSecurityId(securityId);
1186 	}
1187 }
1188 
1189 
1190 /* XReferenceResolvedBroadcaster */
1191 void SAL_CALL SAXEventKeeperImpl::addReferenceResolvedListener(
1192 	sal_Int32 referenceId,
1193 	const cssu::Reference< cssxc::sax::XReferenceResolvedListener >& listener )
1194 	throw (cssu::RuntimeException)
1195 {
1196 	ElementCollector* pElementCollector = (ElementCollector*)findElementMarkBuffer(referenceId);
1197 	if (pElementCollector != NULL)
1198 	{
1199 		pElementCollector->setReferenceResolvedListener(listener);
1200 	}
1201 }
1202 
1203 void SAL_CALL SAXEventKeeperImpl::removeReferenceResolvedListener(
1204 	sal_Int32 /*referenceId*/,
1205 	const cssu::Reference< cssxc::sax::XReferenceResolvedListener >&)
1206 	throw (cssu::RuntimeException)
1207 {
1208 }
1209 
1210 /* XSAXEventKeeperStatusChangeBroadcaster */
1211 void SAL_CALL SAXEventKeeperImpl::addSAXEventKeeperStatusChangeListener(
1212 	const cssu::Reference< cssxc::sax::XSAXEventKeeperStatusChangeListener >& listener )
1213 	throw (cssu::RuntimeException)
1214 {
1215 	m_xSAXEventKeeperStatusChangeListener = listener;
1216 }
1217 
1218 void SAL_CALL SAXEventKeeperImpl::removeSAXEventKeeperStatusChangeListener(
1219 	const cssu::Reference< cssxc::sax::XSAXEventKeeperStatusChangeListener >&)
1220 	throw (cssu::RuntimeException)
1221 {
1222 }
1223 
1224 /* XDocumentHandler */
1225 void SAL_CALL SAXEventKeeperImpl::startDocument(  )
1226 	throw (cssxs::SAXException, cssu::RuntimeException)
1227 {
1228 	if ( m_xNextHandler.is())
1229 	{
1230 		m_xNextHandler->startDocument();
1231 	}
1232 }
1233 
1234 void SAL_CALL SAXEventKeeperImpl::endDocument(  )
1235 	throw (cssxs::SAXException, cssu::RuntimeException)
1236 {
1237 	if ( m_xNextHandler.is())
1238 	{
1239 		m_xNextHandler->endDocument();
1240 	}
1241 }
1242 
1243 void SAL_CALL SAXEventKeeperImpl::startElement(
1244 	const rtl::OUString& aName,
1245 	const cssu::Reference< cssxs::XAttributeList >& xAttribs )
1246 	throw (cssxs::SAXException, cssu::RuntimeException)
1247 {
1248         /*
1249          * If there is a following handler and no blocking now, then
1250          * forward this event
1251          */
1252 	if ((m_pCurrentBlockingBufferNode == NULL) &&
1253 	    (m_xNextHandler.is()) &&
1254 	    (!m_bIsForwarding) &&
1255 	    (m_pNewBlocker == NULL))
1256 	{
1257 		m_xNextHandler->startElement(aName, xAttribs);
1258 	}
1259 
1260         /*
1261          * If not forwarding, buffer this startElement.
1262          */
1263        	if (!m_bIsForwarding)
1264        	{
1265 	#ifndef _USECOMPRESSEDDOCUMENTHANDLER
1266 		m_xDocumentHandler->startElement(aName, xAttribs);
1267 	#else
1268 		sal_Int32 nLength = xAttribs->getLength();
1269 		cssu::Sequence< cssxcsax::XMLAttribute > aAttributes (nLength);
1270 
1271 		for ( int i = 0; i<nLength; ++i )
1272 		{
1273 			aAttributes[i].sName = xAttribs->getNameByIndex((short)i);
1274 			aAttributes[i].sValue =xAttribs->getValueByIndex((short)i);
1275 		}
1276 
1277 		m_xCompressedDocumentHandler->_startElement(aName, aAttributes);
1278 	#endif
1279 
1280 	}
1281 
1282 	BufferNode* pBufferNode = addNewElementMarkBuffers();
1283         if (pBufferNode != NULL)
1284         {
1285 		setCurrentBufferNode(pBufferNode);
1286 	}
1287 }
1288 
1289 void SAL_CALL SAXEventKeeperImpl::endElement( const rtl::OUString& aName )
1290 	throw (cssxs::SAXException, cssu::RuntimeException)
1291 {
1292         sal_Bool bIsCurrent = m_xXMLDocument->isCurrent(m_pCurrentBufferNode->getXMLElement());
1293 
1294         /*
1295          * If there is a following handler and no blocking now, then
1296          * forward this event
1297          */
1298 	if ((m_pCurrentBlockingBufferNode == NULL) &&
1299 	    (m_xNextHandler.is()) &&
1300 	    (!m_bIsForwarding))
1301 	{
1302 		m_xNextHandler->endElement(aName);
1303 	}
1304 
1305 	if ((m_pCurrentBlockingBufferNode != NULL) ||
1306 	    (m_pCurrentBufferNode != m_pRootBufferNode) ||
1307 	    (!m_xXMLDocument->isCurrentElementEmpty()))
1308 	{
1309         	if (!m_bIsForwarding)
1310         	{
1311 		#ifndef _USECOMPRESSEDDOCUMENTHANDLER
1312 			m_xDocumentHandler->endElement(aName);
1313 		#else
1314 			m_xCompressedDocumentHandler->_endElement(aName);
1315 		#endif
1316 		}
1317 
1318         /*
1319         * If the current buffer node has not notified yet, and
1320         * the current buffer node is waiting for the current element,
1321         * then let it notify.
1322         */
1323        	if (bIsCurrent && (m_pCurrentBufferNode != m_pRootBufferNode))
1324 		{
1325 			BufferNode* pOldCurrentBufferNode = m_pCurrentBufferNode;
1326 			m_pCurrentBufferNode = (BufferNode*)m_pCurrentBufferNode->getParent();
1327 
1328 			pOldCurrentBufferNode->setReceivedAll();
1329 
1330 			if ((m_pCurrentBufferNode == m_pRootBufferNode) &&
1331 			    m_xSAXEventKeeperStatusChangeListener.is())
1332 			{
1333 				m_xSAXEventKeeperStatusChangeListener->collectionStatusChanged(sal_False);
1334 			}
1335 		}
1336     }
1337     else
1338     {
1339         if (!m_bIsForwarding)
1340         {
1341             m_xXMLDocument->removeCurrentElement();
1342         }
1343     }
1344 }
1345 
1346 void SAL_CALL SAXEventKeeperImpl::characters( const rtl::OUString& aChars )
1347 	throw (cssxs::SAXException, cssu::RuntimeException)
1348 {
1349 	if (!m_bIsForwarding)
1350 	{
1351 		if ((m_pCurrentBlockingBufferNode == NULL) && m_xNextHandler.is())
1352 		{
1353 			m_xNextHandler->characters(aChars);
1354 		}
1355 
1356 		if ((m_pCurrentBlockingBufferNode != NULL) ||
1357 		    (m_pCurrentBufferNode != m_pRootBufferNode))
1358 		{
1359 		#ifndef _USECOMPRESSEDDOCUMENTHANDLER
1360         		m_xDocumentHandler->characters(aChars);
1361 		#else
1362 			m_xCompressedDocumentHandler->_characters(aChars);
1363 		#endif
1364         	}
1365         }
1366 }
1367 
1368 void SAL_CALL SAXEventKeeperImpl::ignorableWhitespace( const rtl::OUString& aWhitespaces )
1369 	throw (cssxs::SAXException, cssu::RuntimeException)
1370 {
1371 	characters( aWhitespaces );
1372 }
1373 
1374 void SAL_CALL SAXEventKeeperImpl::processingInstruction(
1375 	const rtl::OUString& aTarget, const rtl::OUString& aData )
1376 	throw (cssxs::SAXException, cssu::RuntimeException)
1377 {
1378 	if (!m_bIsForwarding)
1379 	{
1380 		if ((m_pCurrentBlockingBufferNode == NULL) && m_xNextHandler.is())
1381 		{
1382 			m_xNextHandler->processingInstruction(aTarget, aData);
1383 		}
1384 
1385 		if ((m_pCurrentBlockingBufferNode != NULL) ||
1386 		    (m_pCurrentBufferNode != m_pRootBufferNode))
1387 		{
1388 		#ifndef _USECOMPRESSEDDOCUMENTHANDLER
1389 			m_xDocumentHandler->processingInstruction(aTarget, aData);
1390 		#else
1391 			m_xCompressedDocumentHandler->_processingInstruction(aTarget, aData);
1392 		#endif
1393         	}
1394         }
1395 }
1396 
1397 void SAL_CALL SAXEventKeeperImpl::setDocumentLocator( const cssu::Reference< cssxs::XLocator >&)
1398 	throw (cssxs::SAXException, cssu::RuntimeException)
1399 {
1400 }
1401 
1402 /* XInitialization */
1403 void SAL_CALL SAXEventKeeperImpl::initialize( const cssu::Sequence< cssu::Any >& aArguments )
1404 	throw (cssu::Exception, cssu::RuntimeException)
1405 {
1406 	OSL_ASSERT(aArguments.getLength() == 1);
1407 
1408 	aArguments[0] >>= m_xXMLDocument;
1409 	m_xDocumentHandler = cssu::Reference< cssxs::XDocumentHandler >(
1410 		m_xXMLDocument, cssu::UNO_QUERY );
1411 	m_xCompressedDocumentHandler = cssu::Reference< cssxcsax::XCompressedDocumentHandler >(
1412 		m_xXMLDocument, cssu::UNO_QUERY );
1413 
1414 	m_pRootBufferNode = new BufferNode(m_xXMLDocument->getCurrentElement());
1415 	m_pCurrentBufferNode = m_pRootBufferNode;
1416 }
1417 
1418 rtl::OUString SAXEventKeeperImpl_getImplementationName ()
1419 	throw (cssu::RuntimeException)
1420 {
1421 	return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) );
1422 }
1423 
1424 sal_Bool SAL_CALL SAXEventKeeperImpl_supportsService( const rtl::OUString& ServiceName )
1425 	throw (cssu::RuntimeException)
1426 {
1427 	return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ));
1428 }
1429 
1430 cssu::Sequence< rtl::OUString > SAL_CALL SAXEventKeeperImpl_getSupportedServiceNames(  )
1431 	throw (cssu::RuntimeException)
1432 {
1433 	cssu::Sequence < rtl::OUString > aRet(1);
1434 	rtl::OUString* pArray = aRet.getArray();
1435 	pArray[0] =  rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) );
1436 	return aRet;
1437 }
1438 #undef SERVICE_NAME
1439 
1440 cssu::Reference< cssu::XInterface > SAL_CALL SAXEventKeeperImpl_createInstance(
1441 	const cssu::Reference< cssl::XMultiServiceFactory > &)
1442 	throw( cssu::Exception )
1443 {
1444 	return (cppu::OWeakObject*) new SAXEventKeeperImpl();
1445 }
1446 
1447 /* XServiceInfo */
1448 rtl::OUString SAL_CALL SAXEventKeeperImpl::getImplementationName(  )
1449 	throw (cssu::RuntimeException)
1450 {
1451 	return SAXEventKeeperImpl_getImplementationName();
1452 }
1453 sal_Bool SAL_CALL SAXEventKeeperImpl::supportsService( const rtl::OUString& rServiceName )
1454 	throw (cssu::RuntimeException)
1455 {
1456 	return SAXEventKeeperImpl_supportsService( rServiceName );
1457 }
1458 cssu::Sequence< rtl::OUString > SAL_CALL SAXEventKeeperImpl::getSupportedServiceNames(  )
1459 	throw (cssu::RuntimeException)
1460 {
1461 	return SAXEventKeeperImpl_getSupportedServiceNames();
1462 }
1463 
1464