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_ucb.hxx" 30 31 /************************************************************************** 32 TODO 33 ************************************************************************** 34 35 - remove root storage access workaround 36 37 *************************************************************************/ 38 39 #define ROOTSTORAGE_ACCESS_WORKAROUND 1 40 41 #include <memory> 42 43 #include "com/sun/star/beans/XPropertySet.hpp" 44 #include "com/sun/star/embed/ElementModes.hpp" 45 #include "com/sun/star/lang/XSingleServiceFactory.hpp" 46 47 #include "tdoc_uri.hxx" 48 #include "tdoc_docmgr.hxx" 49 #include "tdoc_stgelems.hxx" 50 51 #include "tdoc_storage.hxx" 52 53 using namespace com::sun::star; 54 using namespace tdoc_ucp; 55 56 57 //========================================================================= 58 //========================================================================= 59 // 60 // StorageElementFactory Implementation. 61 // 62 //========================================================================= 63 //========================================================================= 64 65 StorageElementFactory::StorageElementFactory( 66 const uno::Reference< lang::XMultiServiceFactory > & xSMgr, 67 const rtl::Reference< OfficeDocumentsManager > & xDocsMgr ) 68 : m_xDocsMgr( xDocsMgr ), 69 m_xSMgr( xSMgr ) 70 { 71 } 72 73 //========================================================================= 74 StorageElementFactory::~StorageElementFactory() 75 { 76 OSL_ENSURE( m_aMap.size() == 0, 77 "StorageElementFactory::~StorageElementFactory - Dangling storages!" ); 78 } 79 80 //========================================================================= 81 uno::Reference< embed::XStorage > 82 StorageElementFactory::createTemporaryStorage() 83 throw ( uno::Exception, 84 uno::RuntimeException ) 85 { 86 uno::Reference< embed::XStorage > xStorage; 87 uno::Reference< lang::XSingleServiceFactory > xStorageFac; 88 if ( m_xSMgr.is() ) 89 { 90 xStorageFac = uno::Reference< lang::XSingleServiceFactory >( 91 m_xSMgr->createInstance( 92 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 93 "com.sun.star.embed.StorageFactory" ) ) ), 94 uno::UNO_QUERY ); 95 } 96 97 OSL_ENSURE( xStorageFac.is(), "Can't create storage factory!" ); 98 if ( xStorageFac.is() ) 99 xStorage = uno::Reference< embed::XStorage >( 100 xStorageFac->createInstance(), 101 uno::UNO_QUERY ); 102 103 if ( !xStorage.is() ) 104 throw uno::RuntimeException(); 105 106 return xStorage; 107 } 108 109 //========================================================================= 110 uno::Reference< embed::XStorage > 111 StorageElementFactory::createStorage( const rtl::OUString & rUri, 112 StorageAccessMode eMode ) 113 throw ( embed::InvalidStorageException, 114 lang::IllegalArgumentException, 115 io::IOException, 116 embed::StorageWrappedTargetException, 117 uno::RuntimeException ) 118 { 119 osl::MutexGuard aGuard( m_aMutex ); 120 121 if ( ( eMode != READ ) && 122 ( eMode != READ_WRITE_NOCREATE ) && 123 ( eMode != READ_WRITE_CREATE ) ) 124 throw lang::IllegalArgumentException( 125 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 126 "Invalid open mode!" ) ), 127 uno::Reference< uno::XInterface >(), 128 sal_Int16( 2 ) ); 129 130 Uri aUri( rUri ); 131 if ( aUri.isRoot() ) 132 { 133 throw lang::IllegalArgumentException( 134 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 135 "Root never has a storage!" ) ), 136 uno::Reference< uno::XInterface >(), 137 sal_Int16( 1 ) ); 138 } 139 140 rtl::OUString aUriKey 141 ( ( rUri.getStr()[ rUri.getLength() - 1 ] == sal_Unicode( '/' ) ) 142 ? rUri.copy( 0, rUri.getLength() - 1 ) 143 : rUri ); 144 145 StorageMap::iterator aIt ( m_aMap.begin() ); 146 StorageMap::iterator aEnd( m_aMap.end() ); 147 148 while ( aIt != aEnd ) 149 { 150 if ( (*aIt).first.first == aUriKey ) 151 { 152 // URI matches. Now, check open mode. 153 bool bMatch = true; 154 switch ( eMode ) 155 { 156 case READ: 157 // No need to check; storage is at least readable. 158 bMatch = true; 159 break; 160 161 case READ_WRITE_NOCREATE: 162 case READ_WRITE_CREATE: 163 // If found storage is writable, it can be used. 164 // If not, a new one must be created. 165 bMatch = (*aIt).first.second; 166 break; 167 } 168 169 if ( bMatch ) 170 break; 171 } 172 ++aIt; 173 } 174 175 if ( aIt == aEnd ) 176 { 177 uno::Reference< embed::XStorage > xParentStorage; 178 179 // documents never have a parent storage. 180 if ( !aUri.isDocument() ) 181 { 182 xParentStorage = queryParentStorage( aUriKey, eMode ); 183 184 if ( !xParentStorage.is() ) 185 { 186 // requested to create new storage, but failed? 187 OSL_ENSURE( eMode != READ_WRITE_CREATE, 188 "Unable to create parent storage!" ); 189 return xParentStorage; 190 } 191 } 192 193 uno::Reference< embed::XStorage > xStorage 194 = queryStorage( xParentStorage, aUriKey, eMode ); 195 196 if ( !xStorage.is() ) 197 { 198 // requested to create new storage, but failed? 199 OSL_ENSURE( eMode != READ_WRITE_CREATE, 200 "Unable to create storage!" ); 201 return xStorage; 202 } 203 204 bool bWritable = ( ( eMode == READ_WRITE_NOCREATE ) 205 || ( eMode == READ_WRITE_CREATE ) ); 206 207 std::auto_ptr< Storage > xElement( 208 new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage ) ); 209 210 aIt = m_aMap.insert( 211 StorageMap::value_type( 212 std::pair< rtl::OUString, bool >( aUriKey, bWritable ), 213 xElement.get() ) ).first; 214 215 aIt->second->m_aContainerIt = aIt; 216 xElement.release(); 217 return aIt->second; 218 } 219 else if ( osl_incrementInterlockedCount( &aIt->second->m_refCount ) > 1 ) 220 { 221 rtl::Reference< Storage > xElement( aIt->second ); 222 osl_decrementInterlockedCount( &aIt->second->m_refCount ); 223 return aIt->second; 224 } 225 else 226 { 227 osl_decrementInterlockedCount( &aIt->second->m_refCount ); 228 aIt->second->m_aContainerIt = m_aMap.end(); 229 230 uno::Reference< embed::XStorage > xParentStorage; 231 232 // documents never have a parent storage. 233 if ( !aUri.isDocument() ) 234 { 235 xParentStorage = queryParentStorage( aUriKey, eMode ); 236 237 if ( !xParentStorage.is() ) 238 { 239 // requested to create new storage, but failed? 240 OSL_ENSURE( eMode != READ_WRITE_CREATE, 241 "Unable to create parent storage!" ); 242 return xParentStorage; 243 } 244 } 245 246 uno::Reference< embed::XStorage > xStorage 247 = queryStorage( xParentStorage, aUriKey, eMode ); 248 249 if ( !xStorage.is() ) 250 { 251 // requested to create new storage, but failed? 252 OSL_ENSURE( eMode != READ_WRITE_CREATE, 253 "Unable to create storage!" ); 254 return xStorage; 255 } 256 257 aIt->second 258 = new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage ); 259 aIt->second->m_aContainerIt = aIt; 260 return aIt->second; 261 } 262 } 263 264 //========================================================================= 265 uno::Reference< io::XInputStream > 266 StorageElementFactory::createInputStream( const rtl::OUString & rUri, 267 const rtl::OUString & rPassword ) 268 throw ( embed::InvalidStorageException, 269 lang::IllegalArgumentException, 270 io::IOException, 271 embed::StorageWrappedTargetException, 272 packages::WrongPasswordException, 273 uno::RuntimeException ) 274 { 275 osl::MutexGuard aGuard( m_aMutex ); 276 277 uno::Reference< embed::XStorage > xParentStorage 278 = queryParentStorage( rUri, READ ); 279 280 // Each stream must have a parent storage. 281 if ( !xParentStorage.is() ) 282 return uno::Reference< io::XInputStream >(); 283 284 uno::Reference< io::XStream > xStream 285 = queryStream( xParentStorage, rUri, rPassword, READ, false ); 286 287 if ( !xStream.is() ) 288 return uno::Reference< io::XInputStream >(); 289 290 return xStream->getInputStream(); 291 } 292 293 //========================================================================= 294 uno::Reference< io::XOutputStream > 295 StorageElementFactory::createOutputStream( const rtl::OUString & rUri, 296 const rtl::OUString & rPassword, 297 bool bTruncate ) 298 throw ( embed::InvalidStorageException, 299 lang::IllegalArgumentException, 300 io::IOException, 301 embed::StorageWrappedTargetException, 302 packages::WrongPasswordException, 303 uno::RuntimeException ) 304 { 305 osl::MutexGuard aGuard( m_aMutex ); 306 307 uno::Reference< embed::XStorage > xParentStorage 308 = queryParentStorage( rUri, READ_WRITE_CREATE ); 309 310 // Each stream must have a parent storage. 311 if ( !xParentStorage.is() ) 312 { 313 OSL_ENSURE( false, 314 "StorageElementFactory::createOutputStream - " 315 "Unable to create parent storage!" ); 316 return uno::Reference< io::XOutputStream >(); 317 } 318 319 uno::Reference< io::XStream > xStream 320 = queryStream( 321 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate ); 322 323 if ( !xStream.is() ) 324 { 325 OSL_ENSURE( false, 326 "StorageElementFactory::createOutputStream - " 327 "Unable to create stream!" ); 328 return uno::Reference< io::XOutputStream >(); 329 } 330 331 // Note: We need a wrapper to hold a reference to the parent storage to 332 // ensure that nobody else owns it at the moment we want to commit 333 // our changes. (There can be only one writable instance at a time 334 // and even no writable instance if there is already another 335 // read-only instance!) 336 return uno::Reference< io::XOutputStream >( 337 new OutputStream( 338 m_xSMgr, rUri, xParentStorage, xStream->getOutputStream() ) ); 339 } 340 341 //========================================================================= 342 uno::Reference< io::XStream > 343 StorageElementFactory::createStream( const rtl::OUString & rUri, 344 const rtl::OUString & rPassword, 345 bool bTruncate ) 346 throw ( embed::InvalidStorageException, 347 lang::IllegalArgumentException, 348 io::IOException, 349 embed::StorageWrappedTargetException, 350 packages::WrongPasswordException, 351 uno::RuntimeException ) 352 { 353 osl::MutexGuard aGuard( m_aMutex ); 354 355 uno::Reference< embed::XStorage > xParentStorage 356 = queryParentStorage( rUri, READ_WRITE_CREATE ); 357 358 // Each stream must have a parent storage. 359 if ( !xParentStorage.is() ) 360 { 361 OSL_ENSURE( false, 362 "StorageElementFactory::createStream - " 363 "Unable to create parent storage!" ); 364 return uno::Reference< io::XStream >(); 365 } 366 367 uno::Reference< io::XStream > xStream 368 = queryStream( 369 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate ); 370 371 if ( !xStream.is() ) 372 { 373 OSL_ENSURE( false, 374 "StorageElementFactory::createStream - " 375 "Unable to create stream!" ); 376 return uno::Reference< io::XStream >(); 377 } 378 379 return uno::Reference< io::XStream >( 380 new Stream( m_xSMgr, rUri, xParentStorage, xStream ) ); 381 } 382 383 //========================================================================= 384 void StorageElementFactory::releaseElement( Storage * pElement ) SAL_THROW( () ) 385 { 386 OSL_ASSERT( pElement ); 387 osl::MutexGuard aGuard( m_aMutex ); 388 if ( pElement->m_aContainerIt != m_aMap.end() ) 389 m_aMap.erase( pElement->m_aContainerIt ); 390 } 391 392 //========================================================================= 393 // 394 // Non-UNO interface 395 // 396 //========================================================================= 397 398 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage( 399 const rtl::OUString & rUri, StorageAccessMode eMode ) 400 throw ( embed::InvalidStorageException, 401 lang::IllegalArgumentException, 402 io::IOException, 403 embed::StorageWrappedTargetException, 404 uno::RuntimeException ) 405 { 406 uno::Reference< embed::XStorage > xParentStorage; 407 408 Uri aUri( rUri ); 409 Uri aParentUri( aUri.getParentUri() ); 410 if ( !aParentUri.isRoot() ) 411 { 412 xParentStorage = createStorage( aUri.getParentUri(), eMode ); 413 OSL_ENSURE( xParentStorage.is() 414 // requested to create new storage, but failed? 415 || ( eMode != READ_WRITE_CREATE ), 416 "StorageElementFactory::queryParentStorage - No storage!" ); 417 } 418 return xParentStorage; 419 } 420 421 //========================================================================= 422 uno::Reference< embed::XStorage > StorageElementFactory::queryStorage( 423 const uno::Reference< embed::XStorage > & xParentStorage, 424 const rtl::OUString & rUri, 425 StorageAccessMode eMode ) 426 throw ( embed::InvalidStorageException, 427 lang::IllegalArgumentException, 428 io::IOException, 429 embed::StorageWrappedTargetException, 430 uno::RuntimeException ) 431 { 432 uno::Reference< embed::XStorage > xStorage; 433 434 Uri aUri( rUri ); 435 436 if ( !xParentStorage.is() ) 437 { 438 // document storage 439 440 xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() ); 441 442 if ( !xStorage.is() ) 443 { 444 if ( eMode == READ_WRITE_CREATE ) 445 throw lang::IllegalArgumentException( 446 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 447 "Invalid open mode: document storages cannot be " 448 "created!" ) ), 449 uno::Reference< uno::XInterface >(), 450 sal_Int16( 2 ) ); 451 else 452 throw embed::InvalidStorageException( 453 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 454 "Invalid document id!" ) ), 455 uno::Reference< uno::XInterface >() ); 456 } 457 458 // match xStorage's open mode against requested open mode 459 460 uno::Reference< beans::XPropertySet > xPropSet( 461 xStorage, uno::UNO_QUERY ); 462 OSL_ENSURE( xPropSet.is(), 463 "StorageElementFactory::queryStorage - " 464 "No XPropertySet interface!" ); 465 try 466 { 467 uno::Any aPropValue = xPropSet->getPropertyValue( 468 rtl::OUString( 469 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) ); 470 471 sal_Int32 nOpenMode = 0; 472 if ( aPropValue >>= nOpenMode ) 473 { 474 switch ( eMode ) 475 { 476 case READ: 477 if ( !( nOpenMode & embed::ElementModes::READ ) ) 478 { 479 // document opened, but not readable. 480 throw embed::InvalidStorageException( 481 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 482 "Storage is open, but not readable!" ) ), 483 uno::Reference< uno::XInterface >() ); 484 } 485 // storage okay 486 break; 487 488 case READ_WRITE_NOCREATE: 489 case READ_WRITE_CREATE: 490 if ( !( nOpenMode & embed::ElementModes::WRITE ) ) 491 { 492 // document opened, but not writable. 493 throw embed::InvalidStorageException( 494 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 495 "Storage is open, but not writable!" ) ), 496 uno::Reference< uno::XInterface >() ); 497 } 498 // storage okay 499 break; 500 } 501 } 502 else 503 { 504 OSL_ENSURE( 505 false, "Bug! Value of property OpenMode has wrong type!" ); 506 507 throw uno::RuntimeException( 508 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 509 "Bug! Value of property OpenMode has wrong type!" ) ), 510 uno::Reference< uno::XInterface >() ); 511 } 512 } 513 catch ( beans::UnknownPropertyException const & e ) 514 { 515 OSL_ENSURE( false, "Property OpenMode not supported!" ); 516 517 throw embed::StorageWrappedTargetException( 518 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 519 "Bug! Value of property OpenMode has wrong type!" ) ), 520 uno::Reference< uno::XInterface >(), 521 uno::makeAny( e ) ); 522 } 523 catch ( lang::WrappedTargetException const & e ) 524 { 525 OSL_ENSURE( false, "Caught WrappedTargetException!" ); 526 527 throw embed::StorageWrappedTargetException( 528 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 529 "WrappedTargetException during getPropertyValue!" ) ), 530 uno::Reference< uno::XInterface >(), 531 uno::makeAny( e ) ); 532 } 533 } 534 else 535 { 536 // sub storage 537 538 const rtl::OUString & rName = aUri.getDecodedName(); 539 540 if ( eMode == READ ) 541 { 542 try 543 { 544 sal_Int32 nOpenMode = embed::ElementModes::READ 545 | embed::ElementModes::NOCREATE; 546 xStorage 547 = xParentStorage->openStorageElement( rName, nOpenMode ); 548 } 549 catch ( io::IOException const & ) 550 { 551 // Another chance: Try to clone storage. 552 xStorage = createTemporaryStorage(); 553 xParentStorage->copyStorageElementLastCommitTo( rName, 554 xStorage ); 555 } 556 } 557 else 558 { 559 sal_Int32 nOpenMode = embed::ElementModes::READWRITE; 560 if ( eMode == READ_WRITE_NOCREATE ) 561 nOpenMode |= embed::ElementModes::NOCREATE; 562 563 xStorage = xParentStorage->openStorageElement( rName, nOpenMode ); 564 } 565 } 566 567 OSL_ENSURE( xStorage.is() || ( eMode != READ_WRITE_CREATE ), 568 "StorageElementFactory::queryStorage - No storage!" ); 569 return xStorage; 570 } 571 572 //========================================================================= 573 uno::Reference< io::XStream > 574 StorageElementFactory::queryStream( 575 const uno::Reference< embed::XStorage > & xParentStorage, 576 const rtl::OUString & rUri, 577 const rtl::OUString & rPassword, 578 StorageAccessMode eMode, 579 bool bTruncate ) 580 throw ( embed::InvalidStorageException, 581 lang::IllegalArgumentException, 582 io::IOException, 583 embed::StorageWrappedTargetException, 584 packages::WrongPasswordException, 585 uno::RuntimeException ) 586 { 587 osl::MutexGuard aGuard( m_aMutex ); 588 589 if ( !xParentStorage.is() ) 590 { 591 throw lang::IllegalArgumentException( 592 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 593 "No parent storage!" ) ), 594 uno::Reference< uno::XInterface >(), 595 sal_Int16( 2 ) ); 596 } 597 598 Uri aUri( rUri ); 599 if ( aUri.isRoot() ) 600 { 601 throw lang::IllegalArgumentException( 602 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 603 "Root never is a stream!" ) ), 604 uno::Reference< uno::XInterface >(), 605 sal_Int16( 2 ) ); 606 } 607 else if ( aUri.isDocument() ) 608 { 609 throw lang::IllegalArgumentException( 610 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 611 "A document never is a stream!" ) ), 612 uno::Reference< uno::XInterface >(), 613 sal_Int16( 2 ) ); 614 } 615 616 sal_Int32 nOpenMode; 617 switch ( eMode ) 618 { 619 case READ: 620 nOpenMode = embed::ElementModes::READ 621 | embed::ElementModes::NOCREATE 622 | embed::ElementModes::SEEKABLE; 623 break; 624 625 case READ_WRITE_NOCREATE: 626 nOpenMode = embed::ElementModes::READWRITE 627 | embed::ElementModes::NOCREATE 628 | embed::ElementModes::SEEKABLE; 629 630 if ( bTruncate ) 631 nOpenMode |= embed::ElementModes::TRUNCATE; 632 633 break; 634 635 case READ_WRITE_CREATE: 636 nOpenMode = embed::ElementModes::READWRITE 637 | embed::ElementModes::SEEKABLE; 638 639 if ( bTruncate ) 640 nOpenMode |= embed::ElementModes::TRUNCATE; 641 642 break; 643 644 default: 645 OSL_ENSURE( false, 646 "StorageElementFactory::queryStream : Unknown open mode!" ); 647 648 throw embed::InvalidStorageException( 649 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 650 "Unknown open mode!" ) ), 651 uno::Reference< uno::XInterface >() ); 652 } 653 654 // No object re-usage mechanism; streams are seekable => not stateless. 655 656 uno::Reference< io::XStream > xStream; 657 if ( rPassword.getLength() > 0 ) 658 { 659 if ( eMode == READ ) 660 { 661 try 662 { 663 xStream = xParentStorage->cloneEncryptedStreamElement( 664 aUri.getDecodedName(), 665 rPassword ); 666 } 667 catch ( packages::NoEncryptionException const & ) 668 { 669 xStream 670 = xParentStorage->cloneStreamElement( aUri.getDecodedName() ); 671 } 672 } 673 else 674 { 675 try 676 { 677 xStream = xParentStorage->openEncryptedStreamElement( 678 aUri.getDecodedName(), 679 nOpenMode, 680 rPassword ); 681 } 682 catch ( packages::NoEncryptionException const & ) 683 { 684 xStream 685 = xParentStorage->openStreamElement( aUri.getDecodedName(), 686 nOpenMode ); 687 } 688 } 689 } 690 else 691 { 692 if ( eMode == READ ) 693 { 694 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() ); 695 } 696 else 697 { 698 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(), 699 nOpenMode ); 700 } 701 } 702 703 if ( !xStream.is() ) 704 { 705 throw embed::InvalidStorageException( 706 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 707 "No stream!" ) ), 708 uno::Reference< uno::XInterface >() ); 709 } 710 711 return xStream; 712 } 713