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