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( "<" ); break; 89 case '>': sBuf.appendAscii( ">" ); break; 90 case '&': sBuf.appendAscii( "&" ); break; 91 case '\'': sBuf.appendAscii( "'" ); break; 92 case '"': sBuf.appendAscii( """ ); 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