xref: /trunk/main/sax/source/expatwrap/saxwriter.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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