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 302 : 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 302 : , maSpace((const sal_Int8 *)" ", 1)
70 : {
71 302 : }
72 302 : FastSaxSerializer::~FastSaxSerializer() {}
73 :
74 302 : void SAL_CALL FastSaxSerializer::startDocument( ) throw (SAXException, RuntimeException)
75 : {
76 : assert(mxOutputStream.is()); // cannot do anything without that
77 302 : if (!mxOutputStream.is())
78 302 : return;
79 302 : rtl::ByteSequence aXmlHeader((const sal_Int8*) "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", 56);
80 302 : writeBytes(toUnoSequence(aXmlHeader));
81 : }
82 :
83 12134 : OUString FastSaxSerializer::escapeXml( const OUString& s )
84 : {
85 12134 : ::rtl::OUStringBuffer sBuf( s.getLength() );
86 12134 : const sal_Unicode* pStr = s.getStr();
87 12134 : sal_Int32 nLen = s.getLength();
88 121604 : for( sal_Int32 i = 0; i < nLen; ++i)
89 : {
90 109470 : sal_Unicode c = pStr[ i ];
91 109470 : switch( c )
92 : {
93 8 : case '<': sBuf.appendAscii( "<" ); break;
94 0 : case '>': sBuf.appendAscii( ">" ); break;
95 0 : case '&': sBuf.appendAscii( "&" ); break;
96 2 : case '\'': sBuf.appendAscii( "'" ); break;
97 16 : case '"': sBuf.appendAscii( """ ); break;
98 0 : case '\n': sBuf.appendAscii( " " ); break;
99 0 : case '\r': sBuf.appendAscii( " " ); break;
100 109444 : default: sBuf.append( c ); break;
101 : }
102 : }
103 12134 : return sBuf.makeStringAndClear();
104 : }
105 :
106 12872 : void FastSaxSerializer::write( const OUString& s )
107 : {
108 12872 : OString sOutput( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) );
109 : writeBytes( Sequence< sal_Int8 >(
110 12872 : reinterpret_cast< const sal_Int8*>( sOutput.getStr() ),
111 25744 : sOutput.getLength() ) );
112 12872 : }
113 :
114 302 : void SAL_CALL FastSaxSerializer::endDocument( ) throw (SAXException, RuntimeException)
115 : {
116 302 : if (!mxOutputStream.is())
117 0 : return;
118 : }
119 :
120 28318 : void SAL_CALL FastSaxSerializer::writeId( ::sal_Int32 nElement )
121 : {
122 28318 : if( HAS_NAMESPACE( nElement ) ) {
123 23416 : writeBytes(mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)));
124 23416 : writeBytes(toUnoSequence(maColon));
125 23416 : writeBytes(mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)));
126 : } else
127 4902 : writeBytes(mxFastTokenHandler->getUTF8Identifier(nElement));
128 28318 : }
129 :
130 5850 : void SAL_CALL FastSaxSerializer::startFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
131 : throw (SAXException, RuntimeException)
132 : {
133 5850 : if (!mxOutputStream.is())
134 5850 : return;
135 :
136 5850 : if ( !maMarkStack.empty() )
137 2458 : maMarkStack.top()->setCurrentElement( Element );
138 :
139 5850 : writeBytes(toUnoSequence(maOpeningBracket));
140 :
141 5850 : writeId(Element);
142 5850 : writeFastAttributeList(Attribs);
143 :
144 5850 : writeBytes(toUnoSequence(maClosingBracket));
145 : }
146 :
147 5852 : void SAL_CALL FastSaxSerializer::endFastElement( ::sal_Int32 Element )
148 : throw (SAXException, RuntimeException)
149 : {
150 5852 : if (!mxOutputStream.is())
151 5852 : return;
152 :
153 5852 : writeBytes(toUnoSequence(maOpeningBracketAndSlash));
154 :
155 5852 : writeId(Element);
156 :
157 5852 : writeBytes(toUnoSequence(maClosingBracket));
158 : }
159 :
160 5106 : void SAL_CALL FastSaxSerializer::singleFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
161 : throw (SAXException, RuntimeException)
162 : {
163 5106 : if (!mxOutputStream.is())
164 5106 : return;
165 :
166 5106 : if ( !maMarkStack.empty() )
167 2324 : maMarkStack.top()->setCurrentElement( Element );
168 :
169 5106 : writeBytes(toUnoSequence(maOpeningBracket));
170 :
171 5106 : writeId(Element);
172 5106 : writeFastAttributeList(Attribs);
173 :
174 5106 : writeBytes(toUnoSequence(maSlashAndClosingBracket));
175 : }
176 :
177 1414 : void SAL_CALL FastSaxSerializer::characters( const OUString& aChars )
178 : throw (SAXException, RuntimeException)
179 : {
180 1414 : if (!mxOutputStream.is())
181 1414 : return;
182 :
183 1414 : write( aChars );
184 : }
185 :
186 302 : 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 302 : mxOutputStream = xOutputStream;
190 : assert(mxOutputStream.is()); // cannot do anything without that
191 302 : }
192 :
193 302 : 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 302 : mxFastTokenHandler = xFastTokenHandler;
197 302 : }
198 10956 : void FastSaxSerializer::writeFastAttributeList( const Reference< XFastAttributeList >& Attribs )
199 : {
200 10956 : Sequence< Attribute > aAttrSeq = Attribs->getUnknownAttributes();
201 10956 : const Attribute *pAttr = aAttrSeq.getConstArray();
202 10956 : sal_Int32 nAttrLength = aAttrSeq.getLength();
203 10956 : 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 10956 : Sequence< FastAttribute > aFastAttrSeq = Attribs->getFastAttributes();
214 10956 : const FastAttribute *pFastAttr = aFastAttrSeq.getConstArray();
215 10956 : sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
216 22414 : for (sal_Int32 j = 0; j < nFastAttrLength; j++)
217 : {
218 11458 : writeBytes(toUnoSequence(maSpace));
219 :
220 11458 : sal_Int32 nToken = pFastAttr[j].Token;
221 11458 : writeId(nToken);
222 :
223 11458 : writeBytes(toUnoSequence(maEqualSignAndQuote));
224 :
225 11458 : write(escapeXml(Attribs->getValue(pFastAttr[j].Token)));
226 :
227 11458 : writeBytes(toUnoSequence(maQuote));
228 10956 : }
229 10956 : }
230 :
231 2382 : void FastSaxSerializer::mark( Int32Sequence aOrder )
232 : {
233 2382 : if ( aOrder.hasElements() )
234 : {
235 1074 : boost::shared_ptr< ForMerge > pSort( new ForSort( aOrder ) );
236 1074 : maMarkStack.push( pSort );
237 : }
238 : else
239 : {
240 1308 : boost::shared_ptr< ForMerge > pMerge( new ForMerge( ) );
241 1308 : maMarkStack.push( pMerge );
242 : }
243 2382 : }
244 :
245 2382 : void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
246 : {
247 2382 : if ( maMarkStack.empty() )
248 : return;
249 :
250 2382 : if ( maMarkStack.size() == 1 )
251 : {
252 856 : mxOutputStream->writeBytes( maMarkStack.top()->getData() );
253 856 : maMarkStack.pop();
254 : return;
255 : }
256 :
257 1526 : const Int8Sequence aMerge( maMarkStack.top()->getData() );
258 1526 : maMarkStack.pop();
259 :
260 1526 : switch ( eMergeType )
261 : {
262 830 : case MERGE_MARKS_APPEND: maMarkStack.top()->append( aMerge ); break;
263 610 : case MERGE_MARKS_PREPEND: maMarkStack.top()->prepend( aMerge ); break;
264 86 : case MERGE_MARKS_POSTPONE: maMarkStack.top()->postpone( aMerge ); break;
265 1526 : }
266 : }
267 :
268 156314 : void FastSaxSerializer::writeBytes( const Sequence< ::sal_Int8 >& aData ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
269 : {
270 156314 : if ( maMarkStack.empty() )
271 89544 : mxOutputStream->writeBytes( aData );
272 : else
273 66770 : maMarkStack.top()->append( aData );
274 156314 : }
275 :
276 2382 : FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData()
277 : {
278 2382 : merge( maData, maPostponed, true );
279 2382 : maPostponed.realloc( 0 );
280 :
281 2382 : 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 610 : void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat )
304 : {
305 610 : merge( maData, rWhat, false );
306 610 : }
307 :
308 34666 : void FastSaxSerializer::ForMerge::append( const Int8Sequence &rWhat )
309 : {
310 34666 : merge( maData, rWhat, true );
311 34666 : }
312 :
313 86 : void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat )
314 : {
315 86 : merge( maPostponed, rWhat, true );
316 86 : }
317 :
318 72690 : void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend )
319 : {
320 72690 : sal_Int32 nMergeLen = rMerge.getLength();
321 72690 : if ( nMergeLen > 0 )
322 : {
323 70062 : sal_Int32 nTopLen = rTop.getLength();
324 :
325 70062 : rTop.realloc( nTopLen + nMergeLen );
326 70062 : if ( bAppend )
327 : {
328 : // append the rMerge to the rTop
329 69452 : memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen );
330 : }
331 : else
332 : {
333 : // prepend the rMerge to the rTop
334 610 : memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen );
335 610 : memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen );
336 : }
337 : }
338 72690 : }
339 :
340 1074 : void FastSaxSerializer::ForMerge::resetData( )
341 : {
342 1074 : maData = Int8Sequence();
343 1074 : }
344 :
345 2142 : void FastSaxSerializer::ForSort::setCurrentElement( sal_Int32 nElement )
346 : {
347 2142 : SequenceAsVector< sal_Int32 > aOrder( maOrder );
348 2142 : if( std::find( aOrder.begin(), aOrder.end(), nElement ) != aOrder.end() )
349 : {
350 2014 : mnCurrentElement = nElement;
351 2014 : if ( maData.find( nElement ) == maData.end() )
352 2012 : maData[ nElement ] = Int8Sequence();
353 2142 : }
354 2142 : }
355 :
356 0 : void FastSaxSerializer::ForSort::prepend( const Int8Sequence &rWhat )
357 : {
358 0 : append( rWhat );
359 0 : }
360 :
361 34946 : void FastSaxSerializer::ForSort::append( const Int8Sequence &rWhat )
362 : {
363 34946 : merge( maData[mnCurrentElement], rWhat, true );
364 34946 : }
365 :
366 1074 : void FastSaxSerializer::ForSort::sort()
367 : {
368 : // Clear the ForMerge data to avoid duplicate items
369 1074 : resetData();
370 :
371 : // Sort it all
372 1074 : std::map< sal_Int32, Int8Sequence >::iterator iter;
373 41058 : for ( sal_Int32 i=0, len=maOrder.getLength(); i < len; i++ )
374 : {
375 39984 : iter = maData.find( maOrder[i] );
376 39984 : if ( iter != maData.end() )
377 2012 : ForMerge::append( iter->second );
378 : }
379 1074 : }
380 :
381 1074 : FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForSort::getData()
382 : {
383 1074 : sort( );
384 1074 : 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 : } // namespace sax_fastparser
406 :
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|