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( "<" ); break; 93 case '>': sBuf.appendAscii( ">" ); break; 94 case '&': sBuf.appendAscii( "&" ); break; 95 case '\'': sBuf.appendAscii( "'" ); break; 96 case '"': sBuf.appendAscii( """ ); 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