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