xref: /trunk/main/sax/source/expatwrap/saxwriter.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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();
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);
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);
149     inline void FinishStartElement();
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);
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);
176 
GetLastColumnCount()177     sal_uInt32 GetLastColumnCount() { return (sal_uInt32)(nCurrentPos - nLastLineFeedPos); }
178 
179     inline void startDocument();
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);
185     inline sal_Bool FinishEmptyElement();
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);
191     inline void endDocument();
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);
197     inline void startCDATA();
198     inline void endCDATA();
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);
204 
205     inline void clearBuffer();
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()
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)
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 )
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()
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)
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 )
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()
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)
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()
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)
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()
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()
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)
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()
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()
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)
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             {
937                 // temporary: set same stream again to clear buffer
938                 if ( m_out == aStream && mp_SaxWriterHelper && m_bDocStarted )
939                     mp_SaxWriterHelper->clearBuffer();
940                 else
941                 {
942 
943                 m_out = aStream;
944                 delete mp_SaxWriterHelper;
945                 mp_SaxWriterHelper = new SaxWriterHelper(m_out);
946                 m_bDocStarted = sal_False;
947                 m_nLevel = 0;
948                 m_bIsCDATA = sal_False;
949 
950                 }
951             }
getOutputStream(void)952     virtual Reference< XOutputStream >  SAL_CALL getOutputStream(void)
953             { return m_out; }
954 
955 public: // XDocumentHandler
956     virtual void SAL_CALL startDocument(void);
957 
958     virtual void SAL_CALL endDocument(void);
959 
960     virtual void SAL_CALL startElement(const OUString& aName,
961                                        const Reference< XAttributeList > & xAttribs);
962 
963     virtual void SAL_CALL endElement(const OUString& aName);
964 
965     virtual void SAL_CALL characters(const OUString& aChars);
966 
967     virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces);
968     virtual void SAL_CALL processingInstruction(const OUString& aTarget,
969                                                 const OUString& aData);
970     virtual void SAL_CALL setDocumentLocator(const Reference< XLocator > & xLocator);
971 
972 public: // XExtendedDocumentHandler
973     virtual void SAL_CALL startCDATA(void);
974     virtual void SAL_CALL endCDATA(void);
975     virtual void SAL_CALL comment(const OUString& sComment);
976     virtual void SAL_CALL unknown(const OUString& sString);
977     virtual void SAL_CALL allowLineBreak(void);
978 
979 public: // XServiceInfo
980     OUString                     SAL_CALL getImplementationName() throw();
981     Sequence< OUString >         SAL_CALL getSupportedServiceNames(void) throw();
982     sal_Bool                    SAL_CALL supportsService(const OUString& ServiceName) throw();
983 
984 private:
985 
986     void writeSequence( const Sequence<sal_Int8> & seq );
987     sal_Int32 getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurence ) throw();
988 
989     Reference< XOutputStream >  m_out;
990     Sequence < sal_Int8 >       m_seqStartElement;
991     SaxWriterHelper*            mp_SaxWriterHelper;
992 
993     // Status information
994     sal_Bool m_bDocStarted : 1;
995     sal_Bool m_bIsCDATA : 1;
996     sal_Bool m_bForceLineBreak : 1;
997     sal_Bool m_bAllowLineBreak : 1;
998     sal_Int32 m_nLevel;
999 };
1000 
1001 
1002 //--------------------------------------
1003 // the extern interface
1004 //---------------------------------------
SaxWriter_CreateInstance(const Reference<XComponentContext> &)1005 Reference < XInterface > SAL_CALL SaxWriter_CreateInstance(
1006     const Reference < XComponentContext >  &  )
1007 {
1008     SAXWriter *p = new SAXWriter;
1009     return Reference< XInterface > ( SAL_STATIC_CAST(OWeakObject *, p ) );
1010 }
1011 
SaxWriter_getServiceName()1012 OUString SaxWriter_getServiceName() throw()
1013 {
1014     return OUString::createFromAscii( "com.sun.star.xml.sax.Writer" );
1015 }
1016 
SaxWriter_getImplementationName()1017 OUString SaxWriter_getImplementationName() throw()
1018 {
1019     return OUString::createFromAscii( "com.sun.star.extensions.xml.sax.Writer" );
1020 }
1021 
SaxWriter_getSupportedServiceNames(void)1022 Sequence< OUString >    SaxWriter_getSupportedServiceNames(void) throw()
1023 {
1024     Sequence<OUString> aRet(1);
1025     aRet.getArray()[0] = SaxWriter_getServiceName();
1026     return aRet;
1027 }
1028 
1029 
getIndentPrefixLength(sal_Int32 nFirstLineBreakOccurence)1030 sal_Int32 SAXWriter::getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurence ) throw()
1031 {
1032     sal_Int32 nLength =-1;
1033     if (mp_SaxWriterHelper)
1034     {
1035         if ( m_bForceLineBreak ||
1036             (m_bAllowLineBreak &&
1037             ((nFirstLineBreakOccurence + mp_SaxWriterHelper->GetLastColumnCount()) > MAXCOLUMNCOUNT)) )
1038             nLength = m_nLevel;
1039     }
1040     m_bForceLineBreak = sal_False;
1041     m_bAllowLineBreak = sal_False;
1042     return nLength;
1043 }
1044 
isFirstCharWhitespace(const sal_Unicode * p)1045 static inline sal_Bool isFirstCharWhitespace( const sal_Unicode *p ) throw()
1046 {
1047     return *p == ' ';
1048 }
1049 
1050 
1051 // XServiceInfo
getImplementationName()1052 OUString SAXWriter::getImplementationName() throw()
1053 {
1054     return SaxWriter_getImplementationName();
1055 }
1056 
1057 // XServiceInfo
supportsService(const OUString & ServiceName)1058 sal_Bool SAXWriter::supportsService(const OUString& ServiceName) throw()
1059 {
1060     Sequence< OUString > aSNL = getSupportedServiceNames();
1061     const OUString * pArray = aSNL.getConstArray();
1062 
1063     for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
1064         if( pArray[i] == ServiceName )
1065             return sal_True;
1066 
1067     return sal_False;
1068 }
1069 
1070 // XServiceInfo
getSupportedServiceNames(void)1071 Sequence< OUString > SAXWriter::getSupportedServiceNames(void) throw ()
1072 {
1073     Sequence<OUString> seq(1);
1074     seq.getArray()[0] = SaxWriter_getServiceName();
1075     return seq;
1076 }
1077 
1078 
1079 
startDocument()1080 void SAXWriter::startDocument()
1081 {
1082     if( m_bDocStarted || ! m_out.is() || !mp_SaxWriterHelper ) {
1083         throw SAXException();
1084     }
1085     m_bDocStarted = sal_True;
1086     mp_SaxWriterHelper->startDocument();
1087 }
1088 
1089 
endDocument(void)1090 void SAXWriter::endDocument(void)
1091 {
1092     if( ! m_bDocStarted )
1093     {
1094         throw SAXException(
1095             OUString::createFromAscii( "endDocument called before startDocument" ),
1096             Reference< XInterface >() , Any() );
1097     }
1098     if( m_nLevel ) {
1099         throw SAXException(
1100             OUString::createFromAscii( "unexpected end of document" ),
1101             Reference< XInterface >() , Any() );
1102     }
1103     mp_SaxWriterHelper->endDocument();
1104     try
1105     {
1106         m_out->closeOutput();
1107     }
1108     catch( IOException & e )
1109     {
1110         Any a;
1111         a <<= e;
1112         throw SAXException(
1113             OUString::createFromAscii( "IO exception during closing the IO Stream" ),
1114             Reference< XInterface > (),
1115             a );
1116     }
1117 }
1118 
1119 
startElement(const OUString & aName,const Reference<XAttributeList> & xAttribs)1120 void SAXWriter::startElement(const OUString& aName, const Reference< XAttributeList >& xAttribs)
1121 {
1122     if( ! m_bDocStarted )
1123     {
1124         SAXException except;
1125         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "startElement called before startDocument" ));
1126         throw except;
1127     }
1128     if( m_bIsCDATA )
1129     {
1130         SAXException except;
1131         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "startElement call not allowed with CDATA sections" ));
1132         throw except;
1133     }
1134 
1135     sal_Int32 nLength(0);
1136     if (m_bAllowLineBreak)
1137     {
1138         sal_Int32 nAttribCount = xAttribs.is() ? xAttribs->getLength() : 0;
1139 
1140         nLength ++; // "<"
1141         nLength += calcXMLByteLength( aName.getStr() , aName.getLength(),
1142                                   sal_False, sal_False ); // the tag name
1143 
1144         sal_Int16 n;
1145         for( n = 0 ; n < static_cast<sal_Int16>(nAttribCount) ; n ++ ) {
1146             nLength ++; // " "
1147             OUString tmp =  xAttribs->getNameByIndex( n );
1148 
1149             nLength += calcXMLByteLength( tmp.getStr() , tmp.getLength() , sal_False, sal_False );
1150 
1151             nLength += 2; // ="
1152 
1153             tmp = xAttribs->getValueByIndex( n );
1154 
1155             nLength += calcXMLByteLength( tmp.getStr(), tmp.getLength(), sal_True, sal_True );
1156 
1157             nLength += 1; // "
1158         }
1159 
1160         nLength ++;  // '>'
1161     }
1162 
1163     // Is there a new indentation necessary ?
1164     sal_Int32 nPrefix(getIndentPrefixLength( nLength ));
1165 
1166     // write into sequence
1167     if( nPrefix >= 0 )
1168         mp_SaxWriterHelper->insertIndentation( nPrefix );
1169 
1170     SaxInvalidCharacterError eRet(mp_SaxWriterHelper->startElement(aName, xAttribs));
1171 
1172     m_nLevel++;
1173 
1174     if (eRet == SAX_WARNING)
1175     {
1176         SAXInvalidCharacterException except;
1177         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export in a attribute value" ) );
1178         throw except;
1179     }
1180     else if (eRet == SAX_ERROR)
1181     {
1182         SAXException except;
1183         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1184         throw except;
1185     }
1186 }
1187 
endElement(const OUString & aName)1188 void SAXWriter::endElement(const OUString& aName)
1189 {
1190     if( ! m_bDocStarted ) {
1191         throw SAXException ();
1192     }
1193     m_nLevel --;
1194 
1195     if( m_nLevel < 0 ) {
1196         throw SAXException();
1197     }
1198     sal_Bool bRet(sal_True);
1199 
1200     if( mp_SaxWriterHelper->FinishEmptyElement() )
1201         m_bForceLineBreak = sal_False;
1202     else
1203     {
1204         // only ascii chars allowed
1205         sal_Int32 nLength(0);
1206         if (m_bAllowLineBreak)
1207             nLength = 3 + calcXMLByteLength( aName.getStr(), aName.getLength(), sal_False, sal_False );
1208         sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1209 
1210         if( nPrefix >= 0 )
1211             mp_SaxWriterHelper->insertIndentation( nPrefix );
1212 
1213         bRet = mp_SaxWriterHelper->endElement(aName);
1214     }
1215 
1216     if (!bRet)
1217     {
1218         SAXException except;
1219         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1220         throw except;
1221     }
1222 }
1223 
characters(const OUString & aChars)1224 void SAXWriter::characters(const OUString& aChars)
1225 {
1226     if( ! m_bDocStarted )
1227     {
1228         SAXException except;
1229         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "characters method called before startDocument" ) );
1230         throw except;
1231     }
1232 
1233     sal_Bool bThrowException(sal_False);
1234     if( aChars.getLength() )
1235     {
1236         if( m_bIsCDATA )
1237             bThrowException = !mp_SaxWriterHelper->writeString( aChars, sal_False, sal_False );
1238         else
1239         {
1240             // Note : nFirstLineBreakOccurence is not exact, because we don't know, how
1241             //        many 2 and 3 byte chars are inbetween. However this whole stuff
1242             //        is eitherway for pretty printing only, so it does not need to be exact.
1243             sal_Int32 nLength(0);
1244             sal_Int32 nIndentPrefix(-1);
1245             if (m_bAllowLineBreak)
1246             {
1247                 sal_Int32 nFirstLineBreakOccurence = getFirstLineBreak( aChars );
1248 
1249                 nLength = calcXMLByteLength( aChars.getStr(), aChars.getLength(),
1250                                                ! m_bIsCDATA , sal_False );
1251                 nIndentPrefix = getIndentPrefixLength(
1252                     nFirstLineBreakOccurence >= 0 ? nFirstLineBreakOccurence : nLength );
1253             }
1254             else
1255                 nIndentPrefix = getIndentPrefixLength(nLength);
1256 
1257             // insert indentation
1258             if( nIndentPrefix >= 0 )
1259             {
1260                 if( isFirstCharWhitespace( aChars.getStr() ) )
1261                     mp_SaxWriterHelper->insertIndentation( nIndentPrefix - 1 );
1262                 else
1263                     mp_SaxWriterHelper->insertIndentation( nIndentPrefix );
1264             }
1265             bThrowException = !mp_SaxWriterHelper->writeString(aChars, sal_True , sal_False);
1266         }
1267     }
1268     if (bThrowException)
1269     {
1270         SAXInvalidCharacterException except;
1271         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1272         throw except;
1273     }
1274 }
1275 
1276 
ignorableWhitespace(const OUString &)1277 void SAXWriter::ignorableWhitespace(const OUString&)
1278 {
1279     if( ! m_bDocStarted )
1280     {
1281         throw SAXException ();
1282     }
1283 
1284     m_bForceLineBreak = sal_True;
1285 }
1286 
processingInstruction(const OUString & aTarget,const OUString & aData)1287 void SAXWriter::processingInstruction(const OUString& aTarget, const OUString& aData)
1288 {
1289     if( ! m_bDocStarted || m_bIsCDATA )
1290     {
1291         throw SAXException();
1292     }
1293 
1294     sal_Int32 nLength(0);
1295     if (m_bAllowLineBreak)
1296     {
1297         nLength = 2;  // "<?"
1298         nLength += calcXMLByteLength( aTarget.getStr(), aTarget.getLength(), sal_False, sal_False );
1299 
1300         nLength += 1;  // " "
1301 
1302         nLength += calcXMLByteLength( aData.getStr(), aData.getLength(), sal_False, sal_False );
1303 
1304         nLength += 2; // "?>"
1305     }
1306 
1307     sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1308 
1309     if( nPrefix >= 0 )
1310         mp_SaxWriterHelper->insertIndentation( nPrefix );
1311 
1312     if (!mp_SaxWriterHelper->processingInstruction(aTarget, aData))
1313     {
1314         SAXException except;
1315         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1316         throw except;
1317     }
1318 }
1319 
1320 
setDocumentLocator(const Reference<XLocator> &)1321 void SAXWriter::setDocumentLocator(const Reference< XLocator >&)
1322 {
1323 
1324 }
1325 
startCDATA(void)1326 void SAXWriter::startCDATA(void)
1327 {
1328     if( ! m_bDocStarted || m_bIsCDATA)
1329     {
1330         throw SAXException ();
1331     }
1332 
1333     sal_Int32 nLength = 9;
1334     sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1335     if( nPrefix >= 0 )
1336         mp_SaxWriterHelper->insertIndentation( nPrefix );
1337 
1338     mp_SaxWriterHelper->startCDATA();
1339 
1340     m_bIsCDATA = sal_True;
1341 }
1342 
endCDATA(void)1343 void SAXWriter::endCDATA(void)
1344 {
1345     if( ! m_bDocStarted | ! m_bIsCDATA)
1346     {
1347         SAXException except;
1348         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "endCDATA was called without startCDATA" ) );
1349         throw except;
1350     }
1351 
1352     sal_Int32 nLength = 3;
1353     sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1354     if( nPrefix >= 0 )
1355         mp_SaxWriterHelper->insertIndentation( nPrefix );
1356 
1357     mp_SaxWriterHelper->endCDATA();
1358 
1359     m_bIsCDATA = sal_False;
1360 }
1361 
1362 
comment(const OUString & sComment)1363 void SAXWriter::comment(const OUString& sComment)
1364 {
1365     if( ! m_bDocStarted || m_bIsCDATA )
1366     {
1367         throw SAXException();
1368     }
1369 
1370     sal_Int32 nLength(0);
1371     if (m_bAllowLineBreak)
1372     {
1373         nLength = 4; // "<!--"
1374         nLength += calcXMLByteLength( sComment.getStr(), sComment.getLength(), sal_False, sal_False);
1375 
1376         nLength += 3;
1377     }
1378 
1379     sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1380     if( nPrefix >= 0 )
1381         mp_SaxWriterHelper->insertIndentation( nPrefix );
1382 
1383     if (!mp_SaxWriterHelper->comment(sComment))
1384     {
1385         SAXException except;
1386         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1387         throw except;
1388     }
1389 }
1390 
1391 
allowLineBreak()1392 void SAXWriter::allowLineBreak( )
1393 {
1394     if( ! m_bDocStarted || m_bAllowLineBreak ) {
1395         throw SAXException();
1396     }
1397 
1398      m_bAllowLineBreak = sal_True;
1399 }
1400 
unknown(const OUString & sString)1401 void SAXWriter::unknown(const OUString& sString)
1402 {
1403 
1404     if( ! m_bDocStarted )
1405     {
1406         throw SAXException ();
1407     }
1408     if( m_bIsCDATA )
1409     {
1410         throw SAXException();
1411     }
1412 
1413     if( sString.matchAsciiL( "<?xml", 5 ) )
1414         return;
1415 
1416     sal_Int32 nLength(0);
1417     if (m_bAllowLineBreak)
1418         nLength = calcXMLByteLength( sString.getStr(), sString.getLength(), sal_False, sal_False );
1419 
1420     sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1421     if( nPrefix >= 0 )
1422         mp_SaxWriterHelper->insertIndentation( nPrefix );
1423 
1424     if (!mp_SaxWriterHelper->writeString( sString, sal_False, sal_False))
1425     {
1426         SAXException except;
1427         except.Message = OUString( RTL_CONSTASCII_USTRINGPARAM( "Invalid charcter during XML-Export" ) );
1428         throw except;
1429     }
1430 }
1431 
1432 }
1433