Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <string.h>
21 :
22 : #include <stack>
23 : #include <set>
24 :
25 : #include <com/sun/star/lang/XServiceInfo.hpp>
26 : #include <com/sun/star/util/XCloneable.hpp>
27 : #include <com/sun/star/xml/sax/XParser.hpp>
28 : #include <com/sun/star/xml/sax/SAXParseException.hpp>
29 : #include <com/sun/star/xml/sax/SAXInvalidCharacterException.hpp>
30 : #include <com/sun/star/xml/sax/XWriter.hpp>
31 :
32 : #include <com/sun/star/io/XActiveDataSource.hpp>
33 :
34 : #include <cppuhelper/factory.hxx>
35 : #include <cppuhelper/weak.hxx>
36 : #include <cppuhelper/implbase2.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 : enum SaxInvalidCharacterError
71 : {
72 : SAX_NONE,
73 : SAX_WARNING,
74 : SAX_ERROR
75 : };
76 :
77 : class SaxWriterHelper
78 : {
79 : #ifdef DBG_UTIL
80 : public:
81 : ::std::stack<OUString> m_DebugStartedElements;
82 : #endif
83 :
84 : private:
85 : Reference< XOutputStream > m_out;
86 : Sequence < sal_Int8 > m_Sequence;
87 : sal_Int8* mp_Sequence;
88 :
89 : sal_Int32 nLastLineFeedPos; // is negative after writing a sequence
90 : sal_uInt32 nCurrentPos;
91 : sal_Bool m_bStartElementFinished;
92 :
93 : inline sal_uInt32 writeSequence() throw( SAXException );
94 :
95 : // use only if to insert the bytes more space in the sequence is needed and
96 : // so the sequence has to write out and reset rPos to 0
97 : // writes sequence only on overflow, sequence could be full on the end (rPos == SEQUENCESIZE)
98 : inline void AddBytes(sal_Int8* pTarget, sal_uInt32& rPos,
99 : const sal_Int8* pBytes, sal_uInt32 nBytesCount) throw( SAXException );
100 : inline sal_Bool convertToXML(const sal_Unicode * pStr,
101 : sal_Int32 nStrLen,
102 : sal_Bool bDoNormalization,
103 : sal_Bool bNormalizeWhitespace,
104 : sal_Int8 *pTarget,
105 : sal_uInt32& rPos) throw( SAXException );
106 : inline void FinishStartElement() throw( SAXException );
107 : public:
108 1259 : SaxWriterHelper(Reference< XOutputStream > m_TempOut) :
109 : m_out(m_TempOut),
110 : m_Sequence(SEQUENCESIZE),
111 : mp_Sequence(NULL),
112 : nLastLineFeedPos(0),
113 : nCurrentPos(0),
114 1259 : m_bStartElementFinished(sal_True)
115 : {
116 : OSL_ENSURE(SEQUENCESIZE > 50, "Sequence cache size to small");
117 1259 : mp_Sequence = m_Sequence.getArray();
118 1259 : }
119 1259 : ~SaxWriterHelper()
120 1259 : {
121 : OSL_ENSURE(!nCurrentPos, "cached Sequence not written");
122 : OSL_ENSURE(m_bStartElementFinished, "StartElement not complettly written");
123 1259 : }
124 :
125 : inline void insertIndentation(sal_uInt32 m_nLevel) throw( SAXException );
126 :
127 : // returns whether it works correct or invalid characters were in the string
128 : // If there are invalid characters in the string it returns sal_False.
129 : // Than the calling method has to throw the needed Exception.
130 : inline sal_Bool writeString(const OUString& rWriteOutString,
131 : sal_Bool bDoNormalization,
132 : sal_Bool bNormalizeWhitespace) throw( SAXException );
133 :
134 0 : sal_uInt32 GetLastColumnCount() const
135 0 : { return (sal_uInt32)(nCurrentPos - nLastLineFeedPos); }
136 :
137 : inline void startDocument() throw( SAXException );
138 :
139 : // returns whether it works correct or invalid characters were in the strings
140 : // If there are invalid characters in one of the strings it returns sal_False.
141 : // Than the calling method has to throw the needed Exception.
142 : inline SaxInvalidCharacterError startElement(const OUString& rName, const Reference< XAttributeList >& xAttribs) throw( SAXException );
143 : inline sal_Bool FinishEmptyElement() throw( SAXException );
144 :
145 : // returns whether it works correct or invalid characters were in the string
146 : // If there are invalid characters in the string it returns sal_False.
147 : // Than the calling method has to throw the needed Exception.
148 : inline sal_Bool endElement(const OUString& rName) throw( SAXException );
149 : inline void endDocument() throw( SAXException );
150 :
151 : // returns whether it works correct or invalid characters were in the strings
152 : // If there are invalid characters in the string it returns sal_False.
153 : // Than the calling method has to throw the needed Exception.
154 : inline sal_Bool processingInstruction(const OUString& rTarget, const OUString& rData) throw( SAXException );
155 : inline void startCDATA() throw( SAXException );
156 : inline void endCDATA() throw( SAXException );
157 :
158 : // returns whether it works correct or invalid characters were in the strings
159 : // If there are invalid characters in the string it returns sal_False.
160 : // Than the calling method has to throw the needed Exception.
161 : inline sal_Bool comment(const OUString& rComment) throw( SAXException );
162 :
163 : inline void clearBuffer() throw( SAXException );
164 : };
165 :
166 : const sal_Bool g_bValidCharsBelow32[32] =
167 : {
168 : // 0 1 2 3 4 5 6 7
169 : 0,0,0,0,0,0,0,0, //0
170 : 0,1,1,0,0,1,0,0, //8
171 : 0,0,0,0,0,0,0,0, //16
172 : 0,0,0,0,0,0,0,0
173 : };
174 :
175 3281853 : inline sal_Bool IsInvalidChar(const sal_Unicode aChar)
176 : {
177 3281853 : sal_Bool bRet(sal_False);
178 : // check first for the most common characters
179 3281853 : if( aChar < 32 || aChar >= 0xd800 )
180 9 : bRet = ( (aChar < 32 && ! g_bValidCharsBelow32[aChar]) ||
181 58 : aChar == 0xffff ||
182 29 : aChar == 0xfffe );
183 3281853 : return bRet;
184 : }
185 :
186 : /********
187 : * write through to the output stream
188 : *
189 : *****/
190 4378 : inline sal_uInt32 SaxWriterHelper::writeSequence() throw( SAXException )
191 : {
192 : try
193 : {
194 4378 : m_out->writeBytes( m_Sequence );
195 : }
196 0 : catch (const IOException & e)
197 : {
198 0 : Any a;
199 0 : a <<= e;
200 : throw SAXException(
201 : OUString("io exception during writing"),
202 : Reference< XInterface > (),
203 0 : a );
204 : }
205 4378 : nLastLineFeedPos -= SEQUENCESIZE;
206 4378 : return 0;
207 : }
208 :
209 7 : inline void SaxWriterHelper::AddBytes(sal_Int8* pTarget, sal_uInt32& rPos,
210 : const sal_Int8* pBytes, sal_uInt32 nBytesCount) throw( SAXException )
211 : {
212 : OSL_ENSURE((rPos + nBytesCount) > SEQUENCESIZE, "wrong use of AddBytesMethod");
213 7 : sal_uInt32 nCount(SEQUENCESIZE - rPos);
214 7 : memcpy( &(pTarget[rPos]) , pBytes, nCount);
215 :
216 : OSL_ENSURE(rPos + nCount == SEQUENCESIZE, "the position should be the at the end");
217 :
218 7 : rPos = writeSequence();
219 7 : sal_uInt32 nRestCount(nBytesCount - nCount);
220 7 : if ((rPos + nRestCount) <= SEQUENCESIZE)
221 : {
222 7 : memcpy( &(pTarget[rPos]), &pBytes[nCount], nRestCount);
223 7 : rPos += nRestCount;
224 : }
225 : else
226 0 : AddBytes(pTarget, rPos, &pBytes[nCount], nRestCount);
227 7 : }
228 :
229 : /** Converts an UTF16 string to UTF8 and does XML normalization
230 :
231 : @param pTarget
232 : Pointer to a piece of memory, to where the output should be written. The caller
233 : must call calcXMLByteLength on the same string, to ensure,
234 : that there is enough memory for converting.
235 : */
236 247829 : inline sal_Bool SaxWriterHelper::convertToXML( const sal_Unicode * pStr,
237 : sal_Int32 nStrLen,
238 : sal_Bool bDoNormalization,
239 : sal_Bool bNormalizeWhitespace,
240 : sal_Int8 *pTarget,
241 : sal_uInt32& rPos ) throw( SAXException )
242 : {
243 247829 : sal_Bool bRet(sal_True);
244 247829 : sal_uInt32 nSurrogate = 0;
245 :
246 3529682 : for( sal_Int32 i = 0 ; i < nStrLen ; i ++ )
247 : {
248 3281853 : sal_uInt16 c = pStr[i];
249 3281853 : if (IsInvalidChar(c))
250 0 : bRet = sal_False;
251 3281853 : else if( (c >= 0x0001) && (c <= 0x007F) )
252 : {
253 6560384 : if( bDoNormalization )
254 : {
255 1198468 : switch( c )
256 : {
257 : case '&': // resemble to &
258 : {
259 0 : if ((rPos + 5) > SEQUENCESIZE)
260 0 : AddBytes(pTarget, rPos, (sal_Int8*)"&", 5);
261 : else
262 : {
263 0 : memcpy( &(pTarget[rPos]) , "&", 5 );
264 0 : rPos += 5;
265 : }
266 : }
267 0 : break;
268 : case '<':
269 : {
270 103 : if ((rPos + 4) > SEQUENCESIZE)
271 0 : AddBytes(pTarget, rPos, (sal_Int8*)"<", 4);
272 : else
273 : {
274 103 : memcpy( &(pTarget[rPos]) , "<" , 4 );
275 103 : rPos += 4; // <
276 : }
277 : }
278 103 : break;
279 : case '>':
280 : {
281 71 : if ((rPos + 4) > SEQUENCESIZE)
282 0 : AddBytes(pTarget, rPos, (sal_Int8*)">", 4);
283 : else
284 : {
285 71 : memcpy( &(pTarget[rPos]) , ">" , 4 );
286 71 : rPos += 4; // >
287 : }
288 : }
289 71 : break;
290 : case 39: // 39 == '''
291 : {
292 574 : if ((rPos + 6) > SEQUENCESIZE)
293 6 : AddBytes(pTarget, rPos, (sal_Int8*)"'", 6);
294 : else
295 : {
296 568 : memcpy( &(pTarget[rPos]) , "'" , 6 );
297 568 : rPos += 6; // '
298 : }
299 : }
300 574 : break;
301 : case '"':
302 : {
303 62 : if ((rPos + 6) > SEQUENCESIZE)
304 0 : AddBytes(pTarget, rPos, (sal_Int8*)""", 6);
305 : else
306 : {
307 62 : memcpy( &(pTarget[rPos]) , """ , 6 );
308 62 : rPos += 6; // "
309 : }
310 : }
311 62 : break;
312 : case 13:
313 : {
314 0 : if ((rPos + 6) > SEQUENCESIZE)
315 0 : AddBytes(pTarget, rPos, (sal_Int8*)"
", 6);
316 : else
317 : {
318 0 : memcpy( &(pTarget[rPos]) , "
" , 6 );
319 0 : rPos += 6;
320 : }
321 : }
322 0 : break;
323 : case LINEFEED:
324 : {
325 9 : if( bNormalizeWhitespace )
326 : {
327 0 : if ((rPos + 6) > SEQUENCESIZE)
328 0 : AddBytes(pTarget, rPos, (sal_Int8*)"
" , 6);
329 : else
330 : {
331 0 : memcpy( &(pTarget[rPos]) , "
" , 6 );
332 0 : rPos += 6;
333 : }
334 : }
335 : else
336 : {
337 9 : pTarget[rPos] = LINEFEED;
338 9 : nLastLineFeedPos = rPos;
339 9 : rPos ++;
340 : }
341 : }
342 9 : break;
343 : case 9:
344 : {
345 0 : if( bNormalizeWhitespace )
346 : {
347 0 : if ((rPos + 6) > SEQUENCESIZE)
348 0 : AddBytes(pTarget, rPos, (sal_Int8*)"	" , 6);
349 : else
350 : {
351 0 : memcpy( &(pTarget[rPos]) , "	" , 6 );
352 0 : rPos += 6;
353 : }
354 : }
355 : else
356 : {
357 0 : pTarget[rPos] = 9;
358 0 : rPos ++;
359 : }
360 : }
361 0 : break;
362 : default:
363 : {
364 1197649 : pTarget[rPos] = (sal_Int8)c;
365 1197649 : rPos ++;
366 : }
367 1197649 : break;
368 : }
369 : }
370 : else
371 : {
372 2081724 : pTarget[rPos] = (sal_Int8)c;
373 2081724 : if ((sal_Int8)c == LINEFEED)
374 0 : nLastLineFeedPos = rPos;
375 2081724 : rPos ++;
376 : }
377 : }
378 1661 : else if( c >= 0xd800 && c < 0xdc00 )
379 : {
380 : // 1. surrogate: save (until 2. surrogate)
381 : OSL_ENSURE( nSurrogate == 0, "left-over Unicode surrogate" );
382 0 : nSurrogate = ( ( c & 0x03ff ) + 0x0040 );
383 : }
384 1661 : else if( c >= 0xdc00 && c < 0xe000 )
385 : {
386 : // 2. surrogate: write as UTF-8
387 : OSL_ENSURE( nSurrogate != 0, "lone 2nd Unicode surrogate" );
388 :
389 0 : nSurrogate = ( nSurrogate << 10 ) | ( c & 0x03ff );
390 0 : if( nSurrogate >= 0x00010000 && nSurrogate <= 0x0010FFFF )
391 : {
392 0 : sal_Int8 aBytes[] = { sal_Int8(0xF0 | ((nSurrogate >> 18) & 0x0F)),
393 0 : sal_Int8(0x80 | ((nSurrogate >> 12) & 0x3F)),
394 0 : sal_Int8(0x80 | ((nSurrogate >> 6) & 0x3F)),
395 0 : sal_Int8(0x80 | ((nSurrogate >> 0) & 0x3F)) };
396 0 : if ((rPos + 4) > SEQUENCESIZE)
397 0 : AddBytes(pTarget, rPos, aBytes, 4);
398 : else
399 : {
400 0 : pTarget[rPos] = aBytes[0];
401 0 : rPos ++;
402 0 : pTarget[rPos] = aBytes[1];
403 0 : rPos ++;
404 0 : pTarget[rPos] = aBytes[2];
405 0 : rPos ++;
406 0 : pTarget[rPos] = aBytes[3];
407 0 : rPos ++;
408 0 : }
409 : }
410 : else
411 : {
412 : OSL_FAIL( "illegal Unicode character" );
413 0 : bRet = sal_False;
414 : }
415 :
416 : // reset surrogate
417 0 : nSurrogate = 0;
418 : }
419 1661 : else if( c > 0x07FF )
420 : {
421 : sal_Int8 aBytes[] = { sal_Int8(0xE0 | ((c >> 12) & 0x0F)),
422 760 : sal_Int8(0x80 | ((c >> 6) & 0x3F)),
423 1520 : sal_Int8(0x80 | ((c >> 0) & 0x3F)) };
424 760 : if ((rPos + 3) > SEQUENCESIZE)
425 1 : AddBytes(pTarget, rPos, aBytes, 3);
426 : else
427 : {
428 759 : pTarget[rPos] = aBytes[0];
429 759 : rPos ++;
430 759 : pTarget[rPos] = aBytes[1];
431 759 : rPos ++;
432 759 : pTarget[rPos] = aBytes[2];
433 759 : rPos ++;
434 : }
435 : }
436 : else
437 : {
438 901 : sal_Int8 aBytes[] = { sal_Int8(0xC0 | ((c >> 6) & 0x1F)),
439 901 : sal_Int8(0x80 | ((c >> 0) & 0x3F)) };
440 901 : if ((rPos + 2) > SEQUENCESIZE)
441 0 : AddBytes(pTarget, rPos, aBytes, 2);
442 : else
443 : {
444 901 : pTarget[rPos] = aBytes[0];
445 901 : rPos ++;
446 901 : pTarget[rPos] = aBytes[1];
447 901 : rPos ++;
448 : }
449 : }
450 : OSL_ENSURE(rPos <= SEQUENCESIZE, "not reset current position");
451 3281853 : if (rPos == SEQUENCESIZE)
452 2972 : rPos = writeSequence();
453 :
454 : // reset left-over surrogate
455 3281853 : if( ( nSurrogate != 0 ) && !( c >= 0xd800 && c < 0xdc00 ) )
456 : {
457 : OSL_ENSURE( nSurrogate != 0, "left-over Unicode surrogate" );
458 0 : nSurrogate = 0;
459 0 : bRet = sal_False;
460 : }
461 : }
462 247829 : return bRet;
463 : }
464 :
465 320824 : inline void SaxWriterHelper::FinishStartElement() throw( SAXException )
466 : {
467 320824 : if (!m_bStartElementFinished)
468 : {
469 32102 : mp_Sequence[nCurrentPos] = '>';
470 32102 : nCurrentPos++;
471 32102 : if (nCurrentPos == SEQUENCESIZE)
472 8 : nCurrentPos = writeSequence();
473 32102 : m_bStartElementFinished = sal_True;
474 : }
475 320824 : }
476 :
477 1112 : inline void SaxWriterHelper::insertIndentation(sal_uInt32 m_nLevel) throw( SAXException )
478 : {
479 1112 : FinishStartElement();
480 1112 : if (m_nLevel > 0)
481 : {
482 760 : if ((nCurrentPos + m_nLevel + 1) <= SEQUENCESIZE)
483 : {
484 760 : mp_Sequence[nCurrentPos] = LINEFEED;
485 760 : nLastLineFeedPos = nCurrentPos;
486 760 : nCurrentPos++;
487 760 : memset( &(mp_Sequence[nCurrentPos]) , 32 , m_nLevel );
488 760 : nCurrentPos += m_nLevel;
489 760 : if (nCurrentPos == SEQUENCESIZE)
490 0 : nCurrentPos = writeSequence();
491 : }
492 : else
493 : {
494 0 : sal_uInt32 nCount(m_nLevel + 1);
495 0 : sal_Int8* pBytes = new sal_Int8[nCount];
496 0 : pBytes[0] = LINEFEED;
497 0 : memset( &(pBytes[1]), 32, m_nLevel );
498 0 : AddBytes(mp_Sequence, nCurrentPos, pBytes, nCount);
499 0 : delete[] pBytes;
500 0 : nLastLineFeedPos = nCurrentPos - nCount;
501 0 : if (nCurrentPos == SEQUENCESIZE)
502 0 : nCurrentPos = writeSequence();
503 : }
504 : }
505 : else
506 : {
507 352 : mp_Sequence[nCurrentPos] = LINEFEED;
508 352 : nLastLineFeedPos = nCurrentPos;
509 352 : nCurrentPos++;
510 352 : if (nCurrentPos == SEQUENCESIZE)
511 0 : nCurrentPos = writeSequence();
512 : }
513 1112 : }
514 :
515 247829 : inline sal_Bool SaxWriterHelper::writeString( const OUString& rWriteOutString,
516 : sal_Bool bDoNormalization,
517 : sal_Bool bNormalizeWhitespace ) throw( SAXException )
518 : {
519 247829 : FinishStartElement();
520 : return convertToXML(rWriteOutString.getStr(),
521 : rWriteOutString.getLength(),
522 : bDoNormalization,
523 : bNormalizeWhitespace,
524 : mp_Sequence,
525 247829 : nCurrentPos);
526 : }
527 :
528 1259 : inline void SaxWriterHelper::startDocument() throw( SAXException )
529 : {
530 1259 : const char pc[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
531 1259 : const int nLen = strlen( pc );
532 1259 : if ((nCurrentPos + nLen) <= SEQUENCESIZE)
533 : {
534 1259 : memcpy( mp_Sequence, pc , nLen );
535 1259 : nCurrentPos += nLen;
536 : }
537 : else
538 : {
539 0 : AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)pc, nLen);
540 : }
541 : OSL_ENSURE(nCurrentPos <= SEQUENCESIZE, "not reset current position");
542 1259 : if (nCurrentPos == SEQUENCESIZE)
543 0 : nCurrentPos = writeSequence();
544 1259 : mp_Sequence[nCurrentPos] = LINEFEED;
545 1259 : nCurrentPos++;
546 1259 : if (nCurrentPos == SEQUENCESIZE)
547 0 : nCurrentPos = writeSequence();
548 1259 : }
549 :
550 39777 : inline SaxInvalidCharacterError SaxWriterHelper::startElement(const OUString& rName, const Reference< XAttributeList >& xAttribs) throw( SAXException )
551 : {
552 39777 : FinishStartElement();
553 :
554 : #ifdef DBG_UTIL
555 : m_DebugStartedElements.push(rName);
556 : ::std::set<OUString> DebugAttributes;
557 : #endif
558 :
559 39777 : mp_Sequence[nCurrentPos] = '<';
560 39777 : nCurrentPos++;
561 39777 : if (nCurrentPos == SEQUENCESIZE)
562 12 : nCurrentPos = writeSequence();
563 :
564 39777 : SaxInvalidCharacterError eRet(SAX_NONE);
565 39777 : if (!writeString(rName, sal_False, sal_False))
566 0 : eRet = SAX_ERROR;
567 :
568 39777 : sal_Int16 nAttribCount = xAttribs.is() ? static_cast<sal_Int16>(xAttribs->getLength()) : 0;
569 114820 : for(sal_Int16 i = 0 ; i < nAttribCount ; i++ )
570 : {
571 75043 : mp_Sequence[nCurrentPos] = ' ';
572 75043 : nCurrentPos++;
573 75043 : if (nCurrentPos == SEQUENCESIZE)
574 21 : nCurrentPos = writeSequence();
575 :
576 75043 : OUString const& rAttrName(xAttribs->getNameByIndex(i));
577 : #ifdef DBG_UTIL
578 : // Well-formedness constraint: Unique Att Spec
579 : assert(DebugAttributes.find(rAttrName) == DebugAttributes.end());
580 : DebugAttributes.insert(rAttrName);
581 : #endif
582 75043 : if (!writeString(rAttrName, sal_False, sal_False))
583 0 : eRet = SAX_ERROR;
584 :
585 75043 : mp_Sequence[nCurrentPos] = '=';
586 75043 : nCurrentPos++;
587 75043 : if (nCurrentPos == SEQUENCESIZE)
588 31 : nCurrentPos = writeSequence();
589 75043 : mp_Sequence[nCurrentPos] = '"';
590 75043 : nCurrentPos++;
591 75043 : if (nCurrentPos == SEQUENCESIZE)
592 21 : nCurrentPos = writeSequence();
593 :
594 75043 : if (!writeString(xAttribs->getValueByIndex( i ), sal_True, sal_True) &&
595 : !(eRet == SAX_ERROR))
596 0 : eRet = SAX_WARNING;
597 :
598 75043 : mp_Sequence[nCurrentPos] = '"';
599 75043 : nCurrentPos++;
600 75043 : if (nCurrentPos == SEQUENCESIZE)
601 16 : nCurrentPos = writeSequence();
602 75043 : }
603 :
604 39777 : m_bStartElementFinished = sal_False; // because the '>' character is not added,
605 : // because it is possible, that the "/>"
606 : // characters have to add
607 39777 : return eRet;
608 : }
609 :
610 39777 : inline sal_Bool SaxWriterHelper::FinishEmptyElement() throw( SAXException )
611 : {
612 39777 : if (m_bStartElementFinished)
613 32102 : return sal_False;
614 :
615 7675 : mp_Sequence[nCurrentPos] = '/';
616 7675 : nCurrentPos++;
617 7675 : if (nCurrentPos == SEQUENCESIZE)
618 10 : nCurrentPos = writeSequence();
619 7675 : mp_Sequence[nCurrentPos] = '>';
620 7675 : nCurrentPos++;
621 7675 : if (nCurrentPos == SEQUENCESIZE)
622 5 : nCurrentPos = writeSequence();
623 :
624 7675 : m_bStartElementFinished = sal_True;
625 :
626 7675 : return sal_True;
627 : }
628 :
629 32102 : inline sal_Bool SaxWriterHelper::endElement(const OUString& rName) throw( SAXException )
630 : {
631 32102 : FinishStartElement();
632 :
633 32102 : mp_Sequence[nCurrentPos] = '<';
634 32102 : nCurrentPos++;
635 32102 : if (nCurrentPos == SEQUENCESIZE)
636 6 : nCurrentPos = writeSequence();
637 32102 : mp_Sequence[nCurrentPos] = '/';
638 32102 : nCurrentPos++;
639 32102 : if (nCurrentPos == SEQUENCESIZE)
640 0 : nCurrentPos = writeSequence();
641 :
642 32102 : sal_Bool bRet(writeString( rName, sal_False, sal_False));
643 :
644 32102 : mp_Sequence[nCurrentPos] = '>';
645 32102 : nCurrentPos++;
646 32102 : if (nCurrentPos == SEQUENCESIZE)
647 9 : nCurrentPos = writeSequence();
648 :
649 32102 : return bRet;
650 : }
651 :
652 1259 : inline void SaxWriterHelper::endDocument() throw( SAXException )
653 : {
654 1259 : if (nCurrentPos > 0)
655 : {
656 1259 : m_Sequence.realloc(nCurrentPos);
657 1259 : nCurrentPos = writeSequence();
658 : //m_Sequence.realloc(SEQUENCESIZE);
659 : }
660 1259 : }
661 :
662 0 : inline void SaxWriterHelper::clearBuffer() throw( SAXException )
663 : {
664 0 : FinishStartElement();
665 0 : if (nCurrentPos > 0)
666 : {
667 0 : m_Sequence.realloc(nCurrentPos);
668 0 : nCurrentPos = writeSequence();
669 0 : m_Sequence.realloc(SEQUENCESIZE);
670 : // Be sure to update the array pointer after the reallocation.
671 0 : mp_Sequence = m_Sequence.getArray();
672 : }
673 0 : }
674 :
675 0 : inline sal_Bool SaxWriterHelper::processingInstruction(const OUString& rTarget, const OUString& rData) throw( SAXException )
676 : {
677 0 : FinishStartElement();
678 0 : mp_Sequence[nCurrentPos] = '<';
679 0 : nCurrentPos++;
680 0 : if (nCurrentPos == SEQUENCESIZE)
681 0 : nCurrentPos = writeSequence();
682 0 : mp_Sequence[nCurrentPos] = '?';
683 0 : nCurrentPos++;
684 0 : if (nCurrentPos == SEQUENCESIZE)
685 0 : nCurrentPos = writeSequence();
686 :
687 0 : sal_Bool bRet(writeString( rTarget, sal_False, sal_False ));
688 :
689 0 : mp_Sequence[nCurrentPos] = ' ';
690 0 : nCurrentPos++;
691 0 : if (nCurrentPos == SEQUENCESIZE)
692 0 : nCurrentPos = writeSequence();
693 :
694 0 : if (!writeString( rData, sal_False, sal_False ))
695 0 : bRet = sal_False;
696 :
697 0 : mp_Sequence[nCurrentPos] = '?';
698 0 : nCurrentPos++;
699 0 : if (nCurrentPos == SEQUENCESIZE)
700 0 : nCurrentPos = writeSequence();
701 0 : mp_Sequence[nCurrentPos] = '>';
702 0 : nCurrentPos++;
703 0 : if (nCurrentPos == SEQUENCESIZE)
704 0 : nCurrentPos = writeSequence();
705 :
706 0 : return bRet;
707 : }
708 :
709 0 : inline void SaxWriterHelper::startCDATA() throw( SAXException )
710 : {
711 0 : FinishStartElement();
712 0 : if ((nCurrentPos + 9) <= SEQUENCESIZE)
713 : {
714 0 : memcpy( &(mp_Sequence[nCurrentPos]), "<![CDATA[" , 9 );
715 0 : nCurrentPos += 9;
716 : }
717 : else
718 0 : AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)"<![CDATA[" , 9);
719 0 : if (nCurrentPos == SEQUENCESIZE)
720 0 : nCurrentPos = writeSequence();
721 0 : }
722 :
723 0 : inline void SaxWriterHelper::endCDATA() throw( SAXException )
724 : {
725 0 : FinishStartElement();
726 0 : if ((nCurrentPos + 3) <= SEQUENCESIZE)
727 : {
728 0 : memcpy( &(mp_Sequence[nCurrentPos]), "]]>" , 3 );
729 0 : nCurrentPos += 3;
730 : }
731 : else
732 0 : AddBytes(mp_Sequence, nCurrentPos, (sal_Int8*)"]]>" , 3);
733 0 : if (nCurrentPos == SEQUENCESIZE)
734 0 : nCurrentPos = writeSequence();
735 0 : }
736 :
737 4 : inline sal_Bool SaxWriterHelper::comment(const OUString& rComment) throw( SAXException )
738 : {
739 4 : FinishStartElement();
740 4 : mp_Sequence[nCurrentPos] = '<';
741 4 : nCurrentPos++;
742 4 : if (nCurrentPos == SEQUENCESIZE)
743 0 : nCurrentPos = writeSequence();
744 4 : mp_Sequence[nCurrentPos] = '!';
745 4 : nCurrentPos++;
746 4 : if (nCurrentPos == SEQUENCESIZE)
747 0 : nCurrentPos = writeSequence();
748 4 : mp_Sequence[nCurrentPos] = '-';
749 4 : nCurrentPos++;
750 4 : if (nCurrentPos == SEQUENCESIZE)
751 0 : nCurrentPos = writeSequence();
752 4 : mp_Sequence[nCurrentPos] = '-';
753 4 : nCurrentPos++;
754 4 : if (nCurrentPos == SEQUENCESIZE)
755 0 : nCurrentPos = writeSequence();
756 :
757 4 : sal_Bool bRet(writeString( rComment, sal_False, sal_False));
758 :
759 4 : mp_Sequence[nCurrentPos] = '-';
760 4 : nCurrentPos++;
761 4 : if (nCurrentPos == SEQUENCESIZE)
762 0 : nCurrentPos = writeSequence();
763 4 : mp_Sequence[nCurrentPos] = '-';
764 4 : nCurrentPos++;
765 4 : if (nCurrentPos == SEQUENCESIZE)
766 0 : nCurrentPos = writeSequence();
767 4 : mp_Sequence[nCurrentPos] = '>';
768 4 : nCurrentPos++;
769 4 : if (nCurrentPos == SEQUENCESIZE)
770 1 : nCurrentPos = writeSequence();
771 :
772 4 : return bRet;
773 : }
774 :
775 0 : inline sal_Int32 calcXMLByteLength( const sal_Unicode *pStr, sal_Int32 nStrLen,
776 : sal_Bool bDoNormalization,
777 : sal_Bool bNormalizeWhitespace )
778 : {
779 0 : sal_Int32 nOutputLength = 0;
780 0 : sal_uInt32 nSurrogate = 0;
781 :
782 0 : for( sal_Int32 i = 0 ; i < nStrLen ; i++ )
783 : {
784 0 : sal_uInt16 c = pStr[i];
785 0 : if( !IsInvalidChar(c) && (c >= 0x0001) && (c <= 0x007F) )
786 : {
787 0 : if( bDoNormalization )
788 : {
789 0 : switch( c )
790 : {
791 : case '&': // resemble to &
792 0 : nOutputLength +=5;
793 0 : break;
794 : case '<': // <
795 : case '>': // >
796 0 : nOutputLength +=4;
797 0 : break;
798 : case 39: // 39 == ''', '
799 : case '"': // "
800 : case 13: // 
801 0 : nOutputLength += 6;
802 0 : break;
803 :
804 : case 10: // 

805 : case 9: // 	
806 0 : if( bNormalizeWhitespace )
807 : {
808 0 : nOutputLength += 6; //
809 : }
810 : else
811 : {
812 0 : nOutputLength ++;
813 : }
814 0 : break;
815 : default:
816 0 : nOutputLength ++;
817 : }
818 : }
819 : else
820 : {
821 0 : nOutputLength ++;
822 : }
823 : }
824 0 : else if( c >= 0xd800 && c < 0xdc00 )
825 : {
826 : // save surrogate
827 0 : nSurrogate = ( ( c & 0x03ff ) + 0x0040 );
828 : }
829 0 : else if( c >= 0xdc00 && c < 0xe000 )
830 : {
831 : // 2. surrogate: write as UTF-8 (if range is OK
832 0 : nSurrogate = ( nSurrogate << 10 ) | ( c & 0x03ff );
833 0 : if( nSurrogate >= 0x00010000 && nSurrogate <= 0x0010FFFF )
834 0 : nOutputLength += 4;
835 0 : nSurrogate = 0;
836 : }
837 0 : else if( c > 0x07FF )
838 : {
839 0 : nOutputLength += 3;
840 : }
841 : else
842 : {
843 0 : nOutputLength += 2;
844 : }
845 :
846 : // surrogate processing
847 0 : if( ( nSurrogate != 0 ) && !( c >= 0xd800 && c < 0xdc00 ) )
848 0 : nSurrogate = 0;
849 : }
850 :
851 0 : return nOutputLength;
852 : }
853 :
854 : /** returns position of first ascii 10 within the string, -1 when no 10 in string.
855 : */
856 0 : static inline sal_Int32 getFirstLineBreak( const OUString & str ) throw ()
857 : {
858 0 : const sal_Unicode *pSource = str.getStr();
859 0 : sal_Int32 nLen = str.getLength();
860 :
861 0 : for( int n = 0; n < nLen ; n ++ )
862 : {
863 0 : if( LINEFEED == pSource[n] ) {
864 0 : return n;
865 : }
866 : }
867 0 : return -1;
868 : }
869 :
870 : /** returns position of last ascii 10 within sequence, -1 when no 10 in string.
871 : */
872 : static inline sal_Int32 getLastLineBreak( const Sequence<sal_Int8> & seq) throw ()
873 : {
874 : const sal_Int8 *pSource = seq.getConstArray();
875 : sal_Int32 nLen = seq.getLength();
876 :
877 : for( int n = nLen-1; n >= 0 ; n -- )
878 : {
879 : if( LINEFEED == pSource[n] ) {
880 : return n;
881 : }
882 : }
883 : return -1;
884 : }
885 :
886 :
887 : class SAXWriter :
888 : public WeakImplHelper2<
889 : XWriter,
890 : XServiceInfo >
891 : {
892 : public:
893 1217 : SAXWriter( ) :
894 : m_seqStartElement(),
895 : mp_SaxWriterHelper( NULL ),
896 : m_bForceLineBreak(sal_False),
897 1217 : m_bAllowLineBreak(sal_False)
898 1217 : {}
899 2434 : ~SAXWriter()
900 2434 : {
901 1217 : delete mp_SaxWriterHelper;
902 2434 : }
903 :
904 : public: // XActiveDataSource
905 1259 : virtual void SAL_CALL setOutputStream(const Reference< XOutputStream > & aStream)
906 : throw (RuntimeException)
907 : {
908 : // temporary: set same stream again to clear buffer
909 1259 : if ( m_out == aStream && mp_SaxWriterHelper && m_bDocStarted )
910 0 : mp_SaxWriterHelper->clearBuffer();
911 : else
912 : {
913 :
914 1259 : m_out = aStream;
915 1259 : delete mp_SaxWriterHelper;
916 1259 : mp_SaxWriterHelper = new SaxWriterHelper(m_out);
917 1259 : m_bDocStarted = sal_False;
918 1259 : m_nLevel = 0;
919 1259 : m_bIsCDATA = sal_False;
920 :
921 : }
922 1259 : }
923 0 : virtual Reference< XOutputStream > SAL_CALL getOutputStream(void)
924 : throw(RuntimeException)
925 0 : { return m_out; }
926 :
927 : public: // XDocumentHandler
928 : virtual void SAL_CALL startDocument(void)
929 : throw(SAXException, RuntimeException);
930 :
931 : virtual void SAL_CALL endDocument(void)
932 : throw(SAXException, RuntimeException);
933 :
934 : virtual void SAL_CALL startElement(const OUString& aName,
935 : const Reference< XAttributeList > & xAttribs)
936 : throw (SAXException, RuntimeException);
937 :
938 : virtual void SAL_CALL endElement(const OUString& aName)
939 : throw(SAXException, RuntimeException);
940 :
941 : virtual void SAL_CALL characters(const OUString& aChars)
942 : throw(SAXException, RuntimeException);
943 :
944 : virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces)
945 : throw(SAXException, RuntimeException);
946 : virtual void SAL_CALL processingInstruction(const OUString& aTarget,
947 : const OUString& aData)
948 : throw(SAXException, RuntimeException);
949 : virtual void SAL_CALL setDocumentLocator(const Reference< XLocator > & xLocator)
950 : throw(SAXException, RuntimeException);
951 :
952 : public: // XExtendedDocumentHandler
953 : virtual void SAL_CALL startCDATA(void) throw(SAXException, RuntimeException);
954 : virtual void SAL_CALL endCDATA(void) throw(RuntimeException);
955 : virtual void SAL_CALL comment(const OUString& sComment)
956 : throw(SAXException, RuntimeException);
957 : virtual void SAL_CALL unknown(const OUString& sString)
958 : throw(SAXException, RuntimeException);
959 : virtual void SAL_CALL allowLineBreak(void)
960 : throw(SAXException,RuntimeException);
961 :
962 : public: // XServiceInfo
963 : OUString SAL_CALL getImplementationName() throw();
964 : Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw();
965 : sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw();
966 :
967 : private:
968 :
969 : void writeSequence( const Sequence<sal_Int8> & seq );
970 : sal_Int32 getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurrence ) throw();
971 :
972 : Reference< XOutputStream > m_out;
973 : Sequence < sal_Int8 > m_seqStartElement;
974 : SaxWriterHelper* mp_SaxWriterHelper;
975 :
976 : // Status information
977 : sal_Bool m_bDocStarted : 1;
978 : sal_Bool m_bIsCDATA : 1;
979 : sal_Bool m_bForceLineBreak : 1;
980 : sal_Bool m_bAllowLineBreak : 1;
981 : sal_Int32 m_nLevel;
982 : };
983 :
984 :
985 : //--------------------------------------
986 : // the extern interface
987 : //---------------------------------------
988 1217 : Reference < XInterface > SAL_CALL SaxWriter_CreateInstance(
989 : SAL_UNUSED_PARAMETER const Reference < XMultiServiceFactory > & )
990 : throw (Exception)
991 : {
992 1217 : SAXWriter *p = new SAXWriter;
993 1217 : return Reference< XInterface > ( (static_cast< OWeakObject * >(p)) );
994 : }
995 :
996 23 : OUString SaxWriter_getServiceName() throw()
997 : {
998 23 : return OUString("com.sun.star.xml.sax.Writer");
999 : }
1000 :
1001 23 : OUString SaxWriter_getImplementationName() throw()
1002 : {
1003 23 : return OUString("com.sun.star.extensions.xml.sax.Writer");
1004 : }
1005 :
1006 23 : Sequence< OUString > SaxWriter_getSupportedServiceNames(void) throw()
1007 : {
1008 23 : Sequence<OUString> aRet(1);
1009 23 : aRet.getArray()[0] = SaxWriter_getServiceName();
1010 23 : return aRet;
1011 : }
1012 :
1013 :
1014 97743 : sal_Int32 SAXWriter::getIndentPrefixLength( sal_Int32 nFirstLineBreakOccurrence ) throw()
1015 : {
1016 97743 : sal_Int32 nLength =-1;
1017 97743 : if (mp_SaxWriterHelper)
1018 : {
1019 98855 : if ( m_bForceLineBreak ||
1020 0 : (m_bAllowLineBreak &&
1021 0 : ((nFirstLineBreakOccurrence + mp_SaxWriterHelper->GetLastColumnCount()) > MAXCOLUMNCOUNT)) )
1022 1112 : nLength = m_nLevel;
1023 : }
1024 97743 : m_bForceLineBreak = sal_False;
1025 97743 : m_bAllowLineBreak = sal_False;
1026 97743 : return nLength;
1027 : }
1028 :
1029 0 : static inline sal_Bool isFirstCharWhitespace( const sal_Unicode *p ) throw()
1030 : {
1031 0 : return *p == ' ';
1032 : }
1033 :
1034 :
1035 : // XServiceInfo
1036 0 : OUString SAXWriter::getImplementationName() throw()
1037 : {
1038 0 : return SaxWriter_getImplementationName();
1039 : }
1040 :
1041 : // XServiceInfo
1042 0 : sal_Bool SAXWriter::supportsService(const OUString& ServiceName) throw()
1043 : {
1044 0 : Sequence< OUString > aSNL = getSupportedServiceNames();
1045 0 : const OUString * pArray = aSNL.getConstArray();
1046 :
1047 0 : for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
1048 0 : if( pArray[i] == ServiceName )
1049 0 : return sal_True;
1050 :
1051 0 : return sal_False;
1052 : }
1053 :
1054 : // XServiceInfo
1055 0 : Sequence< OUString > SAXWriter::getSupportedServiceNames(void) throw ()
1056 : {
1057 0 : Sequence<OUString> seq(1);
1058 0 : seq.getArray()[0] = SaxWriter_getServiceName();
1059 0 : return seq;
1060 : }
1061 :
1062 :
1063 :
1064 1259 : void SAXWriter::startDocument() throw(SAXException, RuntimeException )
1065 : {
1066 1259 : if( m_bDocStarted || ! m_out.is() || !mp_SaxWriterHelper ) {
1067 0 : throw SAXException();
1068 : }
1069 1259 : m_bDocStarted = sal_True;
1070 1259 : mp_SaxWriterHelper->startDocument();
1071 1259 : }
1072 :
1073 :
1074 1259 : void SAXWriter::endDocument(void) throw(SAXException, RuntimeException)
1075 : {
1076 1259 : if( ! m_bDocStarted )
1077 : {
1078 : throw SAXException(
1079 : OUString("endDocument called before startDocument"),
1080 0 : Reference< XInterface >() , Any() );
1081 : }
1082 1259 : if( m_nLevel ) {
1083 : throw SAXException(
1084 : OUString("unexpected end of document"),
1085 0 : Reference< XInterface >() , Any() );
1086 : }
1087 1259 : mp_SaxWriterHelper->endDocument();
1088 : try
1089 : {
1090 1259 : m_out->closeOutput();
1091 : }
1092 0 : catch (const IOException & e)
1093 : {
1094 0 : Any a;
1095 0 : a <<= e;
1096 : throw SAXException(
1097 : OUString("IO exception during closing the IO Stream"),
1098 : Reference< XInterface > (),
1099 0 : a );
1100 : }
1101 1259 : }
1102 :
1103 :
1104 39777 : void SAXWriter::startElement(const OUString& aName, const Reference< XAttributeList >& xAttribs)
1105 : throw(SAXException, RuntimeException)
1106 : {
1107 39777 : if( ! m_bDocStarted )
1108 : {
1109 0 : SAXException except;
1110 0 : except.Message = OUString( "startElement called before startDocument" );
1111 0 : throw except;
1112 : }
1113 39777 : if( m_bIsCDATA )
1114 : {
1115 0 : SAXException except;
1116 0 : except.Message = OUString( "startElement call not allowed with CDATA sections" );
1117 0 : throw except;
1118 : }
1119 :
1120 39777 : sal_Int32 nLength(0);
1121 39777 : if (m_bAllowLineBreak)
1122 : {
1123 0 : sal_Int32 nAttribCount = xAttribs.is() ? xAttribs->getLength() : 0;
1124 :
1125 0 : nLength ++; // "<"
1126 : nLength += calcXMLByteLength( aName.getStr() , aName.getLength(),
1127 0 : sal_False, sal_False ); // the tag name
1128 :
1129 : sal_Int16 n;
1130 0 : for( n = 0 ; n < static_cast<sal_Int16>(nAttribCount) ; n ++ ) {
1131 0 : nLength ++; // " "
1132 0 : OUString tmp = xAttribs->getNameByIndex( n );
1133 :
1134 0 : nLength += calcXMLByteLength( tmp.getStr() , tmp.getLength() , sal_False, sal_False );
1135 :
1136 0 : nLength += 2; // ="
1137 :
1138 0 : tmp = xAttribs->getValueByIndex( n );
1139 :
1140 0 : nLength += calcXMLByteLength( tmp.getStr(), tmp.getLength(), sal_True, sal_True );
1141 :
1142 0 : nLength += 1; // "
1143 0 : }
1144 :
1145 0 : nLength ++; // '>'
1146 : }
1147 :
1148 : // Is there a new indentation necesarry ?
1149 39777 : sal_Int32 nPrefix(getIndentPrefixLength( nLength ));
1150 :
1151 : // write into sequence
1152 39777 : if( nPrefix >= 0 )
1153 751 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1154 :
1155 39777 : SaxInvalidCharacterError eRet(mp_SaxWriterHelper->startElement(aName, xAttribs));
1156 :
1157 39777 : m_nLevel++;
1158 :
1159 39777 : if (eRet == SAX_WARNING)
1160 : {
1161 0 : SAXInvalidCharacterException except;
1162 0 : except.Message = OUString( "Invalid character during XML-Export in a attribute value" );
1163 0 : throw except;
1164 : }
1165 39777 : else if (eRet == SAX_ERROR)
1166 : {
1167 0 : SAXException except;
1168 0 : except.Message = OUString( "Invalid character during XML-Export" );
1169 0 : throw except;
1170 : }
1171 39777 : }
1172 :
1173 39777 : void SAXWriter::endElement(const OUString& aName) throw (SAXException, RuntimeException)
1174 : {
1175 39777 : if( ! m_bDocStarted ) {
1176 0 : throw SAXException ();
1177 : }
1178 39777 : m_nLevel --;
1179 :
1180 39777 : if( m_nLevel < 0 ) {
1181 0 : throw SAXException();
1182 : }
1183 39777 : sal_Bool bRet(sal_True);
1184 :
1185 : // check here because Helper's endElement is not always called
1186 : #ifdef DBG_UTIL
1187 : assert(!mp_SaxWriterHelper->m_DebugStartedElements.empty());
1188 : // Well-formedness constraint: Element Type Match
1189 : assert(aName == mp_SaxWriterHelper->m_DebugStartedElements.top());
1190 : mp_SaxWriterHelper->m_DebugStartedElements.pop();
1191 : #endif
1192 :
1193 39777 : if( mp_SaxWriterHelper->FinishEmptyElement() )
1194 7675 : m_bForceLineBreak = sal_False;
1195 : else
1196 : {
1197 : // only ascii chars allowed
1198 32102 : sal_Int32 nLength(0);
1199 32102 : if (m_bAllowLineBreak)
1200 0 : nLength = 3 + calcXMLByteLength( aName.getStr(), aName.getLength(), sal_False, sal_False );
1201 32102 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1202 :
1203 32102 : if( nPrefix >= 0 )
1204 361 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1205 :
1206 32102 : bRet = mp_SaxWriterHelper->endElement(aName);
1207 : }
1208 :
1209 39777 : if (!bRet)
1210 : {
1211 0 : SAXException except;
1212 0 : except.Message = OUString( "Invalid character during XML-Export" );
1213 0 : throw except;
1214 : }
1215 39777 : }
1216 :
1217 25873 : void SAXWriter::characters(const OUString& aChars) throw(SAXException, RuntimeException)
1218 : {
1219 25873 : if( ! m_bDocStarted )
1220 : {
1221 0 : SAXException except;
1222 0 : except.Message = OUString( "characters method called before startDocument" );
1223 0 : throw except;
1224 : }
1225 :
1226 25873 : sal_Bool bThrowException(sal_False);
1227 25873 : if( !aChars.isEmpty() )
1228 : {
1229 25852 : if( m_bIsCDATA )
1230 0 : bThrowException = !mp_SaxWriterHelper->writeString( aChars, sal_False, sal_False );
1231 : else
1232 : {
1233 : // Note : nFirstLineBreakOccurrence is not exact, because we don't know, how
1234 : // many 2 and 3 byte chars are inbetween. However this whole stuff
1235 : // is eitherway for pretty printing only, so it does not need to be exact.
1236 25852 : sal_Int32 nLength(0);
1237 25852 : sal_Int32 nIndentPrefix(-1);
1238 25852 : if (m_bAllowLineBreak)
1239 : {
1240 0 : sal_Int32 nFirstLineBreakOccurrence = getFirstLineBreak( aChars );
1241 :
1242 : nLength = calcXMLByteLength( aChars.getStr(), aChars.getLength(),
1243 0 : ! m_bIsCDATA , sal_False );
1244 : nIndentPrefix = getIndentPrefixLength(
1245 0 : nFirstLineBreakOccurrence >= 0 ? nFirstLineBreakOccurrence : nLength );
1246 : }
1247 : else
1248 25852 : nIndentPrefix = getIndentPrefixLength(nLength);
1249 :
1250 : // insert indentation
1251 25852 : if( nIndentPrefix >= 0 )
1252 : {
1253 0 : if( isFirstCharWhitespace( aChars.getStr() ) )
1254 0 : mp_SaxWriterHelper->insertIndentation( nIndentPrefix - 1 );
1255 : else
1256 0 : mp_SaxWriterHelper->insertIndentation( nIndentPrefix );
1257 : }
1258 25852 : bThrowException = !mp_SaxWriterHelper->writeString(aChars, sal_True , sal_False);
1259 : }
1260 : }
1261 25873 : if (bThrowException)
1262 : {
1263 0 : SAXInvalidCharacterException except;
1264 0 : except.Message = OUString( "Invalid character during XML-Export" );
1265 0 : throw except;
1266 : }
1267 25873 : }
1268 :
1269 :
1270 2644 : void SAXWriter::ignorableWhitespace(const OUString&) throw(SAXException, RuntimeException)
1271 : {
1272 2644 : if( ! m_bDocStarted )
1273 : {
1274 0 : throw SAXException ();
1275 : }
1276 :
1277 2644 : m_bForceLineBreak = sal_True;
1278 2644 : }
1279 :
1280 0 : void SAXWriter::processingInstruction(const OUString& aTarget, const OUString& aData)
1281 : throw (SAXException, RuntimeException)
1282 : {
1283 0 : if( ! m_bDocStarted || m_bIsCDATA )
1284 : {
1285 0 : throw SAXException();
1286 : }
1287 :
1288 0 : sal_Int32 nLength(0);
1289 0 : if (m_bAllowLineBreak)
1290 : {
1291 0 : nLength = 2; // "<?"
1292 0 : nLength += calcXMLByteLength( aTarget.getStr(), aTarget.getLength(), sal_False, sal_False );
1293 :
1294 0 : nLength += 1; // " "
1295 :
1296 0 : nLength += calcXMLByteLength( aData.getStr(), aData.getLength(), sal_False, sal_False );
1297 :
1298 0 : nLength += 2; // "?>"
1299 : }
1300 :
1301 0 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1302 :
1303 0 : if( nPrefix >= 0 )
1304 0 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1305 :
1306 0 : if (!mp_SaxWriterHelper->processingInstruction(aTarget, aData))
1307 : {
1308 0 : SAXException except;
1309 0 : except.Message = OUString( "Invalid character during XML-Export" );
1310 0 : throw except;
1311 : }
1312 0 : }
1313 :
1314 :
1315 0 : void SAXWriter::setDocumentLocator(const Reference< XLocator >&)
1316 : throw (SAXException, RuntimeException)
1317 : {
1318 :
1319 0 : }
1320 :
1321 0 : void SAXWriter::startCDATA(void) throw(SAXException, RuntimeException)
1322 : {
1323 0 : if( ! m_bDocStarted || m_bIsCDATA)
1324 : {
1325 0 : throw SAXException ();
1326 : }
1327 :
1328 0 : sal_Int32 nLength = 9;
1329 0 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1330 0 : if( nPrefix >= 0 )
1331 0 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1332 :
1333 0 : mp_SaxWriterHelper->startCDATA();
1334 :
1335 0 : m_bIsCDATA = sal_True;
1336 0 : }
1337 :
1338 0 : void SAXWriter::endCDATA(void) throw (RuntimeException)
1339 : {
1340 0 : if( ! m_bDocStarted || ! m_bIsCDATA)
1341 : {
1342 0 : SAXException except;
1343 0 : except.Message = OUString( "endCDATA was called without startCDATA" );
1344 0 : throw except;
1345 : }
1346 :
1347 0 : sal_Int32 nLength = 3;
1348 0 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1349 0 : if( nPrefix >= 0 )
1350 0 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1351 :
1352 0 : mp_SaxWriterHelper->endCDATA();
1353 :
1354 0 : m_bIsCDATA = sal_False;
1355 0 : }
1356 :
1357 :
1358 4 : void SAXWriter::comment(const OUString& sComment) throw(SAXException, RuntimeException)
1359 : {
1360 4 : if( ! m_bDocStarted || m_bIsCDATA )
1361 : {
1362 0 : throw SAXException();
1363 : }
1364 :
1365 4 : sal_Int32 nLength(0);
1366 4 : if (m_bAllowLineBreak)
1367 : {
1368 0 : nLength = 4; // "<!--"
1369 0 : nLength += calcXMLByteLength( sComment.getStr(), sComment.getLength(), sal_False, sal_False);
1370 :
1371 0 : nLength += 3;
1372 : }
1373 :
1374 4 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1375 4 : if( nPrefix >= 0 )
1376 0 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1377 :
1378 4 : if (!mp_SaxWriterHelper->comment(sComment))
1379 : {
1380 0 : SAXException except;
1381 0 : except.Message = OUString( "Invalid character during XML-Export" );
1382 0 : throw except;
1383 : }
1384 4 : }
1385 :
1386 :
1387 0 : void SAXWriter::allowLineBreak( ) throw ( SAXException , RuntimeException)
1388 : {
1389 0 : if( ! m_bDocStarted || m_bAllowLineBreak ) {
1390 0 : throw SAXException();
1391 : }
1392 :
1393 0 : m_bAllowLineBreak = sal_True;
1394 0 : }
1395 :
1396 8 : void SAXWriter::unknown(const OUString& sString) throw (SAXException, RuntimeException)
1397 : {
1398 :
1399 8 : if( ! m_bDocStarted )
1400 : {
1401 0 : throw SAXException ();
1402 : }
1403 8 : if( m_bIsCDATA )
1404 : {
1405 0 : throw SAXException();
1406 : }
1407 :
1408 8 : if( sString.matchAsciiL( "<?xml", 5 ) )
1409 8 : return;
1410 :
1411 8 : sal_Int32 nLength(0);
1412 8 : if (m_bAllowLineBreak)
1413 0 : nLength = calcXMLByteLength( sString.getStr(), sString.getLength(), sal_False, sal_False );
1414 :
1415 8 : sal_Int32 nPrefix = getIndentPrefixLength( nLength );
1416 8 : if( nPrefix >= 0 )
1417 0 : mp_SaxWriterHelper->insertIndentation( nPrefix );
1418 :
1419 8 : if (!mp_SaxWriterHelper->writeString( sString, sal_False, sal_False))
1420 : {
1421 0 : SAXException except;
1422 0 : except.Message = OUString( "Invalid character during XML-Export" );
1423 0 : throw except;
1424 : }
1425 : }
1426 :
1427 : }
1428 :
1429 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|