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
StorageElementFactory(const uno::Reference<lang::XMultiServiceFactory> & xSMgr,const rtl::Reference<OfficeDocumentsManager> & xDocsMgr)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 //=========================================================================
~StorageElementFactory()70 StorageElementFactory::~StorageElementFactory()
71 {
72 OSL_ENSURE( m_aMap.size() == 0,
73 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
74 }
75
76 //=========================================================================
77 uno::Reference< embed::XStorage >
createTemporaryStorage()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 >
createStorage(const rtl::OUString & rUri,StorageAccessMode eMode)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 >
createInputStream(const rtl::OUString & rUri,const rtl::OUString & rPassword)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 >
createOutputStream(const rtl::OUString & rUri,const rtl::OUString & rPassword,bool bTruncate)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 >
createStream(const rtl::OUString & rUri,const rtl::OUString & rPassword,bool bTruncate)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 //=========================================================================
releaseElement(Storage * pElement)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
queryParentStorage(const rtl::OUString & rUri,StorageAccessMode eMode)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 //=========================================================================
queryStorage(const uno::Reference<embed::XStorage> & xParentStorage,const rtl::OUString & rUri,StorageAccessMode eMode)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 >
queryStream(const uno::Reference<embed::XStorage> & xParentStorage,const rtl::OUString & rUri,const rtl::OUString & rPassword,StorageAccessMode eMode,bool bTruncate)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