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 96 : StorageElementFactory::StorageElementFactory(
46 : const uno::Reference< uno::XComponentContext > & rxContext,
47 : const rtl::Reference< OfficeDocumentsManager > & xDocsMgr )
48 : : m_xDocsMgr( xDocsMgr ),
49 96 : m_xContext( rxContext )
50 : {
51 96 : }
52 :
53 :
54 184 : StorageElementFactory::~StorageElementFactory()
55 : {
56 : OSL_ENSURE( m_aMap.empty(),
57 : "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
58 184 : }
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 624 : 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 624 : osl::MutexGuard aGuard( m_aMutex );
96 :
97 624 : 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 1248 : Uri aUri( rUri );
107 624 : 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 624 : ( rUri.endsWith("/")
118 0 : ? rUri.copy( 0, rUri.getLength() - 1 )
119 1248 : : rUri );
120 :
121 624 : StorageMap::iterator aIt ( m_aMap.begin() );
122 624 : StorageMap::iterator aEnd( m_aMap.end() );
123 :
124 1248 : 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 624 : if ( aIt == aEnd )
152 : {
153 624 : uno::Reference< embed::XStorage > xParentStorage;
154 :
155 : // documents never have a parent storage.
156 624 : 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 1248 : = queryStorage( xParentStorage, aUriKey, eMode );
171 :
172 624 : 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 624 : || ( eMode == READ_WRITE_CREATE ) );
182 :
183 : std::unique_ptr< Storage > xElement(
184 1248 : 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 624 : xElement.get() ) ).first;
190 :
191 624 : aIt->second->m_aContainerIt = aIt;
192 624 : xElement.release();
193 1248 : 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 624 : }
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 624 : void StorageElementFactory::releaseElement( Storage * pElement )
355 : {
356 : OSL_ASSERT( pElement );
357 624 : osl::MutexGuard aGuard( m_aMutex );
358 624 : if ( pElement->m_aContainerIt != m_aMap.end() )
359 624 : m_aMap.erase( pElement->m_aContainerIt );
360 624 : }
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 624 : 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 624 : uno::Reference< embed::XStorage > xStorage;
403 :
404 1248 : Uri aUri( rUri );
405 :
406 624 : if ( !xParentStorage.is() )
407 : {
408 : // document storage
409 :
410 624 : xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() );
411 :
412 624 : 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 624 : xStorage, uno::UNO_QUERY );
431 : OSL_ENSURE( xPropSet.is(),
432 : "StorageElementFactory::queryStorage - "
433 : "No XPropertySet interface!" );
434 : try
435 : {
436 624 : uno::Any aPropValue = xPropSet->getPropertyValue(
437 624 : OUString( "OpenMode" ) );
438 :
439 624 : sal_Int32 nOpenMode = 0;
440 624 : if ( aPropValue >>= nOpenMode )
441 : {
442 624 : switch ( eMode )
443 : {
444 : case READ:
445 624 : if ( !( nOpenMode & embed::ElementModes::READ ) )
446 : {
447 : // document opened, but not readable.
448 : throw embed::InvalidStorageException(
449 0 : "Storage is open, but not readable!" );
450 : }
451 : // storage okay
452 624 : break;
453 :
454 : case READ_WRITE_NOCREATE:
455 : case READ_WRITE_CREATE:
456 0 : if ( !( nOpenMode & embed::ElementModes::WRITE ) )
457 : {
458 : // document opened, but not writable.
459 : throw embed::InvalidStorageException(
460 0 : "Storage is open, but not writable!" );
461 : }
462 : // storage okay
463 0 : break;
464 : }
465 : }
466 : else
467 : {
468 : OSL_FAIL(
469 : "Bug! Value of property OpenMode has wrong type!" );
470 :
471 : throw uno::RuntimeException(
472 0 : "Bug! Value of property OpenMode has wrong type!" );
473 624 : }
474 : }
475 0 : catch ( beans::UnknownPropertyException const & e )
476 : {
477 : OSL_FAIL( "Property OpenMode not supported!" );
478 :
479 : throw embed::StorageWrappedTargetException(
480 : OUString(
481 : "Bug! Value of property OpenMode has wrong type!" ),
482 : uno::Reference< uno::XInterface >(),
483 0 : uno::makeAny( e ) );
484 : }
485 0 : catch ( lang::WrappedTargetException const & e )
486 : {
487 : OSL_FAIL( "Caught WrappedTargetException!" );
488 :
489 : throw embed::StorageWrappedTargetException(
490 : OUString(
491 : "WrappedTargetException during getPropertyValue!" ),
492 : uno::Reference< uno::XInterface >(),
493 0 : uno::makeAny( e ) );
494 624 : }
495 : }
496 : else
497 : {
498 : // sub storage
499 :
500 0 : const OUString & rName = aUri.getDecodedName();
501 :
502 0 : if ( eMode == READ )
503 : {
504 : try
505 : {
506 : sal_Int32 nOpenMode = embed::ElementModes::READ
507 0 : | embed::ElementModes::NOCREATE;
508 : xStorage
509 0 : = xParentStorage->openStorageElement( rName, nOpenMode );
510 : }
511 0 : catch ( io::IOException const & )
512 : {
513 : // Another chance: Try to clone storage.
514 0 : xStorage = createTemporaryStorage();
515 0 : xParentStorage->copyStorageElementLastCommitTo( rName,
516 0 : xStorage );
517 : }
518 : }
519 : else
520 : {
521 0 : sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
522 0 : if ( eMode == READ_WRITE_NOCREATE )
523 0 : nOpenMode |= embed::ElementModes::NOCREATE;
524 :
525 0 : xStorage = xParentStorage->openStorageElement( rName, nOpenMode );
526 : }
527 : }
528 :
529 : OSL_ENSURE( xStorage.is() || ( eMode != READ_WRITE_CREATE ),
530 : "StorageElementFactory::queryStorage - No storage!" );
531 1248 : return xStorage;
532 : }
533 :
534 :
535 : uno::Reference< io::XStream >
536 0 : StorageElementFactory::queryStream(
537 : const uno::Reference< embed::XStorage > & xParentStorage,
538 : const OUString & rUri,
539 : const OUString & rPassword,
540 : StorageAccessMode eMode,
541 : bool bTruncate )
542 : throw ( embed::InvalidStorageException,
543 : lang::IllegalArgumentException,
544 : io::IOException,
545 : embed::StorageWrappedTargetException,
546 : packages::WrongPasswordException,
547 : uno::RuntimeException )
548 : {
549 0 : osl::MutexGuard aGuard( m_aMutex );
550 :
551 0 : if ( !xParentStorage.is() )
552 : {
553 : throw lang::IllegalArgumentException(
554 : OUString(
555 : "No parent storage!" ),
556 : uno::Reference< uno::XInterface >(),
557 0 : sal_Int16( 2 ) );
558 : }
559 :
560 0 : Uri aUri( rUri );
561 0 : if ( aUri.isRoot() )
562 : {
563 : throw lang::IllegalArgumentException(
564 : OUString(
565 : "Root never is a stream!" ),
566 : uno::Reference< uno::XInterface >(),
567 0 : sal_Int16( 2 ) );
568 : }
569 0 : else if ( aUri.isDocument() )
570 : {
571 : throw lang::IllegalArgumentException(
572 : OUString(
573 : "A document never is a stream!" ),
574 : uno::Reference< uno::XInterface >(),
575 0 : sal_Int16( 2 ) );
576 : }
577 :
578 : sal_Int32 nOpenMode;
579 0 : switch ( eMode )
580 : {
581 : case READ:
582 : nOpenMode = embed::ElementModes::READ
583 : | embed::ElementModes::NOCREATE
584 0 : | embed::ElementModes::SEEKABLE;
585 0 : break;
586 :
587 : case READ_WRITE_NOCREATE:
588 : nOpenMode = embed::ElementModes::READWRITE
589 : | embed::ElementModes::NOCREATE
590 0 : | embed::ElementModes::SEEKABLE;
591 :
592 0 : if ( bTruncate )
593 0 : nOpenMode |= embed::ElementModes::TRUNCATE;
594 :
595 0 : break;
596 :
597 : case READ_WRITE_CREATE:
598 : nOpenMode = embed::ElementModes::READWRITE
599 0 : | embed::ElementModes::SEEKABLE;
600 :
601 0 : if ( bTruncate )
602 0 : nOpenMode |= embed::ElementModes::TRUNCATE;
603 :
604 0 : break;
605 :
606 : default:
607 : OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
608 :
609 : throw embed::InvalidStorageException(
610 : OUString(
611 : "Unknown open mode!" ),
612 0 : uno::Reference< uno::XInterface >() );
613 : }
614 :
615 : // No object re-usage mechanism; streams are seekable => not stateless.
616 :
617 0 : uno::Reference< io::XStream > xStream;
618 0 : if ( !rPassword.isEmpty() )
619 : {
620 0 : if ( eMode == READ )
621 : {
622 : try
623 : {
624 0 : xStream = xParentStorage->cloneEncryptedStreamElement(
625 0 : aUri.getDecodedName(),
626 0 : rPassword );
627 : }
628 0 : catch ( packages::NoEncryptionException const & )
629 : {
630 : xStream
631 0 : = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
632 : }
633 : }
634 : else
635 : {
636 : try
637 : {
638 0 : xStream = xParentStorage->openEncryptedStreamElement(
639 0 : aUri.getDecodedName(),
640 : nOpenMode,
641 0 : rPassword );
642 : }
643 0 : catch ( packages::NoEncryptionException const & )
644 : {
645 : xStream
646 0 : = xParentStorage->openStreamElement( aUri.getDecodedName(),
647 0 : nOpenMode );
648 : }
649 : }
650 : }
651 : else
652 : {
653 0 : if ( eMode == READ )
654 : {
655 0 : xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
656 : }
657 : else
658 : {
659 0 : xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
660 0 : nOpenMode );
661 : }
662 : }
663 :
664 0 : if ( !xStream.is() )
665 : {
666 : throw embed::InvalidStorageException(
667 : OUString(
668 : "No stream!" ),
669 0 : uno::Reference< uno::XInterface >() );
670 : }
671 :
672 0 : return xStream;
673 : }
674 :
675 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|