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