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 "fastserializer.hxx"
21 : #include <rtl/ustrbuf.hxx>
22 :
23 : #include <comphelper/sequenceasvector.hxx>
24 :
25 : #include <com/sun/star/xml/Attribute.hpp>
26 : #include <com/sun/star/xml/FastAttribute.hpp>
27 : #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
28 :
29 : #include <string.h>
30 :
31 : #if DEBUG
32 : #include <iostream>
33 : #endif
34 :
35 : using ::comphelper::SequenceAsVector;
36 : using ::rtl::OString;
37 : using ::rtl::OUString;
38 : using ::rtl::OUStringBuffer;
39 : using ::rtl::OUStringToOString;
40 : using ::com::sun::star::uno::Reference;
41 : using ::com::sun::star::uno::RuntimeException;
42 : using ::com::sun::star::uno::Sequence;
43 : using ::com::sun::star::uno::toUnoSequence;
44 : using ::com::sun::star::xml::FastAttribute;
45 : using ::com::sun::star::xml::Attribute;
46 : using ::com::sun::star::xml::sax::SAXException;
47 : using ::com::sun::star::xml::sax::XFastAttributeList;
48 : using ::com::sun::star::io::XOutputStream;
49 : using ::com::sun::star::io::NotConnectedException;
50 : using ::com::sun::star::io::IOException;
51 : using ::com::sun::star::io::BufferSizeExceededException;
52 :
53 : #define HAS_NAMESPACE(x) ((x & 0xffff0000) != 0)
54 : #define NAMESPACE(x) (x >> 16)
55 : #define TOKEN(x) (x & 0xffff)
56 :
57 : namespace sax_fastparser {
58 151 : FastSaxSerializer::FastSaxSerializer( )
59 : : mxOutputStream()
60 : , mxFastTokenHandler()
61 : , maMarkStack()
62 : , maClosingBracket((const sal_Int8 *)">", 1)
63 : , maSlashAndClosingBracket((const sal_Int8 *)"/>", 2)
64 : , maColon((const sal_Int8 *)":", 1)
65 : , maOpeningBracket((const sal_Int8 *)"<", 1)
66 : , maOpeningBracketAndSlash((const sal_Int8 *)"</", 2)
67 : , maQuote((const sal_Int8 *)"\"", 1)
68 : , maEqualSignAndQuote((const sal_Int8 *)"=\"", 2)
69 151 : , maSpace((const sal_Int8 *)" ", 1)
70 : {
71 151 : }
72 151 : FastSaxSerializer::~FastSaxSerializer() {}
73 :
74 151 : void SAL_CALL FastSaxSerializer::startDocument( ) throw (SAXException, RuntimeException)
75 : {
76 : assert(mxOutputStream.is()); // cannot do anything without that
77 151 : if (!mxOutputStream.is())
78 151 : return;
79 151 : rtl::ByteSequence aXmlHeader((const sal_Int8*) "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", 56);
80 151 : writeBytes(toUnoSequence(aXmlHeader));
81 : }
82 :
83 6055 : OUString FastSaxSerializer::escapeXml( const OUString& s )
84 : {
85 6055 : ::rtl::OUStringBuffer sBuf( s.getLength() );
86 6055 : const sal_Unicode* pStr = s.getStr();
87 6055 : sal_Int32 nLen = s.getLength();
88 60755 : for( sal_Int32 i = 0; i < nLen; ++i)
89 : {
90 54700 : sal_Unicode c = pStr[ i ];
91 54700 : switch( c )
92 : {
93 4 : case '<': sBuf.appendAscii( "<" ); break;
94 0 : case '>': sBuf.appendAscii( ">" ); break;
95 0 : case '&': sBuf.appendAscii( "&" ); break;
96 1 : case '\'': sBuf.appendAscii( "'" ); break;
97 8 : case '"': sBuf.appendAscii( """ ); break;
98 0 : case '\n': sBuf.appendAscii( " " ); break;
99 0 : case '\r': sBuf.appendAscii( " " ); break;
100 54687 : default: sBuf.append( c ); break;
101 : }
102 : }
103 6055 : return sBuf.makeStringAndClear();
104 : }
105 :
106 6424 : void FastSaxSerializer::write( const OUString& s )
107 : {
108 6424 : OString sOutput( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) );
109 : writeBytes( Sequence< sal_Int8 >(
110 6424 : reinterpret_cast< const sal_Int8*>( sOutput.getStr() ),
111 12848 : sOutput.getLength() ) );
112 6424 : }
113 :
114 151 : void SAL_CALL FastSaxSerializer::endDocument( ) throw (SAXException, RuntimeException)
115 : {
116 151 : if (!mxOutputStream.is())
117 0 : return;
118 : }
119 :
120 14140 : void SAL_CALL FastSaxSerializer::writeId( ::sal_Int32 nElement )
121 : {
122 14140 : if( HAS_NAMESPACE( nElement ) ) {
123 11708 : writeBytes(mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)));
124 11708 : writeBytes(toUnoSequence(maColon));
125 11708 : writeBytes(mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)));
126 : } else
127 2432 : writeBytes(mxFastTokenHandler->getUTF8Identifier(nElement));
128 14140 : }
129 :
130 2923 : void SAL_CALL FastSaxSerializer::startFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
131 : throw (SAXException, RuntimeException)
132 : {
133 2923 : if (!mxOutputStream.is())
134 2923 : return;
135 :
136 2923 : if ( !maMarkStack.empty() )
137 1229 : maMarkStack.top()->setCurrentElement( Element );
138 :
139 2923 : writeBytes(toUnoSequence(maOpeningBracket));
140 :
141 2923 : writeId(Element);
142 2923 : writeFastAttributeList(Attribs);
143 :
144 2923 : writeBytes(toUnoSequence(maClosingBracket));
145 : }
146 :
147 2924 : void SAL_CALL FastSaxSerializer::endFastElement( ::sal_Int32 Element )
148 : throw (SAXException, RuntimeException)
149 : {
150 2924 : if (!mxOutputStream.is())
151 2924 : return;
152 :
153 2924 : writeBytes(toUnoSequence(maOpeningBracketAndSlash));
154 :
155 2924 : writeId(Element);
156 :
157 2924 : writeBytes(toUnoSequence(maClosingBracket));
158 : }
159 :
160 2550 : void SAL_CALL FastSaxSerializer::singleFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
161 : throw (SAXException, RuntimeException)
162 : {
163 2550 : if (!mxOutputStream.is())
164 2550 : return;
165 :
166 2550 : if ( !maMarkStack.empty() )
167 1162 : maMarkStack.top()->setCurrentElement( Element );
168 :
169 2550 : writeBytes(toUnoSequence(maOpeningBracket));
170 :
171 2550 : writeId(Element);
172 2550 : writeFastAttributeList(Attribs);
173 :
174 2550 : writeBytes(toUnoSequence(maSlashAndClosingBracket));
175 : }
176 :
177 707 : void SAL_CALL FastSaxSerializer::characters( const OUString& aChars )
178 : throw (SAXException, RuntimeException)
179 : {
180 707 : if (!mxOutputStream.is())
181 707 : return;
182 :
183 707 : write( aChars );
184 : }
185 :
186 151 : void SAL_CALL FastSaxSerializer::setOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream )
187 : throw (::com::sun::star::uno::RuntimeException)
188 : {
189 151 : mxOutputStream = xOutputStream;
190 : assert(mxOutputStream.is()); // cannot do anything without that
191 151 : }
192 :
193 151 : void SAL_CALL FastSaxSerializer::setFastTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xFastTokenHandler )
194 : throw (::com::sun::star::uno::RuntimeException)
195 : {
196 151 : mxFastTokenHandler = xFastTokenHandler;
197 151 : }
198 5473 : void FastSaxSerializer::writeFastAttributeList( const Reference< XFastAttributeList >& Attribs )
199 : {
200 5473 : Sequence< Attribute > aAttrSeq = Attribs->getUnknownAttributes();
201 5473 : const Attribute *pAttr = aAttrSeq.getConstArray();
202 5473 : sal_Int32 nAttrLength = aAttrSeq.getLength();
203 5473 : for (sal_Int32 i = 0; i < nAttrLength; i++)
204 : {
205 0 : writeBytes(toUnoSequence(maSpace));
206 :
207 0 : write(pAttr[i].Name);
208 0 : writeBytes(toUnoSequence(maEqualSignAndQuote));
209 0 : write(escapeXml(pAttr[i].Value));
210 0 : writeBytes(toUnoSequence(maQuote));
211 : }
212 :
213 5473 : Sequence< FastAttribute > aFastAttrSeq = Attribs->getFastAttributes();
214 5473 : const FastAttribute *pFastAttr = aFastAttrSeq.getConstArray();
215 5473 : sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
216 11190 : for (sal_Int32 j = 0; j < nFastAttrLength; j++)
217 : {
218 5717 : writeBytes(toUnoSequence(maSpace));
219 :
220 5717 : sal_Int32 nToken = pFastAttr[j].Token;
221 5717 : writeId(nToken);
222 :
223 5717 : writeBytes(toUnoSequence(maEqualSignAndQuote));
224 :
225 5717 : write(escapeXml(Attribs->getValue(pFastAttr[j].Token)));
226 :
227 5717 : writeBytes(toUnoSequence(maQuote));
228 5473 : }
229 5473 : }
230 :
231 1191 : void FastSaxSerializer::mark( Int32Sequence aOrder )
232 : {
233 1191 : if ( aOrder.hasElements() )
234 : {
235 537 : boost::shared_ptr< ForMerge > pSort( new ForSort( aOrder ) );
236 537 : maMarkStack.push( pSort );
237 : }
238 : else
239 : {
240 654 : boost::shared_ptr< ForMerge > pMerge( new ForMerge( ) );
241 654 : maMarkStack.push( pMerge );
242 : }
243 1191 : }
244 :
245 1191 : void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
246 : {
247 1191 : if ( maMarkStack.empty() )
248 : return;
249 :
250 1191 : if ( maMarkStack.size() == 1 )
251 : {
252 428 : mxOutputStream->writeBytes( maMarkStack.top()->getData() );
253 428 : maMarkStack.pop();
254 : return;
255 : }
256 :
257 763 : const Int8Sequence aMerge( maMarkStack.top()->getData() );
258 763 : maMarkStack.pop();
259 :
260 763 : switch ( eMergeType )
261 : {
262 415 : case MERGE_MARKS_APPEND: maMarkStack.top()->append( aMerge ); break;
263 305 : case MERGE_MARKS_PREPEND: maMarkStack.top()->prepend( aMerge ); break;
264 43 : case MERGE_MARKS_POSTPONE: maMarkStack.top()->postpone( aMerge ); break;
265 763 : }
266 : }
267 :
268 78076 : void FastSaxSerializer::writeBytes( const Sequence< ::sal_Int8 >& aData ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
269 : {
270 78076 : if ( maMarkStack.empty() )
271 44691 : mxOutputStream->writeBytes( aData );
272 : else
273 33385 : maMarkStack.top()->append( aData );
274 78076 : }
275 :
276 1191 : FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData()
277 : {
278 1191 : merge( maData, maPostponed, true );
279 1191 : maPostponed.realloc( 0 );
280 :
281 1191 : return maData;
282 : }
283 :
284 : #if DEBUG
285 : void FastSaxSerializer::ForMerge::print( )
286 : {
287 : std::cerr << "Data: ";
288 : for ( sal_Int32 i=0, len=maData.getLength(); i < len; i++ )
289 : {
290 : std::cerr << maData[i];
291 : }
292 :
293 : std::cerr << "\nPostponed: ";
294 : for ( sal_Int32 i=0, len=maPostponed.getLength(); i < len; i++ )
295 : {
296 : std::cerr << maPostponed[i];
297 : }
298 :
299 : std::cerr << "\n";
300 : }
301 : #endif
302 :
303 305 : void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat )
304 : {
305 305 : merge( maData, rWhat, false );
306 305 : }
307 :
308 17333 : void FastSaxSerializer::ForMerge::append( const Int8Sequence &rWhat )
309 : {
310 17333 : merge( maData, rWhat, true );
311 17333 : }
312 :
313 43 : void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat )
314 : {
315 43 : merge( maPostponed, rWhat, true );
316 43 : }
317 :
318 36345 : void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend )
319 : {
320 36345 : sal_Int32 nMergeLen = rMerge.getLength();
321 36345 : if ( nMergeLen > 0 )
322 : {
323 35031 : sal_Int32 nTopLen = rTop.getLength();
324 :
325 35031 : rTop.realloc( nTopLen + nMergeLen );
326 35031 : if ( bAppend )
327 : {
328 : // append the rMerge to the rTop
329 34726 : memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen );
330 : }
331 : else
332 : {
333 : // prepend the rMerge to the rTop
334 305 : memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen );
335 305 : memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen );
336 : }
337 : }
338 36345 : }
339 :
340 537 : void FastSaxSerializer::ForMerge::resetData( )
341 : {
342 537 : maData = Int8Sequence();
343 537 : }
344 :
345 1071 : void FastSaxSerializer::ForSort::setCurrentElement( sal_Int32 nElement )
346 : {
347 1071 : SequenceAsVector< sal_Int32 > aOrder( maOrder );
348 1071 : if( std::find( aOrder.begin(), aOrder.end(), nElement ) != aOrder.end() )
349 : {
350 1007 : mnCurrentElement = nElement;
351 1007 : if ( maData.find( nElement ) == maData.end() )
352 1006 : maData[ nElement ] = Int8Sequence();
353 1071 : }
354 1071 : }
355 :
356 0 : void FastSaxSerializer::ForSort::prepend( const Int8Sequence &rWhat )
357 : {
358 0 : append( rWhat );
359 0 : }
360 :
361 17473 : void FastSaxSerializer::ForSort::append( const Int8Sequence &rWhat )
362 : {
363 17473 : merge( maData[mnCurrentElement], rWhat, true );
364 17473 : }
365 :
366 537 : void FastSaxSerializer::ForSort::sort()
367 : {
368 : // Clear the ForMerge data to avoid duplicate items
369 537 : resetData();
370 :
371 : // Sort it all
372 537 : std::map< sal_Int32, Int8Sequence >::iterator iter;
373 20529 : for ( sal_Int32 i=0, len=maOrder.getLength(); i < len; i++ )
374 : {
375 19992 : iter = maData.find( maOrder[i] );
376 19992 : if ( iter != maData.end() )
377 1006 : ForMerge::append( iter->second );
378 : }
379 537 : }
380 :
381 537 : FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForSort::getData()
382 : {
383 537 : sort( );
384 537 : return ForMerge::getData();
385 : }
386 :
387 : #if DEBUG
388 : void FastSaxSerializer::ForSort::print( )
389 : {
390 : std::map< sal_Int32, Int8Sequence >::iterator iter = maData.begin();
391 : while ( iter != maData.end( ) )
392 : {
393 : std::cerr << "pair: " << iter->first;
394 : for ( sal_Int32 i=0, len=iter->second.getLength(); i < len; ++i )
395 : std::cerr << iter->second[i];
396 : std::cerr << "\n";
397 : ++iter;
398 : }
399 :
400 : sort( );
401 : ForMerge::print();
402 : }
403 : #endif
404 :
405 78 : } // namespace sax_fastparser
406 :
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|