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