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