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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 #include <com/sun/star/embed/ElementModes.hpp> 31 #include <tools/debug.hxx> 32 #include <unotools/streamwrap.hxx> 33 #include <xmlversion.hxx> 34 #include <xmloff/xmlmetae.hxx> 35 36 #include <xmloff/xmltoken.hxx> 37 #include <comphelper/processfactory.hxx> 38 #include <com/sun/star/io/XActiveDataSource.hpp> 39 #include <com/sun/star/io/XOutputStream.hpp> 40 #include <com/sun/star/util/DateTime.hpp> 41 #include <com/sun/star/xml/sax/InputSource.hpp> 42 #include <com/sun/star/xml/sax/XParser.hpp> 43 44 #include <tools/string.hxx> 45 class SvStringsDtor; 46 47 using namespace ::com::sun::star::xml::sax; 48 using namespace ::com::sun::star::uno; 49 using namespace ::com::sun::star; 50 using ::rtl::OUString; 51 52 // ------------------------------------------------------------------------ 53 54 sal_Char __FAR_DATA XMLN_VERSIONSLIST[] = "VersionList.xml"; 55 56 // ------------------------------------------------------------------------ 57 58 // #110897# 59 XMLVersionListExport::XMLVersionListExport( 60 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, 61 const com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions, 62 const OUString &rFileName, 63 Reference< XDocumentHandler > &rHandler ) 64 : SvXMLExport( xServiceFactory, rFileName, rHandler ), 65 maVersions( rVersions ) 66 { 67 _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_DC_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC), 68 xmloff::token::GetXMLToken(xmloff::token::XML_N_DC), XML_NAMESPACE_DC ); 69 _GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST), 70 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK ); 71 } 72 73 // ------------------------------------------------------------------------ 74 sal_uInt32 XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum ) 75 { 76 GetDocHandler()->startDocument(); 77 78 sal_uInt16 nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_DC ); 79 80 AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ), 81 _GetNamespaceMap().GetNameByIndex ( nPos ) ); 82 83 nPos = _GetNamespaceMap().GetIndexByKey( XML_NAMESPACE_FRAMEWORK ); 84 AddAttribute( XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByIndex( nPos ), 85 _GetNamespaceMap().GetNameByIndex ( nPos ) ); 86 87 { 88 // the following object will write all collected attributes in its dtor 89 SvXMLElementExport aRoot( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_LIST, sal_True, sal_True ); 90 91 for ( sal_Int32 n=0; n<maVersions.getLength(); n++ ) 92 { 93 const util::RevisionTag& rInfo = maVersions[n]; 94 AddAttribute( XML_NAMESPACE_FRAMEWORK, 95 xmloff::token::XML_TITLE, 96 OUString( rInfo.Identifier ) ); 97 AddAttribute( XML_NAMESPACE_FRAMEWORK, 98 xmloff::token::XML_COMMENT, 99 OUString( rInfo.Comment ) ); 100 AddAttribute( XML_NAMESPACE_FRAMEWORK, 101 xmloff::token::XML_CREATOR, 102 OUString( rInfo.Author ) ); 103 104 OUString aDateStr = 105 SvXMLMetaExport::GetISODateTimeString( rInfo.TimeStamp ); 106 107 AddAttribute( XML_NAMESPACE_DC, xmloff::token::XML_DATE_TIME, aDateStr ); 108 109 // the following object will write all collected attributes in its dtor 110 SvXMLElementExport aEntry( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_ENTRY, sal_True, sal_True ); 111 } 112 } 113 GetDocHandler()->endDocument(); 114 return 0; 115 } 116 117 // ------------------------------------------------------------------------ 118 // ------------------------------------------------------------------------ 119 120 // #110897# 121 XMLVersionListImport::XMLVersionListImport( 122 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, 123 com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag >& rVersions ) 124 : SvXMLImport(xServiceFactory), 125 maVersions( rVersions ) 126 { 127 GetNamespaceMap().AddAtIndex( XML_NAMESPACE_FRAMEWORK_IDX, xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST), 128 xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK ); 129 } 130 131 // ------------------------------------------------------------------------ 132 XMLVersionListImport::~XMLVersionListImport( void ) throw() 133 {} 134 135 // ------------------------------------------------------------------------ 136 SvXMLImportContext *XMLVersionListImport::CreateContext( 137 sal_uInt16 nPrefix, 138 const OUString& rLocalName, 139 const Reference< XAttributeList > & xAttrList ) 140 { 141 SvXMLImportContext *pContext = 0; 142 143 if ( XML_NAMESPACE_FRAMEWORK == nPrefix && 144 rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_LIST) ) 145 { 146 pContext = new XMLVersionListContext( *this, nPrefix, rLocalName, xAttrList ); 147 } 148 else 149 { 150 pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList ); 151 } 152 153 return pContext; 154 } 155 156 157 // ------------------------------------------------------------------------ 158 // ------------------------------------------------------------------------ 159 160 XMLVersionListContext::XMLVersionListContext( XMLVersionListImport& rImport, 161 sal_uInt16 nPrefix, 162 const OUString& rLocalName, 163 const Reference< XAttributeList > & ) 164 : SvXMLImportContext( rImport, nPrefix, rLocalName ) 165 , rLocalRef( rImport ) 166 { 167 } 168 169 // ------------------------------------------------------------------------ 170 XMLVersionListContext::~XMLVersionListContext( void ) 171 {} 172 173 // ------------------------------------------------------------------------ 174 SvXMLImportContext *XMLVersionListContext::CreateChildContext( sal_uInt16 nPrefix, 175 const OUString& rLocalName, 176 const Reference< XAttributeList > & xAttrList ) 177 { 178 SvXMLImportContext *pContext = 0; 179 180 if ( nPrefix == XML_NAMESPACE_FRAMEWORK && 181 rLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_VERSION_ENTRY) ) 182 { 183 pContext = new XMLVersionContext( rLocalRef, nPrefix, rLocalName, xAttrList ); 184 } 185 else 186 { 187 pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName ); 188 } 189 190 return pContext; 191 } 192 193 // ------------------------------------------------------------------------ 194 // ------------------------------------------------------------------------ 195 196 XMLVersionContext::XMLVersionContext( XMLVersionListImport& rImport, 197 sal_uInt16 nPref, 198 const OUString& rLocalName, 199 const Reference< XAttributeList > & xAttrList ) 200 : SvXMLImportContext( rImport, nPref, rLocalName ) 201 , rLocalRef( rImport ) 202 { 203 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; 204 205 if ( !nAttrCount ) 206 return; 207 208 util::RevisionTag aInfo; 209 for ( sal_Int16 i=0; i < nAttrCount; i++ ) 210 { 211 OUString aLocalName; 212 const OUString& rAttrName = xAttrList->getNameByIndex( i ); 213 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName ); 214 215 if ( XML_NAMESPACE_FRAMEWORK == nPrefix ) 216 { 217 if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_TITLE) ) 218 { 219 const OUString& rAttrValue = xAttrList->getValueByIndex( i ); 220 aInfo.Identifier = rAttrValue; 221 } 222 else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_COMMENT) ) 223 { 224 const OUString& rAttrValue = xAttrList->getValueByIndex( i ); 225 aInfo.Comment = rAttrValue; 226 } 227 else if ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_CREATOR) ) 228 { 229 const OUString& rAttrValue = xAttrList->getValueByIndex( i ); 230 aInfo.Author = rAttrValue; 231 } 232 } 233 else if ( ( XML_NAMESPACE_DC == nPrefix ) && 234 ( aLocalName == xmloff::token::GetXMLToken(xmloff::token::XML_DATE_TIME) ) ) 235 { 236 const OUString& rAttrValue = xAttrList->getValueByIndex( i ); 237 util::DateTime aTime; 238 if ( ParseISODateTimeString( rAttrValue, aTime ) ) 239 aInfo.TimeStamp = aTime; 240 } 241 } 242 243 uno::Sequence < util::RevisionTag >& aList = rLocalRef.GetList(); 244 sal_Int32 nLength = aList.getLength(); 245 aList.realloc( nLength+1 ); 246 aList[nLength] = aInfo; 247 } 248 249 250 // ------------------------------------------------------------------------ 251 XMLVersionContext::~XMLVersionContext( void ) 252 {} 253 254 // ------------------------------------------------------------------------ 255 // static 256 sal_Bool XMLVersionContext::ParseISODateTimeString( 257 const rtl::OUString& rString, 258 util::DateTime& rDateTime ) 259 { 260 sal_Bool bSuccess = sal_True; 261 262 OUString aDateStr, aTimeStr; 263 sal_Int32 nPos = rString.indexOf( (sal_Unicode) 'T' ); 264 if ( nPos >= 0 ) 265 { 266 aDateStr = rString.copy( 0, nPos ); 267 aTimeStr = rString.copy( nPos + 1 ); 268 } 269 else 270 aDateStr = rString; // no separator: only date part 271 272 sal_Int32 nYear = 0; 273 sal_Int32 nMonth = 1; 274 sal_Int32 nDay = 1; 275 sal_Int32 nHour = 0; 276 sal_Int32 nMin = 0; 277 sal_Int32 nSec = 0; 278 279 const sal_Unicode* pStr = aDateStr.getStr(); 280 sal_Int32 nDateTokens = 1; 281 while ( *pStr ) 282 { 283 if ( *pStr == '-' ) 284 nDateTokens++; 285 pStr++; 286 } 287 if ( nDateTokens > 3 || aDateStr.getLength() == 0 ) 288 bSuccess = sal_False; 289 else 290 { 291 sal_Int32 n = 0; 292 nYear = aDateStr.getToken( 0, '-', n ).toInt32(); 293 if ( nYear > 9999 ) 294 bSuccess = sal_False; 295 else if ( nDateTokens >= 2 ) 296 { 297 nMonth = aDateStr.getToken( 0, '-', n ).toInt32(); 298 if ( nMonth > 12 ) 299 bSuccess = sal_False; 300 else if ( nDateTokens >= 3 ) 301 { 302 nDay = aDateStr.getToken( 0, '-', n ).toInt32(); 303 if ( nDay > 31 ) 304 bSuccess = sal_False; 305 } 306 } 307 } 308 309 if ( bSuccess && aTimeStr.getLength() > 0 ) // time is optional 310 { 311 pStr = aTimeStr.getStr(); 312 sal_Int32 nTimeTokens = 1; 313 while ( *pStr ) 314 { 315 if ( *pStr == ':' ) 316 nTimeTokens++; 317 pStr++; 318 } 319 if ( nTimeTokens > 3 ) 320 bSuccess = sal_False; 321 else 322 { 323 sal_Int32 n = 0; 324 nHour = aTimeStr.getToken( 0, ':', n ).toInt32(); 325 if ( nHour > 23 ) 326 bSuccess = sal_False; 327 else if ( nTimeTokens >= 2 ) 328 { 329 nMin = aTimeStr.getToken( 0, ':', n ).toInt32(); 330 if ( nMin > 59 ) 331 bSuccess = sal_False; 332 else if ( nTimeTokens >= 3 ) 333 { 334 nSec = aTimeStr.getToken( 0, ':', n ).toInt32(); 335 if ( nSec > 59 ) 336 bSuccess = sal_False; 337 } 338 } 339 } 340 } 341 342 if ( bSuccess ) 343 { 344 rDateTime.Day = sal::static_int_cast< sal_uInt16 >(nDay); 345 rDateTime.Month = sal::static_int_cast< sal_uInt16 >(nMonth); 346 rDateTime.Year = sal::static_int_cast< sal_uInt16 >(nYear); 347 rDateTime.Hours = sal::static_int_cast< sal_uInt16 >(nHour); 348 rDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(nMin); 349 rDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(nSec); 350 } 351 352 return bSuccess; 353 } 354 355 356 // ------------------------------------------------------------------------ 357 // ------------------------------------------------------------------------ 358 359 void SAL_CALL XMLVersionListPersistence::store( const uno::Reference< embed::XStorage >& xRoot, const uno::Sequence< util::RevisionTag >& rVersions ) 360 throw (::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) 361 { 362 // no storage, no version list! 363 if ( xRoot.is() ) 364 { 365 // get the services needed for writing the xml data 366 Reference< lang::XMultiServiceFactory > xServiceFactory = 367 comphelper::getProcessServiceFactory(); 368 DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" ); 369 370 Reference< XInterface > xWriter (xServiceFactory->createInstance( 371 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")))); 372 DBG_ASSERT( xWriter.is(), "com.sun.star.xml.sax.Writer service missing" ); 373 374 // check wether there's already a sub storage with the version info 375 // and delete it 376 OUString sVerName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST ) ); 377 378 // is this really needed, we set the size to zero before doing 379 // anything with this stream? 380 /* if ( xRoot->IsContained( sVerName ) ) 381 { 382 xRoot->Remove( sVerName ); 383 xRoot->Commit(); 384 } 385 */ 386 try { 387 // open (create) the sub storage with the version info 388 uno::Reference< io::XStream > xVerStream = xRoot->openStreamElement( 389 sVerName, 390 embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); 391 if ( !xVerStream.is() ) 392 throw uno::RuntimeException(); 393 394 //REMOVE // SetSize should not be neccessary because OpenStream( WRITE|TRUNC ) should already 395 //REMOVE // have set the size to zero 396 //REMOVE // xVerStream->SetSize ( 0L ); 397 //REMOVE xVerStream->SetBufferSize( 16*1024 ); 398 399 Reference< io::XOutputStream > xOut = xVerStream->getOutputStream(); 400 if ( !xOut.is() ) 401 throw uno::RuntimeException(); // the stream was successfuly opened for writing already 402 403 Reference< io::XActiveDataSource > xSrc( xWriter, uno::UNO_QUERY ); 404 xSrc->setOutputStream(xOut); 405 406 Reference< XDocumentHandler > xHandler( xWriter, uno::UNO_QUERY ); 407 408 // XMLVersionListExport aExp( pList, sVerName, xHandler ); 409 XMLVersionListExport aExp( xServiceFactory, rVersions, sVerName, xHandler ); 410 411 aExp.exportDoc( ::xmloff::token::XML_VERSION ); 412 413 //REMOVE xVerStream->Commit(); 414 xVerStream = uno::Reference< io::XStream >(); // use refcounting for now to dispose 415 // xRoot->Commit(); 416 } 417 catch( uno::Exception& ) 418 { 419 // TODO: error handling 420 } 421 } 422 } 423 424 // ------------------------------------------------------------------------ 425 uno::Sequence< util::RevisionTag > SAL_CALL XMLVersionListPersistence::load( const uno::Reference< embed::XStorage >& xRoot ) 426 throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::io::IOException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) 427 { 428 com::sun::star::uno::Sequence < com::sun::star::util::RevisionTag > aVersions; 429 430 const OUString sDocName( RTL_CONSTASCII_USTRINGPARAM( XMLN_VERSIONSLIST ) ); 431 uno::Reference< container::XNameAccess > xRootNames( xRoot, uno::UNO_QUERY ); 432 433 try { 434 if ( xRootNames.is() && xRootNames->hasByName( sDocName ) && xRoot->isStreamElement( sDocName ) ) 435 { 436 Reference< lang::XMultiServiceFactory > xServiceFactory = 437 comphelper::getProcessServiceFactory(); 438 DBG_ASSERT( xServiceFactory.is(), "XMLReader::Read: got no service manager" ); 439 440 InputSource aParserInput; 441 442 uno::Reference< beans::XPropertySet > xProps( xRoot, uno::UNO_QUERY ); 443 OSL_ENSURE( xProps.is(), "Storage must implement XPropertySet!\n" ); 444 if ( xProps.is() ) 445 { 446 try { 447 xProps->getPropertyValue( ::rtl::OUString::createFromAscii( "URL" ) ) >>= aParserInput.sSystemId; 448 } 449 catch( uno::Exception& ) 450 {} 451 } 452 453 uno::Reference< io::XStream > xDocStream = xRoot->openStreamElement( 454 sDocName, 455 embed::ElementModes::READ ); 456 if ( !xDocStream.is() ) 457 throw uno::RuntimeException(); 458 459 //REMOVE xDocStream->Seek( 0L ); 460 //REMOVE xDocStream->SetBufferSize( 16*1024 ); 461 462 aParserInput.aInputStream = xDocStream->getInputStream(); 463 OSL_ENSURE( aParserInput.aInputStream.is(), 464 "The stream was successfuly opened for reading, the input part must be accessible!\n" ); 465 if ( !aParserInput.aInputStream.is() ) 466 throw uno::RuntimeException(); 467 468 // get parser 469 Reference< XInterface > xXMLParser = xServiceFactory->createInstance( 470 OUString::createFromAscii("com.sun.star.xml.sax.Parser") ); 471 DBG_ASSERT( xXMLParser.is(), 472 "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" ); 473 474 // get filter 475 // Reference< XDocumentHandler > xFilter = new XMLVersionListImport( pList ); 476 Reference< XDocumentHandler > xFilter = new XMLVersionListImport( xServiceFactory, aVersions ); 477 478 // connect parser and filter 479 Reference< XParser > xParser( xXMLParser, UNO_QUERY ); 480 xParser->setDocumentHandler( xFilter ); 481 482 // parse 483 try 484 { 485 xParser->parseStream( aParserInput ); 486 } 487 catch( SAXParseException& ) {} 488 catch( SAXException& ) {} 489 catch( io::IOException& ) {} 490 } 491 } 492 catch( uno::Exception& ) 493 { 494 // TODO: error handling 495 } 496 497 return aVersions; 498 } 499 500 uno::Sequence< rtl::OUString > SAL_CALL XMLVersionListPersistence_getSupportedServiceNames() 501 throw() 502 { 503 const rtl::OUString aServiceName( 504 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) ); 505 const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 ); 506 return aSeq; 507 } 508 509 rtl::OUString SAL_CALL XMLVersionListPersistence_getImplementationName() throw() 510 { 511 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionListPersistence" ) ); 512 } 513 514 uno::Reference< uno::XInterface > SAL_CALL XMLVersionListPersistence_createInstance( 515 const uno::Reference< lang::XMultiServiceFactory > &) 516 throw( uno::Exception ) 517 { 518 return (cppu::OWeakObject*)new XMLVersionListPersistence; 519 } 520 521 uno::Sequence< rtl::OUString > SAL_CALL XMLVersionImExportOOO_getSupportedServiceNames() 522 throw() 523 { 524 const rtl::OUString aServiceName( 525 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.DocumentRevisionListPersistence" ) ); 526 const uno::Sequence< rtl::OUString > aSeq( &aServiceName, 1 ); 527 return aSeq; 528 } 529 530 rtl::OUString SAL_CALL XMLVersionImExportOOO_getImplementationName() throw() 531 { 532 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XMLVersionImExportOOo" ) ); 533 } 534 535 uno::Reference< uno::XInterface > SAL_CALL XMLVersionImExportOOO_createInstance( 536 const uno::Reference< lang::XMultiServiceFactory > &) 537 throw( uno::Exception ) 538 { 539 return (cppu::OWeakObject*)new XMLVersionListPersistence; 540 } 541 542