xref: /aoo41x/main/sax/source/expatwrap/saxwriter.cxx (revision cdf0e10c)
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 #include <string.h>
28 
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/util/XCloneable.hpp>
31 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
32 #include <com/sun/star/xml/sax/XParser.hpp>
33 #include <com/sun/star/xml/sax/SAXParseException.hpp>
34 #include <com/sun/star/xml/sax/SAXInvalidCharacterException.hpp>
35 
36 #include <com/sun/star/io/XActiveDataSource.hpp>
37 
38 #include <cppuhelper/factory.hxx>
39 #include <cppuhelper/weak.hxx>
40 #include <cppuhelper/implbase3.hxx>
41 
42 #include <rtl/strbuf.hxx>
43 #include <rtl/byteseq.hxx>
44 #include <rtl/ustrbuf.hxx>
45 
46 using namespace ::rtl;
47 using namespace ::std;
48 using namespace ::osl;
49 using namespace ::cppu;
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::registry;
53 using namespace ::com::sun::star::xml::sax;
54 using namespace ::com::sun::star::util;
55 using namespace ::com::sun::star::io;
56 
57 #include "factory.hxx"
58 #include "xml2utf.hxx"
59 
60 #define LINEFEED 10
61 #define SEQUENCESIZE 1024
62 #define MAXCOLUMNCOUNT 72
63 
64 /******
65 *
66 *
67 * Character conversion functions
68 *
69 *
70 *****/
71 
72 namespace sax_expatwrap {
73 /*****
74 *
75 * Calculates the length of the sequence after conversion, but the conversion is not done.
76 * .g. &<>"' plus some more are
77 * special characters in XML that need to be transformed
78 *
79 * @param bConvertAll For Attributes it is necessary to convert every symbol (including line feed and tab)
80 *                    Set this to true, if you want to perform this special conversion
81 * @return The returned value is equal to the length of the incoming sequence, when no
82 +         conversion is necessary, otherwise it is larger than the length of the sequence.
83 ****/
84 //  inline sal_Int32 CalcXMLLen( const Sequence<sal_Int8> & seq , sal_Bool bConvertAll ) throw()
85 //  {
86 //  	sal_Int32 nLen = 0;
87 //  	const sal_Int8 *pArray = seq.getConstArray();
88 
89 //  	for( int i = 0 ; i < seq.getLength() ; i ++ ) {
90 
91 //  		sal_Int8 c = pArray[i];
92 //  		switch( c )
93 //  		{
94 //  		case '&':       // resemble to &amp;
95 //  			nLen +=5;
96 //  			break;
97 //  		case '<':       // &lt;
98 //  		case '>':       // &gt;
99 //  			nLen +=4;
100 //  			break;
101 //  		case 39:        // 39 == ''', &apos;
102 //  		case '"':       // &quot;
103 //  		case 13:        // &#x0d;
104 //  			nLen += 6;
105 //  			break;
106 
107 //  		case 10:        // &#x0a;
108 //  		case 9:         // &#x09;
109 //  			if( bConvertAll )
110 //  			{
111 //  				nLen += 6;		  //
112 //  			}
113 //  			break;
114 //  		default:
115 //  			nLen ++;
116 //  		}
117 //  	}
118 
119 //  	return nLen;
120 //  }
121 
122 enum SaxInvalidCharacterError
123 {
124 	SAX_NONE,
125 	SAX_WARNING,
126 	SAX_ERROR
127 };
128 
129 class SaxWriterHelper
130 {
131 	Reference< XOutputStream >	m_out;
132 	Sequence < sal_Int8 >		m_Sequence;
133 	sal_Int8*					mp_Sequence;
134 
135 	sal_Int32					nLastLineFeedPos; // is negative after writing a sequence
136 	sal_uInt32					nCurrentPos;
137 	sal_Bool					m_bStartElementFinished;
138 
139 
140 	inline sal_uInt32 writeSequence() throw( SAXException );
141 
142 	// use only if to insert the bytes more space in the sequence is needed and
143 	// so the sequence has to write out and reset rPos to 0
144 	// writes sequence only on overflow, sequence could be full on the end (rPos == SEQUENCESIZE)
145 	inline void AddBytes(sal_Int8* pTarget, sal_uInt32& rPos,
146 				const sal_Int8* pBytes, sal_uInt32 nBytesCount) throw( SAXException );
147 	inline sal_Bool convertToXML(const sal_Unicode * pStr,
148 						sal_Int32 nStrLen,
149 						sal_Bool bDoNormalization,
150 						sal_Bool bNormalizeWhitespace,
151 						sal_Int8 *pTarget,
152 						sal_uInt32& rPos) throw( SAXException );
153 	inline void FinishStartElement() throw( SAXException );
154 public:
155 	SaxWriterHelper(Reference< XOutputStream > m_TempOut) :
156 		m_out(m_TempOut),
157 		m_Sequence(SEQUENCESIZE),
158 		mp_Sequence(NULL),
159 		nLastLineFeedPos(0),
160 		nCurrentPos(0),
161 		m_bStartElementFinished(sal_True)
162 	{
163 		OSL_ENSURE(SEQUENCESIZE > 50, "Sequence cache size to small");
164 		mp_Sequence = m_Sequence.getArray();
165 	}
166 	~SaxWriterHelper()
167 	{
168 		OSL_ENSURE(!nCurrentPos, "cached Sequence not written");
169 		OSL_ENSURE(m_bStartElementFinished, "StartElement not complettly written");
170 	}
171 
172 	inline void insertIndentation(sal_uInt32 m_nLevel)  throw( SAXException );
173 
174 // returns whether it works correct or invalid characters were in the string
175 // If there are invalid characters in the string it returns sal_False.
176 // Than the calling method has to throw the needed Exception.
177 	inline sal_Bool writeString(const rtl::OUString& rWriteOutString,
178 						sal_Bool bDoNormalization,
179 						sal_Bool bNormalizeWhitespace) throw( SAXException );
180 
181 	sal_uInt32 GetLastColumnCount() { return (sal_uInt32)(nCurrentPos - nLastLineFeedPos); }
182 
183 	inline void startDocument() throw( SAXException );
184 
185 // returns whether it works correct or invalid characters were in the strings
186 // If there are invalid characters in one of the strings it returns sal_False.
187 // Than the calling method has to throw the needed Exception.
188 	inline SaxInvalidCharacterError startElement(const rtl::OUString& rName, const Reference< XAttributeList >& xAttribs) throw( SAXException );
189 	inline sal_Bool FinishEmptyElement() throw( SAXException );
190 
191 // returns whether it works correct or invalid characters were in the string
192 // If there are invalid characters in the string it returns sal_False.
193 // Than the calling method has to throw the needed Exception.
194 	inline sal_Bool endElement(const rtl::OUString& rName) throw( SAXException );
195 	inline void endDocument() throw( SAXException );
196 
197 // returns whether it works correct or invalid characters were in the strings
198 // If there are invalid characters in the string it returns sal_False.
199 // Than the calling method has to throw the needed Exception.
200 	inline sal_Bool processingInstruction(const rtl::OUString& rTarget, const rtl::OUString& rData) throw( SAXException );
201 	inline void startCDATA() throw( SAXException );
202 	inline void endCDATA() throw( SAXException );
203 
204 // returns whether it works correct or invalid characters were in the strings
205 // If there are invalid characters in the string it returns sal_False.
206 // Than the calling method has to throw the needed Exception.
207 	inline sal_Bool comment(const rtl::OUString& rComment) throw( SAXException );
208 
209 	inline void clearBuffer() throw( SAXException );
210 };
211 
212 const sal_Bool g_bValidCharsBelow32[32] =
213 {
214 //  0 1 2 3 4 5 6 7
215 	0,0,0,0,0,0,0,0,  //0
216 	0,1,1,0,0,1,0,0,  //8
217 	0,0,0,0,0,0,0,0,  //16
218 	0,0,0,0,0,0,0,0
219 };
220 
221 inline sal_Bool IsInvalidChar(const sal_Unicode aChar)
222 {
223 	sal_Bool bRet(sal_False);
224 	// check first for the most common characters
225 	if( aChar < 32 || aChar >= 0xd800 )
226 		bRet = ( (aChar < 32 && ! g_bValidCharsBelow32[aChar]) ||
227 			aChar == 0xffff ||
228 			aChar == 0xfffe );
229 	return bRet;
230 }
231 
232 /********
233 * write through to the output stream
234 *
235 *****/
236 inline sal_uInt32 SaxWriterHelper::writeSequence() throw( SAXException )
237 {
238 	try
239 	{
240 		m_out->writeBytes( m_Sequence );
241 	}
242 	catch( IOException & e )
243 	{
244 		Any a;
245 		a <<= e;
246 		throw SAXException(
247 			OUString::createFromAscii( "io exception during writing" ),
248 			Reference< XInterface > (),
249 			a );
250 	}
251 	nLastLineFeedPos -= SEQUENCESIZE;
252 	return 0;
253 }
254 
255 inline void SaxWriterHelper::AddBytes(sal_Int8* pTarget, sal_uInt32& rPos,
256 				const sal_Int8* pBytes, sal_uInt32 nBytesCount) throw( SAXException )
257 {
258 	OSL_ENSURE((rPos + nBytesCount) > SEQUENCESIZE, "wrong use of AddBytesMethod");
259 	sal_uInt32 nCount(SEQUENCESIZE - rPos);
260 	memcpy( &(pTarget[rPos]) , pBytes,  nCount);
261 
262 	OSL_ENSURE(rPos + nCount == SEQUENCESIZE, "the position should be the at the end");
263 
264 	rPos = writeSequence();
265 	sal_uInt32 nRestCount(nBytesCount - nCount);
266 	if ((rPos + nRestCount) <= SEQUENCESIZE)
267 	{
268 		memcpy( &(pTarget[rPos]), &pBytes[nCount], nRestCount);
269 		rPos += nRestCount;
270 	}
271 	else
272 		AddBytes(pTarget, rPos, &pBytes[nCount], nRestCount);
273 }
274 
275 /** Converts an UTF16 string to UTF8 and does XML normalization
276 
277 	@param pTarget
278 	       Pointer to a piece of memory, to where the output should be written. The caller
279 		   must call calcXMLByteLength on the same string, to ensure,
280 		   that there is enough memory for converting.
281  */
282 inline sal_Bool SaxWriterHelper::convertToXML( const sal_Unicode * pStr,
283 						sal_Int32 nStrLen,
284 						sal_Bool bDoNormalization,
285 						sal_Bool bNormalizeWhitespace,
286 						sal_Int8 *pTarget,
287 						sal_uInt32& rPos ) throw( SAXException )
288 {
289 	sal_Bool bRet(sal_True);
290     sal_uInt32 nSurrogate = 0;
291 
292 	for( sal_Int32 i = 0 ; i < nStrLen ; i ++ )
293 	{
294 	    sal_uInt16 c = pStr[i];
295 	    if (IsInvalidChar(c))
296 	    	bRet = sal_False;
297 	    else if( (c >= 0x0001) && (c <= 0x007F) )
298 		{
299 			if( bDoNormalization )
300 			{
301 				switch( c )
302 				{
303 					case '&':  // resemble to &amp;
304 					{
305 						if ((rPos + 5) > SEQUENCESIZE)
306 							AddBytes(pTarget, rPos, (sal_Int8*)"&amp;", 5);
307 						else
308 						{
309 							memcpy( &(pTarget[rPos]) , "&amp;", 5 );
310 							rPos += 5;
311 						}
312 					}
313 					break;
314 					case '<':
315 					{
316 						if ((rPos + 4) > SEQUENCESIZE)
317 							AddBytes(pTarget, rPos, (sal_Int8*)"&lt;", 4);
318 						else
319 						{
320 							memcpy( &(pTarget[rPos]) , "&lt;" , 4 );
321 							rPos += 4;        // &lt;
322 						}
323 					}
324 					break;
325 					case '>':
326 					{
327 						if ((rPos + 4) > SEQUENCESIZE)
328 							AddBytes(pTarget, rPos, (sal_Int8*)"&gt;", 4);
329 						else
330 						{
331 							memcpy( &(pTarget[rPos]) , "&gt;" , 4 );
332 							rPos += 4;        // &gt;
333 						}
334 					}
335 					break;
336 					case 39:                 // 39 == '''
337 					{
338 						if ((rPos + 6) > SEQUENCESIZE)
339 							AddBytes(pTarget, rPos, (sal_Int8*)"&apos;", 6);
340 						else
341 						{
342 							memcpy( &(pTarget[rPos]) , "&apos;" , 6 );
343 							rPos += 6;        // &apos;
344 						}
345 					}
346 					break;
347 					case '"':
348 					{
349 						if ((rPos + 6) > SEQUENCESIZE)
350 							AddBytes(pTarget, rPos, (sal_Int8*)"&quot;", 6);
351 						else
352 						{
353 							memcpy( &(pTarget[rPos]) , "&quot;" , 6 );
354 							rPos += 6;		  // &quot;
355 						}
356 					}
357 					break;
358 					case 13:
359 					{
360 						if ((rPos + 6) > SEQUENCESIZE)
361 							AddBytes(pTarget, rPos, (sal_Int8*)"&#x0d;", 6);
362 						else
363 						{
364 							memcpy( &(pTarget[rPos]) , "&#x0d;" , 6 );
365 							rPos += 6;
366 						}
367 					}
368 					break;
369 					case LINEFEED:
370 					{
371 						if( bNormalizeWhitespace )
372 						{
373 							if ((rPos + 6) > SEQUENCESIZE)
374 								AddBytes(pTarget, rPos, (sal_Int8*)"&#x0a;" , 6);
375 							else
376 							{
377 								memcpy( &(pTarget[rPos]) , "&#x0a;" , 6 );
378 								rPos += 6;
379 							}
380 						}
381 						else
382 						{
383 							pTarget[rPos] = LINEFEED;
384 							nLastLineFeedPos = rPos;
385 							rPos ++;
386 						}
387 					}
388 					break;
389 					case 9:
390 					{
391 						if( bNormalizeWhitespace )
392 						{
393 							if ((rPos + 6) > SEQUENCESIZE)
394 								AddBytes(pTarget, rPos, (sal_Int8*)"&#x09;" , 6);
395 							else
396 							{
397 								memcpy( &(pTarget[rPos]) , "&#x09;" , 6 );
398 								rPos += 6;
399 							}
400 						}
401 						else
402 						{
403 							pTarget[rPos] = 9;
404 							rPos ++;
405 						}
406 					}
407 					break;
408 					default:
409 					{
410 						pTarget[rPos] = (sal_Int8)c;
411 						rPos ++;
412 					}
413 					break;
414 				}
415 			}
416 			else
417 			{
418 				pTarget[rPos] = (sal_Int8)c;
419 				if ((sal_Int8)c == LINEFEED)
420 					nLastLineFeedPos = rPos;
421 				rPos ++;
422 			}
423 	    }
424         else if( c >= 0xd800 && c < 0xdc00  )
425         {
426             // 1. surrogate: save (until 2. surrogate)
427             OSL_ENSURE( nSurrogate == 0, "left-over Unicode surrogate" );
428             nSurrogate = ( ( c & 0x03ff ) + 0x0040 );
429         }
430         else if( c >= 0xdc00 && c < 0xe000 )
431         {
432             // 2. surrogate: write as UTF-8
433             OSL_ENSURE( nSurrogate != 0, "lone 2nd Unicode surrogate" );
434 
435             nSurrogate = ( nSurrogate << 10 ) | ( c & 0x03ff );
436             if( nSurrogate >= 0x00010000  &&  nSurrogate <= 0x0010FFFF )
437             {
438     			sal_Int8 aBytes[] = { sal_Int8(0xF0 | ((nSurrogate >> 18) & 0x0F)),
439 	    							  sal_Int8(0x80 | ((nSurrogate >> 12) & 0x3F)),
440 		    						  sal_Int8(0x80 | ((nSurrogate >>  6) & 0x3F)),
441 			    					  sal_Int8(0x80 | ((nSurrogate >>  0) & 0x3F)) };
442     			if ((rPos + 4) > SEQUENCESIZE)
443 	    			AddBytes(pTarget, rPos, aBytes, 4);
444 		    	else
445 			    {
446 				    pTarget[rPos] = aBytes[0];
447     				rPos ++;
448 	    			pTarget[rPos] = aBytes[1];
449 		    		rPos ++;
450 			    	pTarget[rPos] = aBytes[2];
451 				    rPos ++;
452     				pTarget[rPos] = aBytes[3];
453 	    			rPos ++;
454 		    	}
455             }
456             else
457             {
458                 OSL_ENSURE( false, "illegal Unicode character" );
459                 bRet = sal_False;
460             }
461 
462             // reset surrogate
463             nSurrogate = 0;
464         }
465 		else if( c > 0x07FF )
466 		{
467 			sal_Int8 aBytes[] = { sal_Int8(0xE0 | ((c >> 12) & 0x0F)),
468 								  sal_Int8(0x80 | ((c >>  6) & 0x3F)),
469 								  sal_Int8(0x80 | ((c >>  0) & 0x3F)) };
470 			if ((rPos + 3) > SEQUENCESIZE)
471 				AddBytes(pTarget, rPos, aBytes, 3);
472 			else
473 			{
474 				pTarget[rPos] = aBytes[0];
475 				rPos ++;
476 				pTarget[rPos] = aBytes[1];
477 				rPos ++;
478 				pTarget[rPos] = aBytes[2];
479 				rPos ++;
480 			}
481 	    }
482 		else
483 		{
484 			sal_Int8 aBytes[] = { sal_Int8(0xC0 | ((c >>  6) & 0x1F)),
485 								sal_Int8(0x80 | ((c >>  0) & 0x3F)) };
486 			if ((rPos + 2) > SEQUENCESIZE)
487 				AddBytes(pTarget, rPos, aBytes, 2);
488 			else
489 			{
490 				pTarget[rPos] = aBytes[0];
491 				rPos ++;
492 				pTarget[rPos] = aBytes[1];
493 				rPos ++;
494 			}
495 		}
496 		OSL_ENSURE(rPos <= SEQUENCESIZE, "not reset current position");
497 		if (rPos == SEQUENCESIZE)
498 			rPos = writeSequence();
499 
500         // reset left-over surrogate
501         if( ( nSurrogate != 0 ) && !( c >= 0xd800 && c < 0xdc00 ) )
502         {
503             OSL_ENSURE( nSurrogate != 0, "left-over Unicode surrogate" );
504             nSurrogate = 0;
505             bRet = sal_False;
506         }
507     }
508 	return bRet;
509 }
510 
511 inline void SaxWriterHelper::FinishStartElement() throw( SAXException )
512 {
513 	if (!m_bStartElementFinished)
514 	{
515 		mp_Sequence[nCurrentPos] = '>';
516 		nCurrentPos++;
517 		if (nCurrentPos == SEQUENCESIZE)
518 			nCurrentPos = writeSequence();
519 		m_bStartElementFinished = sal_True;
520 	}
521 }
522 
523 inline void SaxWriterHelper::insertIndentation(sal_uInt32 m_nLevel) throw( SAXException )
524 {
525 	FinishStartElement();
526 	if (m_nLevel > 0)
527 	{
528 		if ((nCurrentPos + m_nLevel + 1) <= SEQUENCESIZE)
529 		{
530 			mp_Sequence[nCurrentPos] = LINEFEED;
531 			nLastLineFeedPos = nCurrentPos;
532 			nCurrentPos++;
533 			memset( &(mp_Sequence[nCurrentPos]) , 32 , m_nLevel );
534 			nCurrentPos += m_nLevel;
535 			if (nCurrentPos == SEQUENCESIZE)
536 				nCurrentPos = writeSequence();
537 		}
538 		else
539 		{
540 			sal_uInt32 nCount(m_nLevel + 1);
541 			sal_Int8* pBytes = new sal_Int8[nCount];
542 			pBytes[0] = LINEFEED;
543 			memset( &(pBytes[1]), 32, m_nLevel );
544 			AddBytes(mp_Sequence, nCurrentPos, pBytes, nCount);
545 			delete[] pBytes;
546 			nLastLineFeedPos = nCurrentPos - nCount;
547 			if (nCurrentPos == SEQUENCESIZE)
548 				nCurrentPos = writeSequence();
549 		}
550 	}
551 	else
552 	{
553 		mp_Sequence[nCurrentPos] = LINEFEED;
554 		nLastLineFeedPos = nCurrentPos;
555 		nCurrentPos++;
556 		if (nCurrentPos == SEQUENCESIZE)
557 			nCurrentPos = writeSequence();
558 	}
559 }
560 
561 inline sal_Bool SaxWriterHelper::writeString( const rtl::OUString& rWriteOutString,
562 						sal_Bool bDoNormalization,
563 						sal_Bool bNormalizeWhitespace ) throw( SAXException )
564 {
565 	FinishStartElement();
566 	return convertToXML(rWriteOutString.getStr(),
567 					rWriteOutString.getLength(),
568 					bDoNormalization,
569 					bNormalizeWhitespace,
570 					mp_Sequence,
571 					nCurrentPos);
572 }
573 
574 inline void SaxWriterHelper::startDocument() throw( SAXException )
575 {
576 	const char pc[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
577 	const int nLen = strlen( pc );
578 	if ((nCurrentPos + nLen) <= SEQUENCESIZE)
579 	{
580 		memcpy( mp_Sequence, pc , nLen );
581 		nCurrentPos += nLen;
582 	}
583 	else
584 	{
585 		AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)pc, nLen);
586 	}
587 	OSL_ENSURE(nCurrentPos <= SEQUENCESIZE, "not reset current position");
588 	if (nCurrentPos == SEQUENCESIZE)
589 		nCurrentPos = writeSequence();
590 	mp_Sequence[nCurrentPos] = LINEFEED;
591 	nCurrentPos++;
592 	if (nCurrentPos == SEQUENCESIZE)
593 		nCurrentPos = writeSequence();
594 }
595 
596 inline SaxInvalidCharacterError SaxWriterHelper::startElement(const rtl::OUString& rName, const Reference< XAttributeList >& xAttribs) throw( SAXException )
597 {
598 	FinishStartElement();
599 	mp_Sequence[nCurrentPos] = '<';
600 	nCurrentPos++;
601 	if (nCurrentPos == SEQUENCESIZE)
602 		nCurrentPos = writeSequence();
603 
604 	SaxInvalidCharacterError eRet(SAX_NONE);
605 	if (!writeString(rName, sal_False, sal_False))
606 		eRet = SAX_ERROR;
607 
608 	sal_Int16 nAttribCount = xAttribs.is() ? static_cast<sal_Int16>(xAttribs->getLength()) : 0;
609 	for(sal_Int16 i = 0 ; i < nAttribCount ; i++ )
610 	{
611 		mp_Sequence[nCurrentPos] = ' ';
612 		nCurrentPos++;
613 		if (nCurrentPos == SEQUENCESIZE)
614 			nCurrentPos = writeSequence();
615 
616 		if (!writeString(xAttribs->getNameByIndex( i ), sal_False, sal_False))
617 			eRet = SAX_ERROR;
618 
619 		mp_Sequence[nCurrentPos] = '=';
620 		nCurrentPos++;
621 		if (nCurrentPos == SEQUENCESIZE)
622 			nCurrentPos = writeSequence();
623 		mp_Sequence[nCurrentPos] = '"';
624 		nCurrentPos++;
625 		if (nCurrentPos == SEQUENCESIZE)
626 			nCurrentPos = writeSequence();
627 
628 		if (!writeString(xAttribs->getValueByIndex( i ), sal_True, sal_True) &&
629 			!(eRet == SAX_ERROR))
630 			eRet = SAX_WARNING;
631 
632 		mp_Sequence[nCurrentPos] = '"';
633 		nCurrentPos++;
634 		if (nCurrentPos == SEQUENCESIZE)
635 			nCurrentPos = writeSequence();
636 	}
637 
638 	m_bStartElementFinished = sal_False;	// because the '>' character is not added,
639 											// because it is possible, that the "/>"
640 											// characters have to add
641 	return eRet;
642 }
643 
644 inline sal_Bool SaxWriterHelper::FinishEmptyElement() throw( SAXException )
645 {
646 	if (m_bStartElementFinished)
647 		return sal_False;
648 
649 	mp_Sequence[nCurrentPos] = '/';
650 	nCurrentPos++;
651 	if (nCurrentPos == SEQUENCESIZE)
652 		nCurrentPos = writeSequence();
653 	mp_Sequence[nCurrentPos] = '>';
654 	nCurrentPos++;
655 	if (nCurrentPos == SEQUENCESIZE)
656 		nCurrentPos = writeSequence();
657 
658 	m_bStartElementFinished = sal_True;
659 
660 	return sal_True;
661 }
662 
663 inline sal_Bool SaxWriterHelper::endElement(const rtl::OUString& rName) throw( SAXException )
664 {
665 	FinishStartElement();
666 	mp_Sequence[nCurrentPos] = '<';
667 	nCurrentPos++;
668 	if (nCurrentPos == SEQUENCESIZE)
669 		nCurrentPos = writeSequence();
670 	mp_Sequence[nCurrentPos] = '/';
671 	nCurrentPos++;
672 	if (nCurrentPos == SEQUENCESIZE)
673 		nCurrentPos = writeSequence();
674 
675 	sal_Bool bRet(writeString( rName, sal_False, sal_False));
676 
677 	mp_Sequence[nCurrentPos] = '>';
678 	nCurrentPos++;
679 	if (nCurrentPos == SEQUENCESIZE)
680 		nCurrentPos = writeSequence();
681 
682 	return bRet;
683 }
684 
685 inline void SaxWriterHelper::endDocument() throw( SAXException )
686 {
687 	if (nCurrentPos > 0)
688 	{
689 		m_Sequence.realloc(nCurrentPos);
690 		nCurrentPos = writeSequence();
691 		//m_Sequence.realloc(SEQUENCESIZE);
692 	}
693 }
694 
695 inline void SaxWriterHelper::clearBuffer() throw( SAXException )
696 {
697     FinishStartElement();
698     if (nCurrentPos > 0)
699     {
700         m_Sequence.realloc(nCurrentPos);
701         nCurrentPos = writeSequence();
702         m_Sequence.realloc(SEQUENCESIZE);
703         // Be sure to update the array pointer after the reallocation.
704         mp_Sequence = m_Sequence.getArray();
705     }
706 }
707 
708 inline sal_Bool SaxWriterHelper::processingInstruction(const rtl::OUString& rTarget, const rtl::OUString& rData) throw( SAXException )
709 {
710 	FinishStartElement();
711 	mp_Sequence[nCurrentPos] = '<';
712 	nCurrentPos++;
713 	if (nCurrentPos == SEQUENCESIZE)
714 		nCurrentPos = writeSequence();
715 	mp_Sequence[nCurrentPos] = '?';
716 	nCurrentPos++;
717 	if (nCurrentPos == SEQUENCESIZE)
718 		nCurrentPos = writeSequence();
719 
720 	sal_Bool bRet(writeString( rTarget, sal_False, sal_False ));
721 
722 	mp_Sequence[nCurrentPos] = ' ';
723 	nCurrentPos++;
724 	if (nCurrentPos == SEQUENCESIZE)
725 		nCurrentPos = writeSequence();
726 
727 	if (!writeString( rData, sal_False, sal_False ))
728 		bRet = sal_False;
729 
730 	mp_Sequence[nCurrentPos] = '?';
731 	nCurrentPos++;
732 	if (nCurrentPos == SEQUENCESIZE)
733 		nCurrentPos = writeSequence();
734 	mp_Sequence[nCurrentPos] = '>';
735 	nCurrentPos++;
736 	if (nCurrentPos == SEQUENCESIZE)
737 		nCurrentPos = writeSequence();
738 
739 	return bRet;
740 }
741 
742 inline void SaxWriterHelper::startCDATA() throw( SAXException )
743 {
744 	FinishStartElement();
745 	if ((nCurrentPos + 9) <= SEQUENCESIZE)
746 	{
747 		memcpy( &(mp_Sequence[nCurrentPos]), "<![CDATA[" , 9 );
748 		nCurrentPos += 9;
749 	}
750 	else
751 		AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)"<![CDATA[" , 9);
752 	if (nCurrentPos == SEQUENCESIZE)
753 		nCurrentPos = writeSequence();
754 }
755 
756 inline void SaxWriterHelper::endCDATA() throw( SAXException )
757 {
758 	FinishStartElement();
759 	if ((nCurrentPos + 3) <= SEQUENCESIZE)
760 	{
761 		memcpy( &(mp_Sequence[nCurrentPos]), "]]>" , 3 );
762 		nCurrentPos += 3;
763 	}
764 	else
765 		AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)"]]>" , 3);
766 	if (nCurrentPos == SEQUENCESIZE)
767 		nCurrentPos = writeSequence();
768 }
769 
770 inline sal_Bool SaxWriterHelper::comment(const rtl::OUString& rComment) throw( SAXException )
771 {
772 	FinishStartElement();
773 	mp_Sequence[nCurrentPos] = '<';
774 	nCurrentPos++;
775 	if (nCurrentPos == SEQUENCESIZE)
776 		nCurrentPos = writeSequence();
777 	mp_Sequence[nCurrentPos] = '!';
778 	nCurrentPos++;
779 	if (nCurrentPos == SEQUENCESIZE)
780 		nCurrentPos = writeSequence();
781 	mp_Sequence[nCurrentPos] = '-';
782 	nCurrentPos++;
783 	if (nCurrentPos == SEQUENCESIZE)
784 		nCurrentPos = writeSequence();
785 	mp_Sequence[nCurrentPos] = '-';
786 	nCurrentPos++;
787 	if (nCurrentPos == SEQUENCESIZE)
788 		nCurrentPos = writeSequence();
789 
790 	sal_Bool bRet(writeString( rComment, sal_False, sal_False));
791 
792 	mp_Sequence[nCurrentPos] = '-';
793 	nCurrentPos++;
794 	if (nCurrentPos == SEQUENCESIZE)
795 		nCurrentPos = writeSequence();
796 	mp_Sequence[nCurrentPos] = '-';
797 	nCurrentPos++;
798 	if (nCurrentPos == SEQUENCESIZE)
799 		nCurrentPos = writeSequence();
800 	mp_Sequence[nCurrentPos] = '>';
801 	nCurrentPos++;
802 	if (nCurrentPos == SEQUENCESIZE)
803 		nCurrentPos = writeSequence();
804 
805 	return bRet;
806 }
807 
808 inline sal_Int32 calcXMLByteLength( const sal_Unicode *pStr, sal_Int32 nStrLen,
809 									sal_Bool bDoNormalization,
810 									sal_Bool bNormalizeWhitespace )
811 {
812 	sal_Int32 nOutputLength = 0;
813     sal_uInt32 nSurrogate = 0;
814 
815 	for( sal_Int32 i = 0 ; i < nStrLen ; i++ )
816 	{
817 	    sal_uInt16 c = pStr[i];
818 	    if( !IsInvalidChar(c) && (c >= 0x0001) && (c <= 0x007F) )
819 		{
820 			if( bDoNormalization )
821 			{
822 				switch( c )
823 				{
824 				case '&':       // resemble to &amp;
825 					nOutputLength +=5;
826 					break;
827 				case '<':       // &lt;
828 				case '>':       // &gt;
829 					nOutputLength +=4;
830 					break;
831 				case 39:        // 39 == ''', &apos;
832 				case '"':       // &quot;
833 				case 13:        // &#x0d;
834 					nOutputLength += 6;
835 					break;
836 
837 				case 10:        // &#x0a;
838 				case 9:         // &#x09;
839 					if( bNormalizeWhitespace )
840 					{
841 						nOutputLength += 6;		  //
842 					}
843 					else
844 					{
845 						nOutputLength ++;
846 					}
847 					break;
848 				default:
849 					nOutputLength ++;
850 				}
851 			}
852 			else
853 			{
854 				nOutputLength ++;
855 			}
856 	    }
857         else if( c >= 0xd800 && c < 0xdc00  )
858         {
859             // save surrogate
860             nSurrogate = ( ( c & 0x03ff ) + 0x0040 );
861         }
862         else if( c >= 0xdc00 && c < 0xe000 )
863         {
864             // 2. surrogate: write as UTF-8 (if range is OK
865             nSurrogate = ( nSurrogate << 10 ) | ( c & 0x03ff );
866             if( nSurrogate >= 0x00010000  &&  nSurrogate <= 0x0010FFFF )
867                 nOutputLength += 4;
868             nSurrogate = 0;
869         }
870 		else if( c > 0x07FF )
871 		{
872 			nOutputLength += 3;
873 	    }
874 		else
875 		{
876 			nOutputLength += 2;
877 	    }
878 
879         // surrogate processing
880         if( ( nSurrogate != 0 ) && !( c >= 0xd800 && c < 0xdc00 ) )
881             nSurrogate = 0;
882     }
883 
884 	return nOutputLength;
885 }
886 
887 /** returns position of first ascii 10 within the string, -1 when no 10 in string.
888  */
889 static inline sal_Int32 getFirstLineBreak( const OUString & str ) throw ()
890 {
891 	const sal_Unicode *pSource = str.getStr();
892 	sal_Int32 nLen  = str.getLength();
893 
894 	for( int n = 0; n < nLen ; n ++ )
895 	{
896 		if( LINEFEED == pSource[n] ) {
897 			return n;
898 		}
899 	}
900 	return -1;
901 }
902 
903 /** returns position of last ascii 10 within sequence, -1 when no 10 in string.
904  */
905 static inline sal_Int32 getLastLineBreak( const Sequence<sal_Int8>  & seq) throw ()
906 {
907 	const sal_Int8 *pSource = seq.getConstArray();
908 	sal_Int32 nLen  = seq.getLength();
909 
910 	for( int n = nLen-1; n >= 0 ; n -- )
911 	{
912 		if( LINEFEED == pSource[n] ) {
913 			return n;
914 		}
915 	}
916 	return -1;
917 }
918 
919 
920 class SAXWriter :
921 	public WeakImplHelper3<
922             XActiveDataSource,
923             XExtendedDocumentHandler,
924   	        XServiceInfo >
925 {
926 public:
927 	SAXWriter( ) :
928 		m_seqStartElement(),
929 		mp_SaxWriterHelper( NULL ),
930 		m_bForceLineBreak(sal_False),
931 		m_bAllowLineBreak(sal_False)
932 		{}
933 	~SAXWriter()
934 	{
935 		delete mp_SaxWriterHelper;
936 	}
937 
938 public: // XActiveDataSource
939     virtual void SAL_CALL setOutputStream(const Reference< XOutputStream > & aStream)
940 		throw (RuntimeException)
941     		{
942                 // temporary: set same stream again to clear buffer
943                 if ( m_out == aStream && mp_SaxWriterHelper && m_bDocStarted )
944                     mp_SaxWriterHelper->clearBuffer();
945                 else
946                 {
947 
948 				m_out = aStream;
949 				delete mp_SaxWriterHelper;
950 				mp_SaxWriterHelper = new SaxWriterHelper(m_out);
951 				m_bDocStarted = sal_False;
952 				m_nLevel = 0;
953 				m_bIsCDATA = sal_False;
954 
955                 }
956 			}
957     virtual Reference< XOutputStream >  SAL_CALL getOutputStream(void)
958 		throw(RuntimeException)
959     		{ return m_out; }
960 
961 public: // XDocumentHandler
962     virtual void SAL_CALL startDocument(void)
963 		throw(SAXException, RuntimeException);
964 
965     virtual void SAL_CALL endDocument(void)
966 		throw(SAXException, RuntimeException);
967 
968     virtual void SAL_CALL startElement(const OUString& aName,
969 									   const Reference< XAttributeList > & xAttribs)
970 		throw (SAXException, RuntimeException);
971 
972     virtual void SAL_CALL endElement(const OUString& aName)
973 		throw(SAXException, RuntimeException);
974 
975     virtual void SAL_CALL characters(const OUString& aChars)
976 		throw(SAXException, RuntimeException);
977 
978     virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces)
979 		throw(SAXException, RuntimeException);
980     virtual void SAL_CALL processingInstruction(const OUString& aTarget,
981 												const OUString& aData)
982 		throw(SAXException, RuntimeException);
983     virtual void SAL_CALL setDocumentLocator(const Reference< XLocator > & xLocator)
984 		throw(SAXException, RuntimeException);
985 
986 public: // XExtendedDocumentHandler
987     virtual void SAL_CALL startCDATA(void) throw(SAXException, RuntimeException);
988     virtual void SAL_CALL endCDATA(void) throw(RuntimeException);
989     virtual void SAL_CALL comment(const OUString& sComment)
990 		throw(SAXException, RuntimeException);
991     virtual void SAL_CALL unknown(const OUString& sString)
992 		throw(SAXException, RuntimeException);
993 	virtual void SAL_CALL allowLineBreak(void)
994 		throw(SAXException,RuntimeException);
995 
996 public: // XServiceInfo
997     OUString                     SAL_CALL getImplementationName() throw();
998     Sequence< OUString >         SAL_CALL getSupportedServiceNames(void) throw();
999     sal_Bool                    SAL_CALL supportsService(const OUString& ServiceName) throw();
1000 
1001 private:
1002 
1003 	void writeSequence( const Sequence<sal_Int8> & seq );
1004 	sal_Int32 getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurence ) throw();
1005 
1006 	Reference< XOutputStream > 	m_out;
1007 	Sequence < sal_Int8 > 		m_seqStartElement;
1008 	SaxWriterHelper*			mp_SaxWriterHelper;
1009 
1010 	// Status information
1011 	sal_Bool m_bDocStarted : 1;
1012 	sal_Bool m_bIsCDATA : 1;
1013 	sal_Bool m_bForceLineBreak : 1;
1014 	sal_Bool m_bAllowLineBreak : 1;
1015 	sal_Int32 m_nLevel;
1016 };
1017 
1018 
1019 //--------------------------------------
1020 // the extern interface
1021 //---------------------------------------
1022 Reference < XInterface > SAL_CALL SaxWriter_CreateInstance(
1023 	const Reference < XMultiServiceFactory >  &  )
1024 	throw (Exception)
1025 {
1026 	SAXWriter *p = new SAXWriter;
1027 	return Reference< XInterface > ( SAL_STATIC_CAST(OWeakObject *, p ) );
1028 }
1029 
1030 OUString SaxWriter_getServiceName() throw()
1031 {
1032 	return OUString::createFromAscii( "com.sun.star.xml.sax.Writer" );
1033 }
1034 
1035 OUString SaxWriter_getImplementationName() throw()
1036 {
1037 	return OUString::createFromAscii( "com.sun.star.extensions.xml.sax.Writer" );
1038 }
1039 
1040 Sequence< OUString > 	SaxWriter_getSupportedServiceNames(void) throw()
1041 {
1042 	Sequence<OUString> aRet(1);
1043 	aRet.getArray()[0] = SaxWriter_getServiceName();
1044 	return aRet;
1045 }
1046 
1047 
1048 sal_Int32 SAXWriter::getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurence ) throw()
1049 {
1050 	sal_Int32 nLength =-1;
1051 	if (mp_SaxWriterHelper)
1052 	{
1053 		if ( m_bForceLineBreak ||
1054 			(m_bAllowLineBreak &&
1055 			((nFirstLineBreakOccurence + mp_SaxWriterHelper->GetLastColumnCount()) > MAXCOLUMNCOUNT)) )
1056 			nLength = m_nLevel;
1057 	}
1058 	m_bForceLineBreak = sal_False;
1059 	m_bAllowLineBreak = sal_False;
1060 	return nLength;
1061 }
1062 
1063 static inline sal_Bool isFirstCharWhitespace( const sal_Unicode *p ) throw()
1064 {
1065 	return *p == ' ';
1066 }
1067 
1068 
1069 // XServiceInfo
1070 OUString SAXWriter::getImplementationName() throw()
1071 {
1072     return SaxWriter_getImplementationName();
1073 }
1074 
1075 // XServiceInfo
1076 sal_Bool SAXWriter::supportsService(const OUString& ServiceName) throw()
1077 {
1078     Sequence< OUString > aSNL = getSupportedServiceNames();
1079     const OUString * pArray = aSNL.getConstArray();
1080 
1081     for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
1082         if( pArray[i] == ServiceName )
1083             return sal_True;
1084 
1085     return sal_False;
1086 }
1087 
1088 // XServiceInfo
1089 Sequence< OUString > SAXWriter::getSupportedServiceNames(void) throw ()
1090 {
1091     Sequence<OUString> seq(1);
1092     seq.getArray()[0] = SaxWriter_getServiceName();
1093     return seq;
1094 }
1095 
1096 
1097 
1098 void SAXWriter::startDocument()						throw(SAXException, RuntimeException )
1099 {
1100 	if( m_bDocStarted || ! m_out.is() || !mp_SaxWriterHelper ) {
1101 		throw SAXException();
1102 	}
1103 	m_bDocStarted = sal_True;
1104 	mp_SaxWriterHelper->startDocument();
1105 }
1106 
1107 
1108 void SAXWriter::endDocument(void) 					throw(SAXException, RuntimeException)
1109 {
1110 	if( ! m_bDocStarted )
1111 	{
1112 		throw SAXException(
1113 			OUString::createFromAscii( "endDocument called before startDocument" ),
1114 			Reference< XInterface >() , Any() );
1115 	}
1116 	if( m_nLevel ) {
1117 		throw SAXException(
1118 			OUString::createFromAscii( "unexpected end of document" ),
1119 			Reference< XInterface >() , Any() );
1120 	}
1121 	mp_SaxWriterHelper->endDocument();
1122 	try
1123 	{
1124 		m_out->closeOutput();
1125 	}
1126 	catch( IOException & e )
1127 	{
1128 		Any a;
1129 		a <<= e;
1130 		throw SAXException(
1131 			OUString::createFromAscii( "IO exception during closing the IO Stream" ),
1132 			Reference< XInterface > (),
1133 			a );
1134 	}
1135 }
1136 
1137 
1138 void SAXWriter::startElement(const OUString& aName, const Reference< XAttributeList >& xAttribs)
1139 	throw(SAXException, RuntimeException)
1140 {
1141 	if( ! m_bDocStarted )
1142 	{
1143 		SAXException except;
1144 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "startElement called before startDocument" ));
1145 		throw except;
1146 	}
1147 	if( m_bIsCDATA )
1148 	{
1149 		SAXException except;
1150 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "startElement call not allowed with CDATA sections" ));
1151 		throw except;
1152 	}
1153 
1154 	sal_Int32 nLength(0);
1155 	if (m_bAllowLineBreak)
1156 	{
1157 		sal_Int32 nAttribCount = xAttribs.is() ? xAttribs->getLength() : 0;
1158 
1159 		nLength ++; // "<"
1160 		nLength += calcXMLByteLength( aName.getStr() , aName.getLength(),
1161 								  sal_False, sal_False ); // the tag name
1162 
1163 		sal_Int16 n;
1164 		for( n = 0 ; n < static_cast<sal_Int16>(nAttribCount) ; n ++ ) {
1165 			nLength ++; // " "
1166 			OUString tmp =  xAttribs->getNameByIndex( n );
1167 
1168 			nLength += calcXMLByteLength( tmp.getStr() , tmp.getLength() , sal_False, sal_False );
1169 
1170 			nLength += 2; // ="
1171 
1172 			tmp = xAttribs->getValueByIndex( n );
1173 
1174 			nLength += calcXMLByteLength( tmp.getStr(), tmp.getLength(), sal_True, sal_True );
1175 
1176 			nLength += 1; // "
1177 		}
1178 
1179 		nLength ++;  // '>'
1180 	}
1181 
1182 	// Is there a new indentation necesarry ?
1183 	sal_Int32 nPrefix(getIndentPrefixLength( nLength ));
1184 
1185 	// write into sequence
1186 	if( nPrefix >= 0 )
1187 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1188 
1189 	SaxInvalidCharacterError eRet(mp_SaxWriterHelper->startElement(aName, xAttribs));
1190 
1191 	m_nLevel++;
1192 
1193 	if (eRet == SAX_WARNING)
1194 	{
1195 		SAXInvalidCharacterException except;
1196 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export in a attribute value" ) );
1197 		throw except;
1198 	}
1199 	else if (eRet == SAX_ERROR)
1200 	{
1201 		SAXException except;
1202 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1203 		throw except;
1204 	}
1205 }
1206 
1207 void SAXWriter::endElement(const OUString& aName) 	throw (SAXException, RuntimeException)
1208 {
1209 	if( ! m_bDocStarted ) {
1210 		throw SAXException ();
1211 	}
1212 	m_nLevel --;
1213 
1214 	if( m_nLevel < 0 ) {
1215 		throw SAXException();
1216 	}
1217 	sal_Bool bRet(sal_True);
1218 
1219 	if( mp_SaxWriterHelper->FinishEmptyElement() )
1220         m_bForceLineBreak = sal_False;
1221 	else
1222 	{
1223 		// only ascii chars allowed
1224 		sal_Int32 nLength(0);
1225 		if (m_bAllowLineBreak)
1226 			nLength = 3 + calcXMLByteLength( aName.getStr(), aName.getLength(), sal_False, sal_False );
1227 		sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1228 
1229 		if( nPrefix >= 0 )
1230 			mp_SaxWriterHelper->insertIndentation( nPrefix );
1231 
1232 		bRet = mp_SaxWriterHelper->endElement(aName);
1233 	}
1234 
1235 	if (!bRet)
1236 	{
1237 		SAXException except;
1238 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1239 		throw except;
1240 	}
1241 }
1242 
1243 void SAXWriter::characters(const OUString& aChars) 	throw(SAXException, RuntimeException)
1244 {
1245 	if( ! m_bDocStarted )
1246 	{
1247 		SAXException except;
1248 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "characters method called before startDocument" ) );
1249 		throw except;
1250 	}
1251 
1252 	sal_Bool bThrowException(sal_False);
1253 	if( aChars.getLength() )
1254 	{
1255 		if( m_bIsCDATA )
1256 			bThrowException = !mp_SaxWriterHelper->writeString( aChars, sal_False, sal_False );
1257 		else
1258 		{
1259 			// Note : nFirstLineBreakOccurence is not exact, because we don't know, how
1260 			//        many 2 and 3 byte chars are inbetween. However this whole stuff
1261 			//        is eitherway for pretty printing only, so it does not need to be exact.
1262 			sal_Int32 nLength(0);
1263 			sal_Int32 nIndentPrefix(-1);
1264 			if (m_bAllowLineBreak)
1265 			{
1266 				sal_Int32 nFirstLineBreakOccurence = getFirstLineBreak( aChars );
1267 
1268 				nLength = calcXMLByteLength( aChars.getStr(), aChars.getLength(),
1269 											   ! m_bIsCDATA , sal_False );
1270 				nIndentPrefix = getIndentPrefixLength(
1271 					nFirstLineBreakOccurence >= 0 ? nFirstLineBreakOccurence : nLength );
1272 			}
1273 			else
1274 				nIndentPrefix = getIndentPrefixLength(nLength);
1275 
1276 			// insert indentation
1277 			if( nIndentPrefix >= 0 )
1278 			{
1279 				if( isFirstCharWhitespace( aChars.getStr() ) )
1280 					mp_SaxWriterHelper->insertIndentation( nIndentPrefix - 1 );
1281 				else
1282 					mp_SaxWriterHelper->insertIndentation( nIndentPrefix );
1283 			}
1284 			bThrowException = !mp_SaxWriterHelper->writeString(aChars, sal_True , sal_False);
1285 		}
1286 	}
1287 	if (bThrowException)
1288 	{
1289 		SAXInvalidCharacterException except;
1290 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1291 		throw except;
1292 	}
1293 }
1294 
1295 
1296 void SAXWriter::ignorableWhitespace(const OUString&) throw(SAXException, RuntimeException)
1297 {
1298 	if( ! m_bDocStarted )
1299 	{
1300 		throw SAXException ();
1301 	}
1302 
1303 	m_bForceLineBreak = sal_True;
1304 }
1305 
1306 void SAXWriter::processingInstruction(const OUString& aTarget, const OUString& aData)
1307 	throw (SAXException, RuntimeException)
1308 {
1309 	if( ! m_bDocStarted || m_bIsCDATA )
1310 	{
1311 		throw SAXException();
1312 	}
1313 
1314 	sal_Int32 nLength(0);
1315 	if (m_bAllowLineBreak)
1316 	{
1317 		nLength = 2;  // "<?"
1318 		nLength += calcXMLByteLength( aTarget.getStr(), aTarget.getLength(), sal_False, sal_False );
1319 
1320 		nLength += 1;  // " "
1321 
1322 		nLength += calcXMLByteLength( aData.getStr(), aData.getLength(), sal_False, sal_False );
1323 
1324 		nLength += 2; // "?>"
1325 	}
1326 
1327 	sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1328 
1329 	if( nPrefix >= 0 )
1330 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1331 
1332 	if (!mp_SaxWriterHelper->processingInstruction(aTarget, aData))
1333 	{
1334 		SAXException except;
1335 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1336 		throw except;
1337 	}
1338 }
1339 
1340 
1341 void SAXWriter::setDocumentLocator(const Reference< XLocator >&)
1342 		throw (SAXException, RuntimeException)
1343 {
1344 
1345 }
1346 
1347 void SAXWriter::startCDATA(void) throw(SAXException, RuntimeException)
1348 {
1349 	if( ! m_bDocStarted || m_bIsCDATA)
1350 	{
1351 		throw SAXException ();
1352 	}
1353 
1354 	sal_Int32 nLength = 9;
1355 	sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1356 	if( nPrefix >= 0 )
1357 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1358 
1359 	mp_SaxWriterHelper->startCDATA();
1360 
1361 	m_bIsCDATA = sal_True;
1362 }
1363 
1364 void SAXWriter::endCDATA(void) throw (RuntimeException)
1365 {
1366 	if( ! m_bDocStarted | ! m_bIsCDATA)
1367 	{
1368 		SAXException except;
1369 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "endCDATA was called without startCDATA" ) );
1370 		throw except;
1371 	}
1372 
1373 	sal_Int32 nLength = 3;
1374 	sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1375 	if( nPrefix >= 0 )
1376 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1377 
1378 	mp_SaxWriterHelper->endCDATA();
1379 
1380 	m_bIsCDATA = sal_False;
1381 }
1382 
1383 
1384 void SAXWriter::comment(const OUString& sComment) throw(SAXException, RuntimeException)
1385 {
1386 	if( ! m_bDocStarted || m_bIsCDATA )
1387 	{
1388 		throw SAXException();
1389 	}
1390 
1391 	sal_Int32 nLength(0);
1392 	if (m_bAllowLineBreak)
1393 	{
1394 		nLength = 4; // "<!--"
1395 		nLength += calcXMLByteLength( sComment.getStr(), sComment.getLength(), sal_False, sal_False);
1396 
1397 		nLength += 3;
1398 	}
1399 
1400 	sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1401 	if( nPrefix >= 0 )
1402 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1403 
1404 	if (!mp_SaxWriterHelper->comment(sComment))
1405 	{
1406 		SAXException except;
1407 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1408 		throw except;
1409 	}
1410 }
1411 
1412 
1413 void SAXWriter::allowLineBreak( ) 	throw ( SAXException , RuntimeException)
1414 {
1415 	if( ! m_bDocStarted || m_bAllowLineBreak ) {
1416 		throw SAXException();
1417 	}
1418 
1419 	 m_bAllowLineBreak = sal_True;
1420 }
1421 
1422 void SAXWriter::unknown(const OUString& sString) throw (SAXException, RuntimeException)
1423 {
1424 
1425 	if( ! m_bDocStarted )
1426 	{
1427 		throw SAXException ();
1428 	}
1429 	if( m_bIsCDATA )
1430 	{
1431 		throw SAXException();
1432 	}
1433 
1434 	if( sString.matchAsciiL( "<?xml", 5 ) )
1435 		return;
1436 
1437 	sal_Int32 nLength(0);
1438 	if (m_bAllowLineBreak)
1439 		nLength = calcXMLByteLength( sString.getStr(), sString.getLength(), sal_False, sal_False );
1440 
1441 	sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1442 	if( nPrefix >= 0 )
1443 		mp_SaxWriterHelper->insertIndentation( nPrefix );
1444 
1445 	if (!mp_SaxWriterHelper->writeString( sString, sal_False, sal_False))
1446 	{
1447 		SAXException except;
1448 		except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1449 		throw except;
1450 	}
1451 }
1452 
1453 }
1454 
1455