xref: /trunk/main/sax/source/tools/fastserializer.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
FastSaxSerializer()68     FastSaxSerializer::FastSaxSerializer( ) : mxOutputStream(), mxFastTokenHandler(), maMarkStack() {}
~FastSaxSerializer()69     FastSaxSerializer::~FastSaxSerializer() {}
70 
startDocument()71     void SAL_CALL FastSaxSerializer::startDocument(  )
72     {
73         if (!mxOutputStream.is())
74             return;
75         writeBytes(toUnoSequence(aXmlHeader));
76     }
77 
escapeXml(const OUString & s)78     OUString FastSaxSerializer::escapeXml( const OUString& s )
79     {
80         ::rtl::OUStringBuffer sBuf( s.getLength() );
81         const sal_Unicode* pStr = s.getStr();
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 
write(const OUString & s)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 
endDocument()107     void SAL_CALL FastSaxSerializer::endDocument(  )
108     {
109         if (!mxOutputStream.is())
110             return;
111     }
112 
writeId(::sal_Int32 nElement)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 
startFastElement(::sal_Int32 Element,const Reference<XFastAttributeList> & Attribs)123     void SAL_CALL FastSaxSerializer::startFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
124     {
125         if (!mxOutputStream.is())
126             return;
127 
128         writeBytes(toUnoSequence(aOpeningBracket));
129 
130         writeId(Element);
131         writeFastAttributeList(Attribs);
132 
133         writeBytes(toUnoSequence(aClosingBracket));
134     }
135 
startUnknownElement(const OUString & Namespace,const OUString & Name,const Reference<XFastAttributeList> & Attribs)136     void SAL_CALL FastSaxSerializer::startUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
137     {
138         if (!mxOutputStream.is())
139             return;
140 
141         writeBytes(toUnoSequence(aOpeningBracket));
142 
143         if (Namespace.getLength())
144         {
145             write(Namespace);
146             writeBytes(toUnoSequence(aColon));
147         }
148 
149         write(Name);
150 
151         writeFastAttributeList(Attribs);
152 
153         writeBytes(toUnoSequence(aClosingBracket));
154     }
155 
endFastElement(::sal_Int32 Element)156     void SAL_CALL FastSaxSerializer::endFastElement( ::sal_Int32 Element )
157     {
158         if (!mxOutputStream.is())
159             return;
160 
161         writeBytes(toUnoSequence(aOpeningBracketAndSlash));
162 
163         writeId(Element);
164 
165         writeBytes(toUnoSequence(aClosingBracket));
166     }
167 
endUnknownElement(const OUString & Namespace,const OUString & Name)168     void SAL_CALL FastSaxSerializer::endUnknownElement( const OUString& Namespace, const OUString& Name )
169     {
170         if (!mxOutputStream.is())
171             return;
172 
173         writeBytes(toUnoSequence(aOpeningBracketAndSlash));
174 
175         if (Namespace.getLength())
176         {
177             write(Namespace);
178             writeBytes(toUnoSequence(aColon));
179         }
180 
181         write(Name);
182 
183         writeBytes(toUnoSequence(aClosingBracket));
184     }
185 
singleFastElement(::sal_Int32 Element,const Reference<XFastAttributeList> & Attribs)186     void SAL_CALL FastSaxSerializer::singleFastElement( ::sal_Int32 Element, const Reference< XFastAttributeList >& Attribs )
187     {
188         if (!mxOutputStream.is())
189             return;
190 
191         writeBytes(toUnoSequence(aOpeningBracket));
192 
193         writeId(Element);
194         writeFastAttributeList(Attribs);
195 
196         writeBytes(toUnoSequence(aSlashAndClosingBracket));
197     }
198 
singleUnknownElement(const OUString & Namespace,const OUString & Name,const Reference<XFastAttributeList> & Attribs)199     void SAL_CALL FastSaxSerializer::singleUnknownElement( const OUString& Namespace, const OUString& Name, const Reference< XFastAttributeList >& Attribs )
200     {
201         if (!mxOutputStream.is())
202             return;
203 
204         writeBytes(toUnoSequence(aOpeningBracket));
205 
206         if (Namespace.getLength())
207         {
208             write(Namespace);
209             writeBytes(toUnoSequence(aColon));
210         }
211 
212         write(Name);
213 
214         writeFastAttributeList(Attribs);
215 
216         writeBytes(toUnoSequence(aSlashAndClosingBracket));
217     }
218 
characters(const OUString & aChars)219     void SAL_CALL FastSaxSerializer::characters( const OUString& aChars )
220     {
221         if (!mxOutputStream.is())
222             return;
223 
224         write( aChars );
225     }
226 
setOutputStream(const::com::sun::star::uno::Reference<::com::sun::star::io::XOutputStream> & xOutputStream)227     void SAL_CALL FastSaxSerializer::setOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutputStream )
228     {
229         mxOutputStream = xOutputStream;
230     }
231 
setFastTokenHandler(const::com::sun::star::uno::Reference<::com::sun::star::xml::sax::XFastTokenHandler> & xFastTokenHandler)232     void SAL_CALL FastSaxSerializer::setFastTokenHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XFastTokenHandler >& xFastTokenHandler )
233     {
234         mxFastTokenHandler = xFastTokenHandler;
235     }
writeFastAttributeList(const Reference<XFastAttributeList> & Attribs)236     void FastSaxSerializer::writeFastAttributeList( const Reference< XFastAttributeList >& Attribs )
237     {
238         Sequence< Attribute > aAttrSeq = Attribs->getUnknownAttributes();
239         const Attribute *pAttr = aAttrSeq.getConstArray();
240         sal_Int32 nAttrLength = aAttrSeq.getLength();
241         for (sal_Int32 i = 0; i < nAttrLength; i++)
242         {
243             writeBytes(toUnoSequence(aSpace));
244 
245             write(pAttr[i].Name);
246             writeBytes(toUnoSequence(aEqualSignAndQuote));
247             write(escapeXml(pAttr[i].Value));
248             writeBytes(toUnoSequence(aQuote));
249         }
250 
251         Sequence< FastAttribute > aFastAttrSeq = Attribs->getFastAttributes();
252         const FastAttribute *pFastAttr = aFastAttrSeq.getConstArray();
253         sal_Int32 nFastAttrLength = aFastAttrSeq.getLength();
254         for (sal_Int32 j = 0; j < nFastAttrLength; j++)
255         {
256             writeBytes(toUnoSequence(aSpace));
257 
258             sal_Int32 nToken = pFastAttr[j].Token;
259             writeId(nToken);
260 
261             writeBytes(toUnoSequence(aEqualSignAndQuote));
262 
263             write(escapeXml(Attribs->getValue(pFastAttr[j].Token)));
264 
265             writeBytes(toUnoSequence(aQuote));
266         }
267     }
268 
269     // XServiceInfo
getImplementationName()270     OUString FastSaxSerializer::getImplementationName()
271     {
272         return getImplementationName_Static();
273     }
274 
275     // XServiceInfo
supportsService(const OUString & ServiceName)276     sal_Bool FastSaxSerializer::supportsService(const OUString& ServiceName)
277     {
278         Sequence< OUString > aSNL = getSupportedServiceNames();
279         const OUString * pArray = aSNL.getConstArray();
280 
281         for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
282         if( pArray[i] == ServiceName )
283             return sal_True;
284 
285         return sal_False;
286     }
287 
288     // XServiceInfo
getSupportedServiceNames(void)289     Sequence< OUString > FastSaxSerializer::getSupportedServiceNames(void)
290     {
291         Sequence<OUString> seq(1);
292         seq.getArray()[0] = OUString::createFromAscii( SERIALIZER_SERVICE_NAME );
293         return seq;
294     }
295 
getImplementationName_Static()296     OUString FastSaxSerializer::getImplementationName_Static()
297     {
298         return OUString::createFromAscii( SERIALIZER_IMPLEMENTATION_NAME );
299     }
300 
getSupportedServiceNames_Static(void)301     Sequence< OUString > FastSaxSerializer::getSupportedServiceNames_Static(void)
302     {
303         Sequence<OUString> aRet(1);
304         aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(SERIALIZER_SERVICE_NAME) );
305         return aRet;
306     }
307 
mark()308     void FastSaxSerializer::mark()
309     {
310         maMarkStack.push( ForMerge() );
311     }
312 
mergeTopMarks(sax_fastparser::MergeMarksEnum eMergeType)313     void FastSaxSerializer::mergeTopMarks( sax_fastparser::MergeMarksEnum eMergeType )
314     {
315         if ( maMarkStack.empty() )
316             return;
317 
318         if ( maMarkStack.size() == 1 )
319         {
320             mxOutputStream->writeBytes( maMarkStack.top().getData() );
321             maMarkStack.pop();
322             return;
323         }
324 
325         const Int8Sequence aMerge( maMarkStack.top().getData() );
326         maMarkStack.pop();
327 
328         switch ( eMergeType )
329         {
330             case MERGE_MARKS_APPEND:   maMarkStack.top().append( aMerge );   break;
331             case MERGE_MARKS_PREPEND:  maMarkStack.top().prepend( aMerge );  break;
332             case MERGE_MARKS_POSTPONE: maMarkStack.top().postpone( aMerge ); break;
333         }
334     }
335 
writeBytes(const Sequence<::sal_Int8> & aData)336     void FastSaxSerializer::writeBytes( const Sequence< ::sal_Int8 >& aData )
337     {
338         if ( maMarkStack.empty() )
339             mxOutputStream->writeBytes( aData );
340         else
341             maMarkStack.top().append( aData );
342     }
343 
getData()344     FastSaxSerializer::Int8Sequence& FastSaxSerializer::ForMerge::getData()
345     {
346         merge( maData, maPostponed, true );
347         maPostponed.realloc( 0 );
348 
349         return maData;
350     }
351 
prepend(const Int8Sequence & rWhat)352     void FastSaxSerializer::ForMerge::prepend( const Int8Sequence &rWhat )
353     {
354         merge( maData, rWhat, false );
355     }
356 
append(const Int8Sequence & rWhat)357     void FastSaxSerializer::ForMerge::append( const Int8Sequence &rWhat )
358     {
359         merge( maData, rWhat, true );
360     }
361 
postpone(const Int8Sequence & rWhat)362     void FastSaxSerializer::ForMerge::postpone( const Int8Sequence &rWhat )
363     {
364         merge( maPostponed, rWhat, true );
365     }
366 
merge(Int8Sequence & rTop,const Int8Sequence & rMerge,bool bAppend)367     void FastSaxSerializer::ForMerge::merge( Int8Sequence &rTop, const Int8Sequence &rMerge, bool bAppend )
368     {
369         sal_Int32 nMergeLen = rMerge.getLength();
370         if ( nMergeLen > 0 )
371         {
372             sal_Int32 nTopLen = rTop.getLength();
373 
374             rTop.realloc( nTopLen + nMergeLen );
375             if ( bAppend )
376             {
377                 // append the rMerge to the rTop
378                 memcpy( rTop.getArray() + nTopLen, rMerge.getConstArray(), nMergeLen );
379             }
380             else
381             {
382                 // prepend the rMerge to the rTop
383                 memmove( rTop.getArray() + nMergeLen, rTop.getConstArray(), nTopLen );
384                 memcpy( rTop.getArray(), rMerge.getConstArray(), nMergeLen );
385             }
386         }
387     }
388 
389 } // namespace sax_fastparser
390