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