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