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( "<" ); 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 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