1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "fastserializer.hxx"
29 #include <rtl/ustrbuf.hxx>
30 #include <rtl/byteseq.hxx>
31 
32 #include <com/sun/star/xml/Attribute.hpp>
33 #include <com/sun/star/xml/FastAttribute.hpp>
34 #include <com/sun/star/xml/sax/XFastAttributeList.hpp>
35 
36 #include <string.h>
37 
38 using ::rtl::OString;
39 using ::rtl::OUString;
40 using ::rtl::OUStringBuffer;
41 using ::rtl::OUStringToOString;
42 using ::com::sun::star::uno::Reference;
43 using ::com::sun::star::uno::RuntimeException;
44 using ::com::sun::star::uno::Sequence;
45 using ::com::sun::star::uno::toUnoSequence;
46 using ::com::sun::star::xml::FastAttribute;
47 using ::com::sun::star::xml::Attribute;
48 using ::com::sun::star::xml::sax::SAXException;
49 using ::com::sun::star::xml::sax::XFastAttributeList;
50 using ::com::sun::star::xml::sax::XFastTokenHandler;
51 using ::com::sun::star::xml::sax::XFastSerializer;
52 using ::com::sun::star::io::XOutputStream;
53 using ::com::sun::star::io::NotConnectedException;
54 using ::com::sun::star::io::IOException;
55 using ::com::sun::star::io::BufferSizeExceededException;
56 
57 static rtl::ByteSequence aClosingBracket((const sal_Int8 *)">", 1);
58 static rtl::ByteSequence aSlashAndClosingBracket((const sal_Int8 *)"/>", 2);
59 static rtl::ByteSequence aColon((const sal_Int8 *)":", 1);
60 static rtl::ByteSequence aOpeningBracket((const sal_Int8 *)"<", 1);
61 static rtl::ByteSequence aOpeningBracketAndSlash((const sal_Int8 *)"</", 2);
62 static rtl::ByteSequence aQuote((const sal_Int8 *)"\"", 1);
63 static rtl::ByteSequence aEqualSignAndQuote((const sal_Int8 *)"=\"", 2);
64 static rtl::ByteSequence aSpace((const sal_Int8 *)" ", 1);
65 static rtl::ByteSequence aXmlHeader((const sal_Int8*) "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", 56);
66 
67 #define HAS_NAMESPACE(x) ((x & 0xffff0000) != 0)
68 #define NAMESPACE(x) (x >> 16)
69 #define TOKEN(x) (x & 0xffff)
70 
71 namespace sax_fastparser {
72     FastSaxSerializer::FastSaxSerializer( ) : mxOutputStream(), mxFastTokenHandler(), maMarkStack() {}
73     FastSaxSerializer::~FastSaxSerializer() {}
74 
75 	void SAL_CALL FastSaxSerializer::startDocument(  ) throw (SAXException, RuntimeException)
76 	{
77 		if (!mxOutputStream.is())
78 			return;
79 		writeBytes(toUnoSequence(aXmlHeader));
80 	}
81 
82 	OUString FastSaxSerializer::escapeXml( const OUString& s )
83 	{
84 		::rtl::OUStringBuffer sBuf( s.getLength() );
85 		const sal_Unicode* pStr = s;
86 		sal_Int32 nLen = s.getLength();
87 		for( sal_Int32 i = 0; i < nLen; ++i)
88 		{
89 			sal_Unicode c = pStr[ i ];
90 			switch( c )
91 			{
92 				case '<':   sBuf.appendAscii( "&lt;" );     break;
93 				case '>':   sBuf.appendAscii( "&gt;" );     break;
94 				case '&':   sBuf.appendAscii( "&amp;" );    break;
95 				case '\'':  sBuf.appendAscii( "&apos;" );   break;
96 				case '"':   sBuf.appendAscii( "&quot;" );   break;
97 				default:    sBuf.append( c );               break;
98 			}
99 		}
100 		return sBuf.makeStringAndClear();
101 	}
102 
103 	void FastSaxSerializer::write( const OUString& s )
104 	{
105 		OString sOutput( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) );
106 		writeBytes( Sequence< sal_Int8 >(
107 					reinterpret_cast< const sal_Int8*>( sOutput.getStr() ),
108 					sOutput.getLength() ) );
109 	}
110 
111     void SAL_CALL FastSaxSerializer::endDocument(  ) throw (SAXException, RuntimeException)
112 	{
113 		if (!mxOutputStream.is())
114 			return;
115 	}
116 
117     void SAL_CALL FastSaxSerializer::writeId( ::sal_Int32 nElement )
118     {
119         if( HAS_NAMESPACE( nElement ) ) {
120             writeBytes(mxFastTokenHandler->getUTF8Identifier(NAMESPACE(nElement)));
121             writeBytes(toUnoSequence(aColon));
122             writeBytes(mxFastTokenHandler->getUTF8Identifier(TOKEN(nElement)));
123         } else
124             writeBytes(mxFastTokenHandler->getUTF8Identifier(nElement));
125     }
126 
127     void SAL_CALL FastSaxSerializer::startFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
128 		throw (SAXException, RuntimeException)
129 	{
130 		if (!mxOutputStream.is())
131 			return;
132 
133 		writeBytes(toUnoSequence(aOpeningBracket));
134 
135         writeId(Element);
136 		writeFastAttributeList(Attribs);
137 
138 		writeBytes(toUnoSequence(aClosingBracket));
139 	}
140 
141     void SAL_CALL FastSaxSerializer::startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
142 		throw (SAXException, RuntimeException)
143 	{
144 		if (!mxOutputStream.is())
145 			return;
146 
147 		writeBytes(toUnoSequence(aOpeningBracket));
148 
149 		if (Namespace.getLength())
150 		{
151 			write(Namespace);
152 			writeBytes(toUnoSequence(aColon));
153 		}
154 
155 		write(Name);
156 
157 		writeFastAttributeList(Attribs);
158 
159 		writeBytes(toUnoSequence(aClosingBracket));
160 	}
161 
162     void SAL_CALL FastSaxSerializer::endFastElement( ::sal_Int32 Element )
163 		throw (SAXException, RuntimeException)
164 	{
165 		if (!mxOutputStream.is())
166 			return;
167 
168 		writeBytes(toUnoSequence(aOpeningBracketAndSlash));
169 
170         writeId(Element);
171 
172 		writeBytes(toUnoSequence(aClosingBracket));
173 	}
174 
175     void SAL_CALL FastSaxSerializer::endUnknownElement( const OUString& Namespace, const OUString& Name )
176 		throw (SAXException, RuntimeException)
177 	{
178 		if (!mxOutputStream.is())
179 			return;
180 
181 		writeBytes(toUnoSequence(aOpeningBracketAndSlash));
182 
183 		if (Namespace.getLength())
184 		{
185 			write(Namespace);
186 			writeBytes(toUnoSequence(aColon));
187 		}
188 
189 		write(Name);
190 
191 		writeBytes(toUnoSequence(aClosingBracket));
192 	}
193 
194     void SAL_CALL FastSaxSerializer::singleFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
195 		throw (SAXException, RuntimeException)
196 	{
197 		if (!mxOutputStream.is())
198 			return;
199 
200 		writeBytes(toUnoSequence(aOpeningBracket));
201 
202         writeId(Element);
203 		writeFastAttributeList(Attribs);
204 
205 		writeBytes(toUnoSequence(aSlashAndClosingBracket));
206 	}
207 
208     void SAL_CALL FastSaxSerializer::singleUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
209 		throw (SAXException, RuntimeException)
210 	{
211 		if (!mxOutputStream.is())
212 			return;
213 
214 		writeBytes(toUnoSequence(aOpeningBracket));
215 
216 		if (Namespace.getLength())
217 		{
218 			write(Namespace);
219 			writeBytes(toUnoSequence(aColon));
220 		}
221 
222 		write(Name);
223 
224 		writeFastAttributeList(Attribs);
225 
226 		writeBytes(toUnoSequence(aSlashAndClosingBracket));
227 	}
228 
229     void SAL_CALL FastSaxSerializer::characters( const OUString& aChars )
230 		throw (SAXException, RuntimeException)
231 	{
232 		if (!mxOutputStream.is())
233 			return;
234 
235 		write( aChars );
236 	}
237 
238     void SAL_CALL FastSaxSerializer::setOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream )
239 		throw (::com::sun::star::uno::RuntimeException)
240 	{
241 		mxOutputStream = xOutputStream;
242 	}
243 
244     void SAL_CALL FastSaxSerializer::setFastTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xFastTokenHandler )
245 		throw (::com::sun::star::uno::RuntimeException)
246 	{
247 		mxFastTokenHandler = xFastTokenHandler;
248 	}
249 	void FastSaxSerializer::writeFastAttributeList( const Reference< XFastAttributeList >& Attribs )
250 	{
251 		Sequence< Attribute > aAttrSeq = Attribs->getUnknownAttributes();
252 		const Attribute *pAttr = aAttrSeq.getConstArray();
253 		sal_Int32 nAttrLength = aAttrSeq.getLength();
254 		for (sal_Int32 i = 0; i < nAttrLength; i++)
255 		{
256 			writeBytes(toUnoSequence(aSpace));
257 
258 			write(pAttr[i].Name);
259 			writeBytes(toUnoSequence(aEqualSignAndQuote));
260 			write(escapeXml(pAttr[i].Value));
261 			writeBytes(toUnoSequence(aQuote));
262 		}
263 
264 		Sequence< FastAttribute > aFastAttrSeq = Attribs->getFastAttributes();
265 		const FastAttribute *pFastAttr = aFastAttrSeq.getConstArray();
266 		sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
267 		for (sal_Int32 j = 0; j < nFastAttrLength; j++)
268 		{
269 			writeBytes(toUnoSequence(aSpace));
270 
271             sal_Int32 nToken = pFastAttr[j].Token;
272             writeId(nToken);
273 
274 			writeBytes(toUnoSequence(aEqualSignAndQuote));
275 
276 			write(escapeXml(Attribs->getValue(pFastAttr[j].Token)));
277 
278 			writeBytes(toUnoSequence(aQuote));
279 		}
280 	}
281 
282 	// XServiceInfo
283 	OUString FastSaxSerializer::getImplementationName() throw (RuntimeException)
284 	{
285 		return OUString::createFromAscii( SERIALIZER_IMPLEMENTATION_NAME );
286 	}
287 
288 	// XServiceInfo
289 	sal_Bool FastSaxSerializer::supportsService(const OUString& ServiceName) throw (RuntimeException)
290 	{
291 		Sequence< OUString > aSNL = getSupportedServiceNames();
292 		const OUString * pArray = aSNL.getConstArray();
293 
294 		for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
295 		if( pArray[i] == ServiceName )
296 			return sal_True;
297 
298 		return sal_False;
299 	}
300 
301 	// XServiceInfo
302 	Sequence< OUString > FastSaxSerializer::getSupportedServiceNames(void) throw (RuntimeException)
303 	{
304 		Sequence<OUString> seq(1);
305 		seq.getArray()[0] = OUString::createFromAscii( SERIALIZER_SERVICE_NAME );
306 		return seq;
307 	}
308 
309     OUString FastSaxSerializer::getImplementationName_Static()
310     {
311         return OUString::createFromAscii( SERIALIZER_IMPLEMENTATION_NAME );
312     }
313 
314     Sequence< OUString > FastSaxSerializer::getSupportedServiceNames_Static(void)
315     {
316         Sequence<OUString> aRet(1);
317         aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(SERIALIZER_SERVICE_NAME) );
318         return aRet;
319     }
320 
321     void FastSaxSerializer::mark()
322     {
323         maMarkStack.push( ForMerge() );
324     }
325 
326     void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
327     {
328         if ( maMarkStack.empty() )
329             return;
330 
331         if ( maMarkStack.size() == 1 )
332         {
333             mxOutputStream->writeBytes( maMarkStack.top().getData() );
334             maMarkStack.pop();
335             return;
336         }
337 
338         const Int8Sequence aMerge( maMarkStack.top().getData() );
339         maMarkStack.pop();
340 
341         switch ( eMergeType )
342         {
343             case MERGE_MARKS_APPEND:   maMarkStack.top().append( aMerge );   break;
344             case MERGE_MARKS_PREPEND:  maMarkStack.top().prepend( aMerge );  break;
345             case MERGE_MARKS_POSTPONE: maMarkStack.top().postpone( aMerge ); break;
346         }
347     }
348 
349     void FastSaxSerializer::writeBytes( const Sequence< ::sal_Int8 >& aData ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
350     {
351         if ( maMarkStack.empty() )
352             mxOutputStream->writeBytes( aData );
353         else
354             maMarkStack.top().append( aData );
355     }
356 
357     FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData()
358     {
359         merge( maData, maPostponed, true );
360         maPostponed.realloc( 0 );
361 
362         return maData;
363     }
364 
365     void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat )
366     {
367         merge( maData, rWhat, false );
368     }
369 
370     void FastSaxSerializer::ForMerge::append( const Int8Sequence &rWhat )
371     {
372         merge( maData, rWhat, true );
373     }
374 
375     void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat )
376     {
377         merge( maPostponed, rWhat, true );
378     }
379 
380     void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend )
381     {
382         sal_Int32 nMergeLen = rMerge.getLength();
383         if ( nMergeLen > 0 )
384         {
385             sal_Int32 nTopLen = rTop.getLength();
386 
387             rTop.realloc( nTopLen + nMergeLen );
388             if ( bAppend )
389             {
390                 // append the rMerge to the rTop
391                 memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen );
392             }
393             else
394             {
395                 // prepend the rMerge to the rTop
396                 memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen );
397                 memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen );
398             }
399         }
400     }
401 
402 } // namespace sax_fastparser
403 
404