bump product version to 7.6.3.2-android
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_content.cxx
blob5bc1f79ffb59f9846a31f0e17193e7ba9b337d06
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
27 #include <sal/config.h>
29 #include <string_view>
31 #include <o3tl/string_view.hxx>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <com/sun/star/beans/IllegalTypeException.hpp>
35 #include <com/sun/star/beans/PropertyAttribute.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/InvalidStorageException.hpp>
38 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
39 #include <com/sun/star/embed/XTransactedObject.hpp>
40 #include <com/sun/star/io/BufferSizeExceededException.hpp>
41 #include <com/sun/star/io/IOException.hpp>
42 #include <com/sun/star/io/NotConnectedException.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/io/XActiveDataStreamer.hpp>
45 #include <com/sun/star/lang/IllegalAccessException.hpp>
46 #include <com/sun/star/packages/WrongPasswordException.hpp>
47 #include <com/sun/star/task/DocumentPasswordRequest.hpp>
48 #include <com/sun/star/task/XInteractionPassword.hpp>
49 #include <com/sun/star/ucb/CommandFailedException.hpp>
50 #include <com/sun/star/ucb/ContentAction.hpp>
51 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
52 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
53 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
54 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
55 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
56 #include <com/sun/star/ucb/NameClash.hpp>
57 #include <com/sun/star/ucb/NameClashException.hpp>
58 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
59 #include <com/sun/star/ucb/OpenMode.hpp>
60 #include <com/sun/star/ucb/TransferInfo.hpp>
61 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
62 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
63 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
64 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
65 #include <com/sun/star/ucb/XCommandInfo.hpp>
66 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
68 #include <comphelper/propertysequence.hxx>
69 #include <cppuhelper/queryinterface.hxx>
70 #include <ucbhelper/cancelcommandexecution.hxx>
71 #include <ucbhelper/contentidentifier.hxx>
72 #include <ucbhelper/propertyvalueset.hxx>
73 #include <ucbhelper/macros.hxx>
74 #include <utility>
76 #include "tdoc_content.hxx"
77 #include "tdoc_resultset.hxx"
78 #include "tdoc_passwordrequest.hxx"
80 #include "../inc/urihelper.hxx"
82 using namespace com::sun::star;
83 using namespace tdoc_ucp;
86 static ContentType lcl_getContentType( std::u16string_view rType )
88 if ( rType == TDOC_ROOT_CONTENT_TYPE )
89 return ROOT;
90 else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
91 return DOCUMENT;
92 else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
93 return FOLDER;
94 else if ( rType == TDOC_STREAM_CONTENT_TYPE )
95 return STREAM;
96 else
98 OSL_FAIL( "Content::Content - unsupported content type string" );
99 return STREAM;
104 // Content Implementation.
107 // static ( "virtual" ctor )
108 rtl::Reference<Content> Content::create(
109 const uno::Reference< uno::XComponentContext >& rxContext,
110 ContentProvider* pProvider,
111 const uno::Reference< ucb::XContentIdentifier >& Identifier )
113 // Fail, if resource does not exist.
114 ContentProperties aProps;
115 if ( !Content::loadData( pProvider,
116 Uri( Identifier->getContentIdentifier() ),
117 aProps ) )
118 return nullptr;
120 return new Content( rxContext, pProvider, Identifier, std::move(aProps) );
124 // static ( "virtual" ctor )
125 rtl::Reference<Content> Content::create(
126 const uno::Reference< uno::XComponentContext >& rxContext,
127 ContentProvider* pProvider,
128 const uno::Reference< ucb::XContentIdentifier >& Identifier,
129 const ucb::ContentInfo& Info )
131 if ( Info.Type.isEmpty() )
132 return nullptr;
134 if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
136 OSL_FAIL( "Content::create - unsupported content type!" );
137 return nullptr;
140 return new Content( rxContext, pProvider, Identifier, Info );
144 Content::Content(
145 const uno::Reference< uno::XComponentContext > & rxContext,
146 ContentProvider * pProvider,
147 const uno::Reference< ucb::XContentIdentifier > & Identifier,
148 ContentProperties aProps )
149 : ContentImplHelper( rxContext, pProvider, Identifier ),
150 m_aProps(std::move( aProps )),
151 m_eState( PERSISTENT ),
152 m_pProvider( pProvider )
157 // ctor for a content just created via XContentCreator::createNewContent()
158 Content::Content(
159 const uno::Reference< uno::XComponentContext >& rxContext,
160 ContentProvider* pProvider,
161 const uno::Reference< ucb::XContentIdentifier >& Identifier,
162 const ucb::ContentInfo& Info )
163 : ContentImplHelper( rxContext, pProvider, Identifier ),
164 m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
165 m_eState( TRANSIENT ),
166 m_pProvider( pProvider )
171 // virtual
172 Content::~Content()
177 // XInterface methods.
180 // virtual
181 void SAL_CALL Content::acquire()
182 noexcept
184 ContentImplHelper::acquire();
188 // virtual
189 void SAL_CALL Content::release()
190 noexcept
192 ContentImplHelper::release();
196 // virtual
197 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
199 uno::Any aRet = ContentImplHelper::queryInterface( rType );
201 if ( !aRet.hasValue() )
203 aRet = cppu::queryInterface(
204 rType, static_cast< ucb::XContentCreator * >( this ) );
205 if ( aRet.hasValue() )
207 if ( !m_aProps.isContentCreator() )
208 return uno::Any();
212 return aRet;
216 // XTypeProvider methods.
219 XTYPEPROVIDER_COMMON_IMPL( Content );
222 // virtual
223 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
225 if ( m_aProps.isContentCreator() )
227 static cppu::OTypeCollection s_aFolderTypes(
228 CPPU_TYPE_REF( lang::XTypeProvider ),
229 CPPU_TYPE_REF( lang::XServiceInfo ),
230 CPPU_TYPE_REF( lang::XComponent ),
231 CPPU_TYPE_REF( ucb::XContent ),
232 CPPU_TYPE_REF( ucb::XCommandProcessor ),
233 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
234 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
235 CPPU_TYPE_REF( beans::XPropertyContainer ),
236 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
237 CPPU_TYPE_REF( container::XChild ),
238 CPPU_TYPE_REF( ucb::XContentCreator ) );
240 return s_aFolderTypes.getTypes();
242 else
244 static cppu::OTypeCollection s_aDocumentTypes(
245 CPPU_TYPE_REF( lang::XTypeProvider ),
246 CPPU_TYPE_REF( lang::XServiceInfo ),
247 CPPU_TYPE_REF( lang::XComponent ),
248 CPPU_TYPE_REF( ucb::XContent ),
249 CPPU_TYPE_REF( ucb::XCommandProcessor ),
250 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
251 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
252 CPPU_TYPE_REF( beans::XPropertyContainer ),
253 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
254 CPPU_TYPE_REF( container::XChild ) );
256 return s_aDocumentTypes.getTypes();
261 // XServiceInfo methods.
264 // virtual
265 OUString SAL_CALL Content::getImplementationName()
267 return "com.sun.star.comp.ucb.TransientDocumentsContent";
271 // virtual
272 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
274 osl::Guard< osl::Mutex > aGuard( m_aMutex );
276 uno::Sequence< OUString > aSNS( 1 );
278 if ( m_aProps.getType() == STREAM )
279 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsStreamContent";
280 else if ( m_aProps.getType() == FOLDER )
281 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsFolderContent";
282 else if ( m_aProps.getType() == DOCUMENT )
283 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsDocumentContent";
284 else
285 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsRootContent";
287 return aSNS;
291 // XContent methods.
294 // virtual
295 OUString SAL_CALL Content::getContentType()
297 osl::Guard< osl::Mutex > aGuard( m_aMutex );
298 return m_aProps.getContentType();
302 // virtual
303 uno::Reference< ucb::XContentIdentifier > SAL_CALL
304 Content::getIdentifier()
307 osl::Guard< osl::Mutex > aGuard( m_aMutex );
309 // Transient?
310 if ( m_eState == TRANSIENT )
312 // Transient contents have no identifier.
313 return uno::Reference< ucb::XContentIdentifier >();
316 return ContentImplHelper::getIdentifier();
320 // XCommandProcessor methods.
323 // virtual
324 uno::Any SAL_CALL Content::execute(
325 const ucb::Command& aCommand,
326 sal_Int32 /*CommandId*/,
327 const uno::Reference< ucb::XCommandEnvironment >& Environment )
329 uno::Any aRet;
331 if ( aCommand.Name == "getPropertyValues" )
334 // getPropertyValues
337 uno::Sequence< beans::Property > Properties;
338 if ( !( aCommand.Argument >>= Properties ) )
340 ucbhelper::cancelCommandExecution(
341 uno::Any( lang::IllegalArgumentException(
342 "Wrong argument type!",
343 static_cast< cppu::OWeakObject * >( this ),
344 -1 ) ),
345 Environment );
346 // Unreachable
349 aRet <<= getPropertyValues( Properties );
351 else if ( aCommand.Name == "setPropertyValues" )
354 // setPropertyValues
357 uno::Sequence< beans::PropertyValue > aProperties;
358 if ( !( aCommand.Argument >>= aProperties ) )
360 ucbhelper::cancelCommandExecution(
361 uno::Any( lang::IllegalArgumentException(
362 "Wrong argument type!",
363 static_cast< cppu::OWeakObject * >( this ),
364 -1 ) ),
365 Environment );
366 // Unreachable
369 if ( !aProperties.hasElements() )
371 ucbhelper::cancelCommandExecution(
372 uno::Any( lang::IllegalArgumentException(
373 "No properties!",
374 static_cast< cppu::OWeakObject * >( this ),
375 -1 ) ),
376 Environment );
377 // Unreachable
380 aRet <<= setPropertyValues( aProperties, Environment );
382 else if ( aCommand.Name == "getPropertySetInfo" )
385 // getPropertySetInfo
388 aRet <<= getPropertySetInfo( Environment );
390 else if ( aCommand.Name == "getCommandInfo" )
393 // getCommandInfo
396 aRet <<= getCommandInfo( Environment );
398 else if ( aCommand.Name == "open" )
401 // open
404 ucb::OpenCommandArgument2 aOpenCommand;
405 if ( !( aCommand.Argument >>= aOpenCommand ) )
407 ucbhelper::cancelCommandExecution(
408 uno::Any( lang::IllegalArgumentException(
409 "Wrong argument type!",
410 static_cast< cppu::OWeakObject * >( this ),
411 -1 ) ),
412 Environment );
413 // Unreachable
416 aRet = open( aOpenCommand, Environment );
418 else if ( aCommand.Name == "insert" )
421 // insert ( Supported by folders and streams only )
424 ContentType eType = m_aProps.getType();
425 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
427 ucbhelper::cancelCommandExecution(
428 uno::Any( ucb::UnsupportedCommandException(
429 "insert command only supported by "
430 "folders and streams!",
431 static_cast< cppu::OWeakObject * >( this ) ) ),
432 Environment );
433 // Unreachable
436 if ( eType == STREAM )
438 Uri aUri( m_xIdentifier->getContentIdentifier() );
439 Uri aParentUri( aUri.getParentUri() );
440 if ( aParentUri.isDocument() )
442 ucbhelper::cancelCommandExecution(
443 uno::Any( ucb::UnsupportedCommandException(
444 "insert command not supported by "
445 "streams that are direct children "
446 "of document root!",
447 static_cast< cppu::OWeakObject * >(
448 this ) ) ),
449 Environment );
450 // Unreachable
454 ucb::InsertCommandArgument aArg;
455 if ( !( aCommand.Argument >>= aArg ) )
457 ucbhelper::cancelCommandExecution(
458 uno::Any( lang::IllegalArgumentException(
459 "Wrong argument type!",
460 static_cast< cppu::OWeakObject * >( this ),
461 -1 ) ),
462 Environment );
463 // Unreachable
466 sal_Int32 nNameClash = aArg.ReplaceExisting
467 ? ucb::NameClash::OVERWRITE
468 : ucb::NameClash::ERROR;
469 insert( aArg.Data, nNameClash, Environment );
471 else if ( aCommand.Name == "delete" )
474 // delete ( Supported by folders and streams only )
478 osl::MutexGuard aGuard( m_aMutex );
480 ContentType eType = m_aProps.getType();
481 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
483 ucbhelper::cancelCommandExecution(
484 uno::Any( ucb::UnsupportedCommandException(
485 "delete command only supported by "
486 "folders and streams!",
487 static_cast< cppu::OWeakObject * >(
488 this ) ) ),
489 Environment );
490 // Unreachable
494 bool bDeletePhysical = false;
495 aCommand.Argument >>= bDeletePhysical;
496 destroy( bDeletePhysical, Environment );
498 // Remove own and all children's persistent data.
499 if ( !removeData() )
501 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
503 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
504 }));
505 ucbhelper::cancelCommandExecution(
506 ucb::IOErrorCode_CANT_WRITE,
507 aArgs,
508 Environment,
509 "Cannot remove persistent data!",
510 this );
511 // Unreachable
514 // Remove own and all children's Additional Core Properties.
515 removeAdditionalPropertySet();
517 else if ( aCommand.Name == "transfer" )
520 // transfer ( Supported by document and folders only )
524 osl::MutexGuard aGuard( m_aMutex );
526 ContentType eType = m_aProps.getType();
527 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
529 ucbhelper::cancelCommandExecution(
530 uno::Any( ucb::UnsupportedCommandException(
531 "transfer command only supported "
532 "by folders and documents!",
533 static_cast< cppu::OWeakObject * >(
534 this ) ) ),
535 Environment );
536 // Unreachable
540 ucb::TransferInfo aInfo;
541 if ( !( aCommand.Argument >>= aInfo ) )
543 OSL_FAIL( "Wrong argument type!" );
544 ucbhelper::cancelCommandExecution(
545 uno::Any( lang::IllegalArgumentException(
546 "Wrong argument type!",
547 static_cast< cppu::OWeakObject * >( this ),
548 -1 ) ),
549 Environment );
550 // Unreachable
553 transfer( aInfo, Environment );
555 else if ( aCommand.Name == "createNewContent" )
558 // createNewContent ( Supported by document and folders only )
562 osl::MutexGuard aGuard( m_aMutex );
564 ContentType eType = m_aProps.getType();
565 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
567 ucbhelper::cancelCommandExecution(
568 uno::Any( ucb::UnsupportedCommandException(
569 "createNewContent command only "
570 "supported by folders and "
571 "documents!",
572 static_cast< cppu::OWeakObject * >(
573 this ) ) ),
574 Environment );
575 // Unreachable
579 ucb::ContentInfo aInfo;
580 if ( !( aCommand.Argument >>= aInfo ) )
582 OSL_FAIL( "Wrong argument type!" );
583 ucbhelper::cancelCommandExecution(
584 uno::Any( lang::IllegalArgumentException(
585 "Wrong argument type!",
586 static_cast< cppu::OWeakObject * >( this ),
587 -1 ) ),
588 Environment );
589 // Unreachable
592 aRet <<= createNewContent( aInfo );
594 else
597 // Unsupported command
600 ucbhelper::cancelCommandExecution(
601 uno::Any( ucb::UnsupportedCommandException(
602 OUString(),
603 static_cast< cppu::OWeakObject * >( this ) ) ),
604 Environment );
605 // Unreachable
608 return aRet;
612 // virtual
613 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
618 // XContentCreator methods.
621 // virtual
622 uno::Sequence< ucb::ContentInfo > SAL_CALL
623 Content::queryCreatableContentsInfo()
625 return m_aProps.getCreatableContentsInfo();
629 // virtual
630 uno::Reference< ucb::XContent > SAL_CALL
631 Content::createNewContent( const ucb::ContentInfo& Info )
633 if ( m_aProps.isContentCreator() )
635 osl::Guard< osl::Mutex > aGuard( m_aMutex );
637 if ( Info.Type.isEmpty() )
638 return uno::Reference< ucb::XContent >();
640 bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
642 // streams cannot be created as direct children of document root
643 if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
645 OSL_FAIL( "Content::createNewContent - streams cannot be "
646 "created as direct children of document root!" );
647 return uno::Reference< ucb::XContent >();
649 if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
651 OSL_FAIL( "Content::createNewContent - unsupported type!" );
652 return uno::Reference< ucb::XContent >();
655 OUString aURL = m_xIdentifier->getContentIdentifier();
657 OSL_ENSURE( !aURL.isEmpty(),
658 "Content::createNewContent - empty identifier!" );
660 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
661 aURL += "/";
663 if ( bCreateFolder )
664 aURL += "New_Folder";
665 else
666 aURL += "New_Stream";
668 uno::Reference< ucb::XContentIdentifier > xId
669 = new ::ucbhelper::ContentIdentifier( aURL );
671 return create( m_xContext, m_pProvider, xId, Info );
673 else
675 OSL_FAIL( "createNewContent called on non-contentcreator object!" );
676 return uno::Reference< ucb::XContent >();
681 // virtual
682 OUString Content::getParentURL()
684 osl::Guard< osl::Mutex > aGuard( m_aMutex );
685 Uri aUri( m_xIdentifier->getContentIdentifier() );
686 return aUri.getParentUri();
690 uno::Reference< ucb::XContentIdentifier >
691 Content::makeNewIdentifier( const OUString& rTitle )
693 osl::Guard< osl::Mutex > aGuard( m_aMutex );
695 // Assemble new content identifier...
696 Uri aUri( m_xIdentifier->getContentIdentifier() );
697 OUString aNewURL = aUri.getParentUri() + ::ucb_impl::urihelper::encodeSegment( rTitle );
699 return
700 uno::Reference< ucb::XContentIdentifier >(
701 new ::ucbhelper::ContentIdentifier( aNewURL ) );
705 void Content::queryChildren( ContentRefList& rChildren )
707 osl::Guard< osl::Mutex > aGuard( m_aMutex );
709 // Only folders (root, documents, folders) have children.
710 if ( !m_aProps.getIsFolder() )
711 return;
713 // Obtain a list with a snapshot of all currently instantiated contents
714 // from provider and extract the contents which are direct children
715 // of this content.
717 ::ucbhelper::ContentRefList aAllContents;
718 m_xProvider->queryExistingContents( aAllContents );
720 OUString aURL = m_xIdentifier->getContentIdentifier();
721 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
723 if ( nURLPos != ( aURL.getLength() - 1 ) )
725 // No trailing slash found. Append.
726 aURL += "/";
729 sal_Int32 nLen = aURL.getLength();
731 for ( const auto& rContent : aAllContents )
733 ::ucbhelper::ContentImplHelperRef xChild = rContent;
734 OUString aChildURL
735 = xChild->getIdentifier()->getContentIdentifier();
737 // Is aURL a prefix of aChildURL?
738 if ( ( aChildURL.getLength() > nLen ) &&
739 ( aChildURL.startsWith( aURL ) ) )
741 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
743 if ( ( nPos == -1 ) ||
744 ( nPos == ( aChildURL.getLength() - 1 ) ) )
746 // No further slashes / only a final slash. It's a child!
747 rChildren.emplace_back(
748 static_cast< Content * >( xChild.get() ) );
755 bool Content::exchangeIdentity(
756 const uno::Reference< ucb::XContentIdentifier >& xNewId )
758 if ( !xNewId.is() )
759 return false;
761 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
763 uno::Reference< ucb::XContent > xThis = this;
765 // Already persistent?
766 if ( m_eState != PERSISTENT )
768 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
769 return false;
772 // Only folders and streams can be renamed -> exchange identity.
773 ContentType eType = m_aProps.getType();
774 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
776 OSL_FAIL( "Content::exchangeIdentity - "
777 "Not supported by root or document!" );
778 return false;
781 // Exchange own identity.
783 // Fail, if a content with given id already exists.
784 if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
786 OUString aOldURL = m_xIdentifier->getContentIdentifier();
788 aGuard.clear();
789 if ( exchange( xNewId ) )
791 if ( eType == FOLDER )
793 // Process instantiated children...
795 ContentRefList aChildren;
796 queryChildren( aChildren );
798 for ( const auto& rChild : aChildren )
800 ContentRef xChild = rChild;
802 // Create new content identifier for the child...
803 uno::Reference< ucb::XContentIdentifier > xOldChildId
804 = xChild->getIdentifier();
805 OUString aOldChildURL
806 = xOldChildId->getContentIdentifier();
807 OUString aNewChildURL
808 = aOldChildURL.replaceAt(
810 aOldURL.getLength(),
811 xNewId->getContentIdentifier() );
812 uno::Reference< ucb::XContentIdentifier > xNewChildId
813 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
815 if ( !xChild->exchangeIdentity( xNewChildId ) )
816 return false;
819 return true;
823 OSL_FAIL( "Content::exchangeIdentity - "
824 "Panic! Cannot exchange identity!" );
825 return false;
829 // static
830 uno::Reference< sdbc::XRow > Content::getPropertyValues(
831 const uno::Reference< uno::XComponentContext >& rxContext,
832 const uno::Sequence< beans::Property >& rProperties,
833 ContentProvider* pProvider,
834 const OUString& rContentId )
836 ContentProperties aData;
837 if ( loadData( pProvider, Uri(rContentId), aData ) )
839 return getPropertyValues(
840 rxContext, rProperties, aData, pProvider, rContentId );
842 else
844 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
845 = new ::ucbhelper::PropertyValueSet( rxContext );
847 for ( const beans::Property& rProp : rProperties )
848 xRow->appendVoid( rProp );
850 return xRow;
855 // static
856 uno::Reference< sdbc::XRow > Content::getPropertyValues(
857 const uno::Reference< uno::XComponentContext >& rxContext,
858 const uno::Sequence< beans::Property >& rProperties,
859 const ContentProperties& rData,
860 ContentProvider* pProvider,
861 const OUString& rContentId )
863 // Note: Empty sequence means "get values of all supported properties".
865 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
866 = new ::ucbhelper::PropertyValueSet( rxContext );
868 if ( rProperties.hasElements() )
870 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
871 bool bTriedToGetAdditionalPropSet = false;
873 for ( const beans::Property& rProp : rProperties )
875 // Process Core properties.
877 if ( rProp.Name == "ContentType" )
879 xRow->appendString ( rProp, rData.getContentType() );
881 else if ( rProp.Name == "Title" )
883 xRow->appendString ( rProp, rData.getTitle() );
885 else if ( rProp.Name == "IsDocument" )
887 xRow->appendBoolean( rProp, rData.getIsDocument() );
889 else if ( rProp.Name == "IsFolder" )
891 xRow->appendBoolean( rProp, rData.getIsFolder() );
893 else if ( rProp.Name == "CreatableContentsInfo" )
895 xRow->appendObject(
896 rProp, uno::Any( rData.getCreatableContentsInfo() ) );
898 else if ( rProp.Name == "DateModified" )
900 // DateModified is only supported by streams.
901 ContentType eType = rData.getType();
902 if ( eType == STREAM )
904 xRow->appendObject(
905 rProp,
906 uno::Any(
907 pProvider->queryStreamDateModified( rContentId ) ) );
909 else
910 xRow->appendVoid( rProp );
912 else if ( rProp.Name == "Storage" )
914 // Storage is only supported by folders.
915 ContentType eType = rData.getType();
916 if ( eType == FOLDER )
917 xRow->appendObject(
918 rProp,
919 uno::Any(
920 pProvider->queryStorageClone( rContentId ) ) );
921 else
922 xRow->appendVoid( rProp );
924 else if ( rProp.Name == "DocumentModel" )
926 // DocumentModel is only supported by documents.
927 ContentType eType = rData.getType();
928 if ( eType == DOCUMENT )
929 xRow->appendObject(
930 rProp,
931 uno::Any(
932 pProvider->queryDocumentModel( rContentId ) ) );
933 else
934 xRow->appendVoid( rProp );
936 else
938 // Not a Core Property! Maybe it's an Additional Core Property?!
940 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
942 xAdditionalPropSet =
943 pProvider->getAdditionalPropertySet( rContentId,
944 false );
945 bTriedToGetAdditionalPropSet = true;
948 if ( xAdditionalPropSet.is() )
950 if ( !xRow->appendPropertySetValue(
951 xAdditionalPropSet,
952 rProp ) )
954 // Append empty entry.
955 xRow->appendVoid( rProp );
958 else
960 // Append empty entry.
961 xRow->appendVoid( rProp );
966 else
968 // Append all Core Properties.
969 xRow->appendString (
970 beans::Property( "ContentType",
972 cppu::UnoType<OUString>::get(),
973 beans::PropertyAttribute::BOUND
974 | beans::PropertyAttribute::READONLY ),
975 rData.getContentType() );
977 ContentType eType = rData.getType();
979 xRow->appendString (
980 beans::Property( "Title",
982 cppu::UnoType<OUString>::get(),
983 // Title is read-only for root and documents.
984 beans::PropertyAttribute::BOUND |
985 ( ( eType == ROOT ) || ( eType == DOCUMENT )
986 ? beans::PropertyAttribute::READONLY
987 : 0 ) ),
988 rData.getTitle() );
989 xRow->appendBoolean(
990 beans::Property( "IsDocument",
992 cppu::UnoType<bool>::get(),
993 beans::PropertyAttribute::BOUND
994 | beans::PropertyAttribute::READONLY ),
995 rData.getIsDocument() );
996 xRow->appendBoolean(
997 beans::Property( "IsFolder",
999 cppu::UnoType<bool>::get(),
1000 beans::PropertyAttribute::BOUND
1001 | beans::PropertyAttribute::READONLY ),
1002 rData.getIsFolder() );
1003 xRow->appendObject(
1004 beans::Property(
1005 "CreatableContentsInfo",
1007 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
1008 beans::PropertyAttribute::BOUND
1009 | beans::PropertyAttribute::READONLY ),
1010 uno::Any( rData.getCreatableContentsInfo() ) );
1012 // DateModified is only supported by streams.
1013 if ( eType == STREAM )
1015 xRow->appendObject(
1016 beans::Property( "DateModified",
1018 cppu::UnoType<css::util::DateTime>::get(),
1019 beans::PropertyAttribute::BOUND
1020 | beans::PropertyAttribute::READONLY ),
1021 uno::Any( pProvider->queryStreamDateModified( rContentId ) ) );
1024 // Storage is only supported by folders.
1025 if ( eType == FOLDER )
1026 xRow->appendObject(
1027 beans::Property( "Storage",
1029 cppu::UnoType<embed::XStorage>::get(),
1030 beans::PropertyAttribute::BOUND
1031 | beans::PropertyAttribute::READONLY ),
1032 uno::Any( pProvider->queryStorageClone( rContentId ) ) );
1034 // DocumentModel is only supported by documents.
1035 if ( eType == DOCUMENT )
1036 xRow->appendObject(
1037 beans::Property( "DocumentModel",
1039 cppu::UnoType<frame::XModel>::get(),
1040 beans::PropertyAttribute::BOUND
1041 | beans::PropertyAttribute::READONLY ),
1042 uno::Any(
1043 pProvider->queryDocumentModel( rContentId ) ) );
1045 // Append all Additional Core Properties.
1047 uno::Reference< beans::XPropertySet > xSet =
1048 pProvider->getAdditionalPropertySet( rContentId, false );
1049 xRow->appendPropertySet( xSet );
1052 return xRow;
1056 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1057 const uno::Sequence< beans::Property >& rProperties )
1059 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1060 return getPropertyValues( m_xContext,
1061 rProperties,
1062 m_aProps,
1063 m_pProvider,
1064 m_xIdentifier->getContentIdentifier() );
1068 uno::Sequence< uno::Any > Content::setPropertyValues(
1069 const uno::Sequence< beans::PropertyValue >& rValues,
1070 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1072 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1074 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1075 auto aRetRange = asNonConstRange(aRet);
1076 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1077 sal_Int32 nChanged = 0;
1079 beans::PropertyChangeEvent aEvent;
1080 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1081 aEvent.Further = false;
1082 // aEvent.PropertyName =
1083 aEvent.PropertyHandle = -1;
1084 // aEvent.OldValue =
1085 // aEvent.NewValue =
1087 const beans::PropertyValue* pValues = rValues.getConstArray();
1088 sal_Int32 nCount = rValues.getLength();
1090 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1091 bool bTriedToGetAdditionalPropSet = false;
1093 bool bExchange = false;
1094 OUString aOldTitle;
1095 sal_Int32 nTitlePos = -1;
1097 for ( sal_Int32 n = 0; n < nCount; ++n )
1099 const beans::PropertyValue& rValue = pValues[ n ];
1101 if ( rValue.Name == "ContentType" )
1103 // Read-only property!
1104 aRetRange[ n ] <<= lang::IllegalAccessException(
1105 "Property is read-only!",
1106 static_cast< cppu::OWeakObject * >( this ) );
1108 else if ( rValue.Name == "IsDocument" )
1110 // Read-only property!
1111 aRetRange[ n ] <<= lang::IllegalAccessException(
1112 "Property is read-only!",
1113 static_cast< cppu::OWeakObject * >( this ) );
1115 else if ( rValue.Name == "IsFolder" )
1117 // Read-only property!
1118 aRetRange[ n ] <<= lang::IllegalAccessException(
1119 "Property is read-only!",
1120 static_cast< cppu::OWeakObject * >( this ) );
1122 else if ( rValue.Name == "CreatableContentsInfo" )
1124 // Read-only property!
1125 aRetRange[ n ] <<= lang::IllegalAccessException(
1126 "Property is read-only!",
1127 static_cast< cppu::OWeakObject * >( this ) );
1129 else if ( rValue.Name == "Title" )
1131 // Title is read-only for root and documents.
1132 ContentType eType = m_aProps.getType();
1133 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1135 aRetRange[ n ] <<= lang::IllegalAccessException(
1136 "Property is read-only!",
1137 static_cast< cppu::OWeakObject * >( this ) );
1139 else
1141 OUString aNewValue;
1142 if ( rValue.Value >>= aNewValue )
1144 // No empty titles!
1145 if ( !aNewValue.isEmpty() )
1147 if ( aNewValue != m_aProps.getTitle() )
1149 // modified title -> modified URL -> exchange !
1150 if ( m_eState == PERSISTENT )
1151 bExchange = true;
1153 aOldTitle = m_aProps.getTitle();
1154 m_aProps.setTitle( aNewValue );
1156 // property change event will be sent later...
1158 // remember position within sequence of values
1159 // (for error handling).
1160 nTitlePos = n;
1163 else
1165 aRetRange[ n ] <<= lang::IllegalArgumentException(
1166 "Empty Title not allowed!",
1167 static_cast< cppu::OWeakObject * >( this ),
1168 -1 );
1171 else
1173 aRetRange[ n ] <<= beans::IllegalTypeException(
1174 "Title Property value has wrong type!",
1175 static_cast< cppu::OWeakObject * >( this ) );
1179 else if ( rValue.Name == "Storage" )
1181 ContentType eType = m_aProps.getType();
1182 if ( eType == FOLDER )
1184 aRetRange[ n ] <<= lang::IllegalAccessException(
1185 "Property is read-only!",
1186 static_cast< cppu::OWeakObject * >( this ) );
1188 else
1190 // Storage is only supported by folders.
1191 aRetRange[ n ] <<= beans::UnknownPropertyException(
1192 "Storage property only supported by folders",
1193 static_cast< cppu::OWeakObject * >( this ) );
1196 else if ( rValue.Name == "DocumentModel" )
1198 ContentType eType = m_aProps.getType();
1199 if ( eType == DOCUMENT )
1201 aRetRange[ n ] <<= lang::IllegalAccessException(
1202 "Property is read-only!",
1203 static_cast< cppu::OWeakObject * >( this ) );
1205 else
1207 // Storage is only supported by folders.
1208 aRetRange[ n ] <<= beans::UnknownPropertyException(
1209 "DocumentModel property only supported by documents",
1210 static_cast< cppu::OWeakObject * >( this ) );
1213 else
1215 // Not a Core Property! Maybe it's an Additional Core Property?!
1217 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1219 xAdditionalPropSet = getAdditionalPropertySet( false );
1220 bTriedToGetAdditionalPropSet = true;
1223 if ( xAdditionalPropSet.is() )
1227 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1228 rValue.Name );
1229 if ( aOldValue != rValue.Value )
1231 xAdditionalPropSet->setPropertyValue(
1232 rValue.Name, rValue.Value );
1234 aEvent.PropertyName = rValue.Name;
1235 aEvent.OldValue = aOldValue;
1236 aEvent.NewValue = rValue.Value;
1238 aChanges.getArray()[ nChanged ] = aEvent;
1239 nChanged++;
1242 catch ( beans::UnknownPropertyException const & e )
1244 aRetRange[ n ] <<= e;
1246 catch ( lang::WrappedTargetException const & e )
1248 aRetRange[ n ] <<= e;
1250 catch ( beans::PropertyVetoException const & e )
1252 aRetRange[ n ] <<= e;
1254 catch ( lang::IllegalArgumentException const & e )
1256 aRetRange[ n ] <<= e;
1259 else
1261 aRetRange[ n ] <<= uno::Exception(
1262 "No property set for storing the value!",
1263 static_cast< cppu::OWeakObject * >( this ) );
1268 if ( bExchange )
1270 uno::Reference< ucb::XContentIdentifier > xOldId
1271 = m_xIdentifier;
1272 uno::Reference< ucb::XContentIdentifier > xNewId
1273 = makeNewIdentifier( m_aProps.getTitle() );
1275 aGuard.clear();
1276 if ( exchangeIdentity( xNewId ) )
1278 // Adapt persistent data.
1279 renameData( xOldId, xNewId );
1281 // Adapt Additional Core Properties.
1282 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1283 xNewId->getContentIdentifier() );
1285 else
1287 // Roll-back.
1288 m_aProps.setTitle( aOldTitle );
1289 aOldTitle.clear();
1291 // Set error .
1292 aRetRange[ nTitlePos ] <<= uno::Exception(
1293 "Exchange failed!",
1294 static_cast< cppu::OWeakObject * >( this ) );
1298 if ( !aOldTitle.isEmpty() )
1300 aEvent.PropertyName = "Title";
1301 aEvent.OldValue <<= aOldTitle;
1302 aEvent.NewValue <<= m_aProps.getTitle();
1304 aChanges.getArray()[ nChanged ] = aEvent;
1305 nChanged++;
1308 if ( nChanged > 0 )
1310 // Save changes, if content was already made persistent.
1311 if ( !bExchange && ( m_eState == PERSISTENT ) )
1313 if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1315 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1317 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1318 }));
1319 ucbhelper::cancelCommandExecution(
1320 ucb::IOErrorCode_CANT_WRITE,
1321 aArgs,
1322 xEnv,
1323 "Cannot store persistent data!",
1324 this );
1325 // Unreachable
1329 aChanges.realloc( nChanged );
1331 aGuard.clear();
1332 notifyPropertiesChange( aChanges );
1335 return aRet;
1339 uno::Any Content::open(
1340 const ucb::OpenCommandArgument2& rArg,
1341 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1343 if ( rArg.Mode == ucb::OpenMode::ALL ||
1344 rArg.Mode == ucb::OpenMode::FOLDERS ||
1345 rArg.Mode == ucb::OpenMode::DOCUMENTS )
1348 // open command for a folder content
1351 uno::Reference< ucb::XDynamicResultSet > xSet
1352 = new DynamicResultSet( m_xContext, this, rArg );
1353 return uno::Any( xSet );
1355 else
1358 // open command for a document content
1361 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1362 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1364 // Currently(?) unsupported.
1365 ucbhelper::cancelCommandExecution(
1366 uno::Any( ucb::UnsupportedOpenModeException(
1367 OUString(),
1368 static_cast< cppu::OWeakObject * >( this ),
1369 sal_Int16( rArg.Mode ) ) ),
1370 xEnv );
1371 // Unreachable
1374 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1376 uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1377 rArg.Sink, uno::UNO_QUERY );
1378 if ( xDataStreamer.is() )
1380 // May throw CommandFailedException, DocumentPasswordRequest!
1381 uno::Reference< io::XStream > xStream = getStream( xEnv );
1382 if ( !xStream.is() )
1384 // No interaction if we are not persistent!
1385 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1387 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1388 }));
1389 ucbhelper::cancelCommandExecution(
1390 ucb::IOErrorCode_CANT_READ,
1391 aArgs,
1392 m_eState == PERSISTENT
1393 ? xEnv
1394 : uno::Reference< ucb::XCommandEnvironment >(),
1395 "Got no data stream!",
1396 this );
1397 // Unreachable
1400 // Done.
1401 xDataStreamer->setStream( xStream );
1403 else
1405 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1406 if ( xOut.is() )
1408 // PUSH: write data into xOut
1410 // May throw CommandFailedException, DocumentPasswordRequest!
1411 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1412 if ( !xIn.is() )
1414 // No interaction if we are not persistent!
1415 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1417 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1418 }));
1419 ucbhelper::cancelCommandExecution(
1420 ucb::IOErrorCode_CANT_READ,
1421 aArgs,
1422 m_eState == PERSISTENT
1423 ? xEnv
1424 : uno::Reference< ucb::XCommandEnvironment >(),
1425 "Got no data stream!",
1426 this );
1427 // Unreachable
1432 uno::Sequence< sal_Int8 > aBuffer;
1434 while (true)
1436 sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1437 if (!nRead)
1438 break;
1439 aBuffer.realloc( nRead );
1440 xOut->writeBytes( aBuffer );
1443 xOut->closeOutput();
1445 catch ( io::NotConnectedException const & )
1447 // closeOutput, readSomeBytes, writeBytes
1449 catch ( io::BufferSizeExceededException const & )
1451 // closeOutput, readSomeBytes, writeBytes
1453 catch ( io::IOException const & )
1455 // closeOutput, readSomeBytes, writeBytes
1458 else
1460 uno::Reference< io::XActiveDataSink > xDataSink(
1461 rArg.Sink, uno::UNO_QUERY );
1462 if ( xDataSink.is() )
1464 // PULL: wait for client read
1466 // May throw CommandFailedException, DocumentPasswordRequest!
1467 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1468 if ( !xIn.is() )
1470 // No interaction if we are not persistent!
1471 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1473 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1474 }));
1475 ucbhelper::cancelCommandExecution(
1476 ucb::IOErrorCode_CANT_READ,
1477 aArgs,
1478 m_eState == PERSISTENT
1479 ? xEnv
1480 : uno::Reference<
1481 ucb::XCommandEnvironment >(),
1482 "Got no data stream!",
1483 this );
1484 // Unreachable
1487 // Done.
1488 xDataSink->setInputStream( xIn );
1490 else
1492 ucbhelper::cancelCommandExecution(
1493 uno::Any(
1494 ucb::UnsupportedDataSinkException(
1495 OUString(),
1496 static_cast< cppu::OWeakObject * >( this ),
1497 rArg.Sink ) ),
1498 xEnv );
1499 // Unreachable
1505 return uno::Any();
1509 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1510 sal_Int32 nNameClashResolve,
1511 const uno::Reference<
1512 ucb::XCommandEnvironment > & xEnv )
1514 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1516 ContentType eType = m_aProps.getType();
1518 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1519 "insert command only supported by streams and folders!" );
1521 Uri aUri( m_xIdentifier->getContentIdentifier() );
1523 #if OSL_DEBUG_LEVEL > 0
1524 if ( eType == STREAM )
1526 Uri aParentUri( aUri.getParentUri() );
1527 OSL_ENSURE( !aParentUri.isDocument(),
1528 "insert command not supported by streams that are direct "
1529 "children of document root!" );
1531 #endif
1533 // Check, if all required properties were set.
1534 if ( eType == FOLDER )
1536 // Required: Title
1538 if ( m_aProps.getTitle().isEmpty() )
1539 m_aProps.setTitle( aUri.getDecodedName() );
1541 else // stream
1543 // Required: data
1545 if ( !xData.is() )
1547 ucbhelper::cancelCommandExecution(
1548 uno::Any( ucb::MissingInputStreamException(
1549 OUString(),
1550 static_cast< cppu::OWeakObject * >( this ) ) ),
1551 xEnv );
1552 // Unreachable
1555 // Required: Title
1557 if ( m_aProps.getTitle().isEmpty() )
1558 m_aProps.setTitle( aUri.getDecodedName() );
1561 Uri aNewUri( aUri.getParentUri() + m_aProps.getTitle() );
1563 // Handle possible name clash...
1564 switch ( nNameClashResolve )
1566 // fail.
1567 case ucb::NameClash::ERROR:
1568 if ( hasData( aNewUri ) )
1570 ucbhelper::cancelCommandExecution(
1571 uno::Any( ucb::NameClashException(
1572 OUString(),
1573 static_cast< cppu::OWeakObject * >( this ),
1574 task::InteractionClassification_ERROR,
1575 m_aProps.getTitle() ) ),
1576 xEnv );
1577 // Unreachable
1579 break;
1581 // replace (possibly) existing object.
1582 case ucb::NameClash::OVERWRITE:
1583 break;
1585 // "invent" a new valid title.
1586 case ucb::NameClash::RENAME:
1587 if ( hasData( aNewUri ) )
1589 sal_Int32 nTry = 0;
1593 aNewUri.setUri( aNewUri.getUri() + "_" + OUString::number(++nTry) );
1595 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1597 if ( nTry == 1000 )
1599 ucbhelper::cancelCommandExecution(
1600 uno::Any(
1601 ucb::UnsupportedNameClashException(
1602 "Unable to resolve name clash!",
1603 static_cast< cppu::OWeakObject * >( this ),
1604 nNameClashResolve ) ),
1605 xEnv );
1606 // Unreachable
1608 else
1610 m_aProps.setTitle( m_aProps.getTitle() + "_" + OUString::number( ++nTry ) );
1613 break;
1615 case ucb::NameClash::KEEP: // deprecated
1616 case ucb::NameClash::ASK:
1617 default:
1618 if ( hasData( aNewUri ) )
1620 ucbhelper::cancelCommandExecution(
1621 uno::Any(
1622 ucb::UnsupportedNameClashException(
1623 OUString(),
1624 static_cast< cppu::OWeakObject * >( this ),
1625 nNameClashResolve ) ),
1626 xEnv );
1627 // Unreachable
1629 break;
1632 // Identifier changed?
1633 bool bNewId = ( aUri != aNewUri );
1635 if ( bNewId )
1637 m_xIdentifier
1638 = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1641 if ( !storeData( xData, xEnv ) )
1643 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1645 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1646 }));
1647 ucbhelper::cancelCommandExecution(
1648 ucb::IOErrorCode_CANT_WRITE,
1649 aArgs,
1650 xEnv,
1651 "Cannot store persistent data!",
1652 this );
1653 // Unreachable
1656 m_eState = PERSISTENT;
1658 if ( bNewId )
1660 //loadData( m_pProvider, m_aUri, m_aProps );
1662 aGuard.clear();
1663 inserted();
1668 void Content::destroy( bool bDeletePhysical,
1669 const uno::Reference<
1670 ucb::XCommandEnvironment > & xEnv )
1672 // @@@ take care about bDeletePhysical -> trashcan support
1674 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1676 ContentType eType = m_aProps.getType();
1678 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1679 "delete command only supported by streams and folders!" );
1681 uno::Reference< ucb::XContent > xThis = this;
1683 // Persistent?
1684 if ( m_eState != PERSISTENT )
1686 ucbhelper::cancelCommandExecution(
1687 uno::Any( ucb::UnsupportedCommandException(
1688 "Not persistent!",
1689 static_cast< cppu::OWeakObject * >( this ) ) ),
1690 xEnv );
1691 // Unreachable
1694 m_eState = DEAD;
1696 aGuard.clear();
1697 deleted();
1699 if ( eType == FOLDER )
1701 // Process instantiated children...
1703 ContentRefList aChildren;
1704 queryChildren( aChildren );
1706 for ( auto& rChild : aChildren )
1708 rChild->destroy( bDeletePhysical, xEnv );
1714 void Content::notifyDocumentClosed()
1716 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1718 m_eState = DEAD;
1720 // @@@ anything else to reset or such?
1722 // callback follows!
1723 aGuard.clear();
1725 // Propagate destruction to content event listeners
1726 // Remove this from provider's content list.
1727 deleted();
1731 uno::Reference< ucb::XContent >
1732 Content::queryChildContent( std::u16string_view rRelativeChildUri )
1734 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1736 const OUString aMyId = getIdentifier()->getContentIdentifier();
1737 OUStringBuffer aBuf( aMyId );
1738 if ( !aMyId.endsWith("/") )
1739 aBuf.append( "/" );
1740 if ( !o3tl::starts_with(rRelativeChildUri, u"/") )
1741 aBuf.append( rRelativeChildUri );
1742 else
1743 aBuf.append( rRelativeChildUri.substr(1) );
1745 uno::Reference< ucb::XContentIdentifier > xChildId
1746 = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1748 uno::Reference< ucb::XContent > xChild;
1751 xChild = m_pProvider->queryContent( xChildId );
1753 catch ( ucb::IllegalIdentifierException const & )
1755 // handled below.
1758 OSL_ENSURE( xChild.is(),
1759 "Content::queryChildContent - unable to create child content!" );
1760 return xChild;
1764 void Content::notifyChildRemoved( std::u16string_view rRelativeChildUri )
1766 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1768 // Ugly! Need to create child content object, just to fill event properly.
1769 uno::Reference< ucb::XContent > xChild
1770 = queryChildContent( rRelativeChildUri );
1772 if ( !xChild.is() )
1773 return;
1775 // callback follows!
1776 aGuard.clear();
1778 // Notify "REMOVED" event.
1779 ucb::ContentEvent aEvt(
1780 static_cast< cppu::OWeakObject * >( this ),
1781 ucb::ContentAction::REMOVED,
1782 xChild,
1783 getIdentifier() );
1784 notifyContentEvent( aEvt );
1788 void Content::notifyChildInserted( std::u16string_view rRelativeChildUri )
1790 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1792 // Ugly! Need to create child content object, just to fill event properly.
1793 uno::Reference< ucb::XContent > xChild
1794 = queryChildContent( rRelativeChildUri );
1796 if ( !xChild.is() )
1797 return;
1799 // callback follows!
1800 aGuard.clear();
1802 // Notify "INSERTED" event.
1803 ucb::ContentEvent aEvt(
1804 static_cast< cppu::OWeakObject * >( this ),
1805 ucb::ContentAction::INSERTED,
1806 xChild,
1807 getIdentifier() );
1808 notifyContentEvent( aEvt );
1812 void Content::transfer(
1813 const ucb::TransferInfo& rInfo,
1814 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1816 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1818 // Persistent?
1819 if ( m_eState != PERSISTENT )
1821 ucbhelper::cancelCommandExecution(
1822 uno::Any( ucb::UnsupportedCommandException(
1823 "Not persistent!",
1824 static_cast< cppu::OWeakObject * >( this ) ) ),
1825 xEnv );
1826 // Unreachable
1829 // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1831 if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1833 // Invalid length (to short).
1834 ucbhelper::cancelCommandExecution(
1835 uno::Any( ucb::InteractiveBadTransferURLException(
1836 OUString(),
1837 static_cast< cppu::OWeakObject * >( this ) ) ),
1838 xEnv );
1839 // Unreachable
1842 OUString aScheme
1843 = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1844 .toAsciiLowerCase();
1845 if ( aScheme != TDOC_URL_SCHEME ":/" )
1847 // Invalid scheme.
1848 ucbhelper::cancelCommandExecution(
1849 uno::Any( ucb::InteractiveBadTransferURLException(
1850 OUString(),
1851 static_cast< cppu::OWeakObject * >( this ) ) ),
1852 xEnv );
1853 // Unreachable
1856 // Does source URI describe a tdoc folder or stream?
1857 Uri aSourceUri( rInfo.SourceURL );
1858 if ( !aSourceUri.isValid() )
1860 ucbhelper::cancelCommandExecution(
1861 uno::Any( lang::IllegalArgumentException(
1862 "Invalid source URI! Syntax!",
1863 static_cast< cppu::OWeakObject * >( this ),
1864 -1 ) ),
1865 xEnv );
1866 // Unreachable
1869 if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1871 ucbhelper::cancelCommandExecution(
1872 uno::Any( lang::IllegalArgumentException(
1873 "Invalid source URI! Must describe a folder or stream!",
1874 static_cast< cppu::OWeakObject * >( this ),
1875 -1 ) ),
1876 xEnv );
1877 // Unreachable
1880 // Is source not a parent of me / not me?
1881 OUString aId = m_xIdentifier->getContentIdentifier();
1882 sal_Int32 nPos = aId.lastIndexOf( '/' );
1883 if ( nPos != ( aId.getLength() - 1 ) )
1885 // No trailing slash found. Append.
1886 aId += "/";
1889 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1891 if ( aId.startsWith( rInfo.SourceURL ) )
1893 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1895 {"Uri", uno::Any(rInfo.SourceURL)}
1896 }));
1897 ucbhelper::cancelCommandExecution(
1898 ucb::IOErrorCode_RECURSIVE,
1899 aArgs,
1900 xEnv,
1901 "Target is equal to or is a child of source!",
1902 this );
1903 // Unreachable
1907 if ( m_aProps.getType() == DOCUMENT )
1909 bool bOK = false;
1911 uno::Reference< embed::XStorage > xStorage
1912 = m_pProvider->queryStorage(
1913 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1914 if ( xStorage.is() )
1918 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1920 ucbhelper::cancelCommandExecution(
1921 uno::Any( lang::IllegalArgumentException(
1922 "Invalid source URI! "
1923 "Streams cannot be created as "
1924 "children of document root!",
1925 static_cast< cppu::OWeakObject * >(
1926 this ),
1927 -1 ) ),
1928 xEnv );
1929 // Unreachable
1931 bOK = true;
1933 catch ( container::NoSuchElementException const & )
1935 // handled below.
1937 catch ( lang::IllegalArgumentException const & )
1939 // handled below.
1941 catch ( embed::InvalidStorageException const & )
1943 // handled below.
1947 if ( !bOK )
1949 ucbhelper::cancelCommandExecution(
1950 uno::Any( lang::IllegalArgumentException(
1951 "Invalid source URI! Unable to determine source type!",
1952 static_cast< cppu::OWeakObject * >( this ),
1953 -1 ) ),
1954 xEnv );
1955 // Unreachable
1960 // Copy data.
1963 OUString aNewName( !rInfo.NewTitle.isEmpty()
1964 ? rInfo.NewTitle
1965 : aSourceUri.getDecodedName() );
1967 if ( !copyData( aSourceUri, aNewName ) )
1969 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1971 {"Uri", uno::Any(rInfo.SourceURL)}
1972 }));
1973 ucbhelper::cancelCommandExecution(
1974 ucb::IOErrorCode_CANT_WRITE,
1975 aArgs,
1976 xEnv,
1977 "Cannot copy data!",
1978 this );
1979 // Unreachable
1983 // Copy own and all children's Additional Core Properties.
1986 OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1987 if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1988 aTargetUri += "/";
1990 if ( !rInfo.NewTitle.isEmpty() )
1991 aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1992 else
1993 aTargetUri += aSourceUri.getName();
1995 if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1997 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1999 {"Uri", uno::Any(rInfo.SourceURL)}
2000 }));
2001 ucbhelper::cancelCommandExecution(
2002 ucb::IOErrorCode_CANT_WRITE,
2003 aArgs,
2004 xEnv,
2005 "Cannot copy additional properties!",
2006 this );
2007 // Unreachable
2011 // Propagate new content.
2014 rtl::Reference< Content > xTarget;
2017 uno::Reference< ucb::XContentIdentifier > xTargetId
2018 = new ::ucbhelper::ContentIdentifier( aTargetUri );
2020 // Note: The static cast is okay here, because its sure that
2021 // m_xProvider is always the WebDAVContentProvider.
2022 xTarget = static_cast< Content * >(
2023 m_pProvider->queryContent( xTargetId ).get() );
2026 catch ( ucb::IllegalIdentifierException const & )
2028 // queryContent
2031 if ( !xTarget.is() )
2033 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2035 {"Uri", uno::Any(aTargetUri)}
2036 }));
2037 ucbhelper::cancelCommandExecution(
2038 ucb::IOErrorCode_CANT_READ,
2039 aArgs,
2040 xEnv,
2041 "Cannot instantiate target object!",
2042 this );
2043 // Unreachable
2046 // Announce transferred content in its new folder.
2047 xTarget->inserted();
2050 // Remove source, if requested
2053 if ( !rInfo.MoveData )
2054 return;
2056 rtl::Reference< Content > xSource;
2059 uno::Reference< ucb::XContentIdentifier >
2060 xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2062 // Note: The static cast is okay here, because its sure
2063 // that m_xProvider is always the ContentProvider.
2064 xSource = static_cast< Content * >(
2065 m_xProvider->queryContent( xSourceId ).get() );
2067 catch ( ucb::IllegalIdentifierException const & )
2069 // queryContent
2072 if ( !xSource.is() )
2074 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2076 {"Uri", uno::Any(rInfo.SourceURL)}
2077 }));
2078 ucbhelper::cancelCommandExecution(
2079 ucb::IOErrorCode_CANT_READ,
2080 aArgs,
2081 xEnv,
2082 "Cannot instantiate target object!",
2083 this );
2084 // Unreachable
2087 // Propagate destruction (recursively).
2088 xSource->destroy( true, xEnv );
2090 // Remove all persistent data of source and its children.
2091 if ( !xSource->removeData() )
2093 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2095 {"Uri", uno::Any(rInfo.SourceURL)}
2096 }));
2097 ucbhelper::cancelCommandExecution(
2098 ucb::IOErrorCode_CANT_WRITE,
2099 aArgs,
2100 xEnv,
2101 "Cannot remove persistent data of source object!",
2102 this );
2103 // Unreachable
2106 // Remove own and all children's Additional Core Properties.
2107 if ( xSource->removeAdditionalPropertySet() )
2108 return;
2110 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2112 {"Uri", uno::Any(rInfo.SourceURL)}
2113 }));
2114 ucbhelper::cancelCommandExecution(
2115 ucb::IOErrorCode_CANT_WRITE,
2116 aArgs,
2117 xEnv,
2118 "Cannot remove additional properties of source object!",
2119 this );
2120 // Unreachable
2124 //static
2125 bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2127 if ( rUri.isRoot() )
2129 return true; // root has no storage
2131 else if ( rUri.isDocument() )
2133 uno::Reference< embed::XStorage > xStorage
2134 = pProvider->queryStorage( rUri.getUri(), READ );
2135 return xStorage.is();
2137 else
2139 // folder or stream
2141 // Ask parent storage. In case that rUri describes a stream,
2142 // ContentProvider::queryStorage( rUri ) would return null.
2144 uno::Reference< embed::XStorage > xStorage
2145 = pProvider->queryStorage( rUri.getParentUri(), READ );
2147 if ( !xStorage.is() )
2148 return false;
2150 return xStorage->hasByName( rUri.getDecodedName() );
2155 //static
2156 bool Content::loadData( ContentProvider const * pProvider,
2157 const Uri & rUri,
2158 ContentProperties& rProps )
2160 if ( rUri.isRoot() ) // root has no storage, but can always be created
2162 rProps
2163 = ContentProperties(
2164 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2166 else if ( rUri.isDocument() ) // document must have storage
2168 uno::Reference< embed::XStorage > xStorage
2169 = pProvider->queryStorage( rUri.getUri(), READ );
2171 if ( !xStorage.is() )
2172 return false;
2174 rProps
2175 = ContentProperties(
2176 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2178 else // stream or folder; stream has no storage; folder has storage
2180 uno::Reference< embed::XStorage > xStorage
2181 = pProvider->queryStorage( rUri.getParentUri(), READ );
2183 if ( !xStorage.is() )
2184 return false;
2186 // Check whether exists at all, is stream or folder
2189 // return: true -> folder
2190 // return: false -> stream
2191 // NoSuchElementException -> neither folder nor stream
2192 bool bIsFolder
2193 = xStorage->isStorageElement( rUri.getDecodedName() );
2195 rProps
2196 = ContentProperties(
2197 bIsFolder ? FOLDER : STREAM,
2198 pProvider->queryStorageTitle( rUri.getUri() ) );
2200 catch ( container::NoSuchElementException const & )
2202 // there is no element with such name
2203 //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2204 return false;
2206 catch ( lang::IllegalArgumentException const & )
2208 // an illegal argument is provided
2209 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2210 return false;
2212 catch ( embed::InvalidStorageException const & )
2214 // this storage is in invalid state for any reason
2215 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2216 return false;
2219 return true;
2223 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2224 const uno::Reference<
2225 ucb::XCommandEnvironment >& xEnv )
2227 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2229 ContentType eType = m_aProps.getType();
2230 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2232 OSL_FAIL( "storeData not supported by root and documents!" );
2233 return false;
2236 Uri aUri( m_xIdentifier->getContentIdentifier() );
2238 if ( eType == FOLDER )
2240 uno::Reference< embed::XStorage > xStorage
2241 = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2243 if ( !xStorage.is() )
2244 return false;
2246 uno::Reference< beans::XPropertySet > xPropSet(
2247 xStorage, uno::UNO_QUERY );
2248 OSL_ENSURE( xPropSet.is(),
2249 "Content::storeData - Got no XPropertySet interface!" );
2250 if ( !xPropSet.is() )
2251 return false;
2255 // According to MBA, if no mediatype is set, folder and all
2256 // its contents will be lost on save of the document!!!
2257 xPropSet->setPropertyValue(
2258 "MediaType",
2259 uno::Any(
2260 OUString( // @@@ better mediatype
2261 "application/binary" ) ) );
2263 catch ( beans::UnknownPropertyException const & )
2265 OSL_FAIL( "Property MediaType not supported!" );
2266 return false;
2268 catch ( beans::PropertyVetoException const & )
2270 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2271 return false;
2273 catch ( lang::IllegalArgumentException const & )
2275 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2276 return false;
2278 catch ( lang::WrappedTargetException const & )
2280 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2281 return false;
2284 if ( !commitStorage( xStorage ) )
2285 return false;
2287 else if ( eType == STREAM )
2289 // stream
2291 // Important: Parent storage and output stream must be kept alive until
2292 // changes have been committed!
2293 uno::Reference< embed::XStorage > xStorage
2294 = m_pProvider->queryStorage(
2295 aUri.getParentUri(), READ_WRITE_CREATE );
2296 uno::Reference< io::XOutputStream > xOut;
2298 if ( !xStorage.is() )
2299 return false;
2301 if ( xData.is() )
2303 // May throw CommandFailedException, DocumentPasswordRequest!
2304 xOut = getTruncatedOutputStream( xEnv );
2306 OSL_ENSURE( xOut.is(), "No target data stream!" );
2310 uno::Sequence< sal_Int8 > aBuffer;
2311 while (true)
2313 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2314 if (!nRead)
2315 break;
2316 aBuffer.realloc( nRead );
2317 xOut->writeBytes( aBuffer );
2320 closeOutputStream( xOut );
2322 catch ( io::NotConnectedException const & )
2324 // readSomeBytes, writeBytes
2325 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2326 closeOutputStream( xOut );
2327 return false;
2329 catch ( io::BufferSizeExceededException const & )
2331 // readSomeBytes, writeBytes
2332 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2333 closeOutputStream( xOut );
2334 return false;
2336 catch ( io::IOException const & )
2338 // readSomeBytes, writeBytes
2339 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2340 closeOutputStream( xOut );
2341 return false;
2343 catch ( ... )
2345 closeOutputStream( xOut );
2346 throw;
2350 // Commit changes.
2351 if ( !commitStorage( xStorage ) )
2352 return false;
2354 else
2356 OSL_FAIL( "Unknown content type!" );
2357 return false;
2359 return true;
2363 void Content::renameData(
2364 const uno::Reference< ucb::XContentIdentifier >& xOldId,
2365 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2367 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2369 ContentType eType = m_aProps.getType();
2370 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2372 OSL_FAIL( "renameData not supported by root and documents!" );
2373 return;
2376 Uri aOldUri( xOldId->getContentIdentifier() );
2377 uno::Reference< embed::XStorage > xStorage
2378 = m_pProvider->queryStorage(
2379 aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2381 if ( !xStorage.is() )
2382 return;
2386 Uri aNewUri( xNewId->getContentIdentifier() );
2387 xStorage->renameElement(
2388 aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2390 catch ( embed::InvalidStorageException const & )
2392 // this storage is in invalid state for any reason
2393 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2394 return;
2396 catch ( lang::IllegalArgumentException const & )
2398 // an illegal argument is provided
2399 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2400 return;
2402 catch ( container::NoSuchElementException const & )
2404 // there is no element with old name in this storage
2405 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2406 return;
2408 catch ( container::ElementExistException const & )
2410 // an element with new name already exists in this storage
2411 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2412 return;
2414 catch ( io::IOException const & )
2416 // in case of io errors during renaming
2417 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2418 return;
2420 catch ( embed::StorageWrappedTargetException const & )
2422 // wraps other exceptions
2423 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2424 return;
2427 commitStorage( xStorage );
2431 bool Content::removeData()
2433 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2435 ContentType eType = m_aProps.getType();
2436 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2438 OSL_FAIL( "removeData not supported by root and documents!" );
2439 return false;
2442 Uri aUri( m_xIdentifier->getContentIdentifier() );
2443 uno::Reference< embed::XStorage > xStorage
2444 = m_pProvider->queryStorage(
2445 aUri.getParentUri(), READ_WRITE_NOCREATE );
2447 if ( !xStorage.is() )
2448 return false;
2452 xStorage->removeElement( aUri.getDecodedName() );
2454 catch ( embed::InvalidStorageException const & )
2456 // this storage is in invalid state for any reason
2457 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2458 return false;
2460 catch ( lang::IllegalArgumentException const & )
2462 // an illegal argument is provided
2463 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2464 return false;
2466 catch ( container::NoSuchElementException const & )
2468 // there is no element with this name in this storage
2469 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2470 return false;
2472 catch ( io::IOException const & )
2474 // in case of io errors during renaming
2475 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2476 return false;
2478 catch ( embed::StorageWrappedTargetException const & )
2480 // wraps other exceptions
2481 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2482 return false;
2485 return commitStorage( xStorage );
2489 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2491 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2493 ContentType eType = m_aProps.getType();
2494 if ( ( eType == ROOT ) || ( eType == STREAM ) )
2496 OSL_FAIL( "copyData not supported by root and streams!" );
2497 return false;
2500 Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2501 uno::Reference< embed::XStorage > xDestStorage
2502 = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2504 if ( !xDestStorage.is() )
2505 return false;
2507 uno::Reference< embed::XStorage > xSourceStorage
2508 = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2510 if ( !xSourceStorage.is() )
2511 return false;
2515 xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2516 xDestStorage,
2517 rNewName );
2519 catch ( embed::InvalidStorageException const & )
2521 // this storage is in invalid state for any reason
2522 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2523 return false;
2525 catch ( lang::IllegalArgumentException const & )
2527 // an illegal argument is provided
2528 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2529 return false;
2531 catch ( container::NoSuchElementException const & )
2533 // there is no element with this name in this storage
2534 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2535 return false;
2537 catch ( container::ElementExistException const & )
2539 // there is no element with this name in this storage
2540 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2541 return false;
2543 catch ( io::IOException const & )
2545 // in case of io errors during renaming
2546 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2547 return false;
2549 catch ( embed::StorageWrappedTargetException const & )
2551 // wraps other exceptions
2552 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2553 return false;
2556 return commitStorage( xDestStorage );
2560 // static
2561 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2563 // Commit changes
2564 uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2566 OSL_ENSURE( xTO.is(),
2567 "Required interface css.embed.XTransactedObject missing!" );
2570 xTO->commit();
2572 catch ( io::IOException const & )
2574 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2575 return false;
2577 catch ( lang::WrappedTargetException const & )
2579 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2580 return false;
2583 return true;
2587 // static
2588 bool Content::closeOutputStream(
2589 const uno::Reference< io::XOutputStream > & xOut )
2591 if ( xOut.is() )
2595 xOut->closeOutput();
2596 return true;
2598 catch ( io::NotConnectedException const & )
2600 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2602 catch ( io::BufferSizeExceededException const & )
2604 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2606 catch ( io::IOException const & )
2608 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2611 return false;
2614 /// @throws ucb::CommandFailedException
2615 /// @throws task::DocumentPasswordRequest
2616 static OUString obtainPassword(
2617 const OUString & rName,
2618 task::PasswordRequestMode eMode,
2619 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2621 rtl::Reference< DocumentPasswordRequest > xRequest
2622 = new DocumentPasswordRequest( eMode, rName );
2624 if ( xEnv.is() )
2626 uno::Reference< task::XInteractionHandler > xIH
2627 = xEnv->getInteractionHandler();
2628 if ( xIH.is() )
2630 xIH->handle( xRequest );
2632 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2633 = xRequest->getSelection();
2635 if ( xSelection.is() )
2637 // Handler handled the request.
2638 uno::Reference< task::XInteractionAbort > xAbort(
2639 xSelection.get(), uno::UNO_QUERY );
2640 if ( xAbort.is() )
2642 throw ucb::CommandFailedException(
2643 "Abort requested by Interaction Handler.",
2644 uno::Reference< uno::XInterface >(),
2645 xRequest->getRequest() );
2648 uno::Reference< task::XInteractionPassword > xPassword(
2649 xSelection.get(), uno::UNO_QUERY );
2650 if ( xPassword.is() )
2652 return xPassword->getPassword();
2655 // Unknown selection. Should never happen.
2656 throw ucb::CommandFailedException(
2657 "Interaction Handler selected unknown continuation!",
2658 uno::Reference< uno::XInterface >(),
2659 xRequest->getRequest() );
2664 // No IH or IH did not handle exception.
2665 task::DocumentPasswordRequest aRequest;
2666 xRequest->getRequest() >>= aRequest;
2667 throw aRequest;
2671 uno::Reference< io::XInputStream > Content::getInputStream(
2672 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2674 OUString aUri;
2675 OUString aPassword;
2676 bool bPasswordRequested = false;
2679 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2681 OSL_ENSURE( m_aProps.getType() == STREAM,
2682 "Content::getInputStream - content is no stream!" );
2684 aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2687 for ( ;; )
2691 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2692 return m_pProvider->queryInputStream( aUri, aPassword );
2694 catch ( packages::WrongPasswordException const & )
2696 // Obtain (new) password.
2697 aPassword
2698 = obtainPassword( aUri, /* @@@ find better title */
2699 bPasswordRequested
2700 ? task::PasswordRequestMode_PASSWORD_REENTER
2701 : task::PasswordRequestMode_PASSWORD_ENTER,
2702 xEnv );
2703 bPasswordRequested = true;
2708 /// @throws ucb::CommandFailedException
2709 /// @throws task::DocumentPasswordRequest
2710 /// @throws uno::RuntimeException
2711 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2712 const OUString & rUri,
2713 ContentProvider const * pProvider,
2714 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2716 OUString aPassword;
2717 bool bPasswordRequested = false;
2718 for ( ;; )
2722 return pProvider->queryOutputStream(
2723 rUri, aPassword, true /* truncate */ );
2725 catch ( packages::WrongPasswordException const & )
2727 // Obtain (new) password.
2728 aPassword
2729 = obtainPassword( rUri, /* @@@ find better title */
2730 bPasswordRequested
2731 ? task::PasswordRequestMode_PASSWORD_REENTER
2732 : task::PasswordRequestMode_PASSWORD_ENTER,
2733 xEnv );
2734 bPasswordRequested = true;
2740 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2741 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2743 OSL_ENSURE( m_aProps.getType() == STREAM,
2744 "Content::getTruncatedOutputStream - content is no stream!" );
2746 return lcl_getTruncatedOutputStream(
2747 Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2748 m_pProvider,
2749 xEnv );
2753 uno::Reference< io::XStream > Content::getStream(
2754 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2756 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2758 OSL_ENSURE( m_aProps.getType() == STREAM,
2759 "Content::getStream - content is no stream!" );
2761 OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2762 OUString aPassword;
2763 bool bPasswordRequested = false;
2764 for ( ;; )
2768 return m_pProvider->queryStream(
2769 aUri, aPassword, false /* no truncate */ );
2771 catch ( packages::WrongPasswordException const & )
2773 // Obtain (new) password.
2774 aPassword
2775 = obtainPassword( aUri, /* @@@ find better title */
2776 bPasswordRequested
2777 ? task::PasswordRequestMode_PASSWORD_REENTER
2778 : task::PasswordRequestMode_PASSWORD_ENTER,
2779 xEnv );
2780 bPasswordRequested = true;
2786 // ContentProperties Implementation.
2789 uno::Sequence< ucb::ContentInfo >
2790 ContentProperties::getCreatableContentsInfo() const
2792 if ( isContentCreator() )
2794 uno::Sequence< beans::Property > aProps( 1 );
2795 aProps.getArray()[ 0 ] = beans::Property(
2796 "Title",
2798 cppu::UnoType<OUString>::get(),
2799 beans::PropertyAttribute::BOUND );
2801 if ( getType() == DOCUMENT )
2803 // streams cannot be created as direct children of document root
2804 uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2806 // Folder.
2807 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2808 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2809 aSeq.getArray()[ 0 ].Properties = aProps;
2811 return aSeq;
2813 else
2815 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2817 // Folder.
2818 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2819 aSeq.getArray()[ 0 ].Attributes
2820 = ucb::ContentInfoAttribute::KIND_FOLDER;
2821 aSeq.getArray()[ 0 ].Properties = aProps;
2823 // Stream.
2824 aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2825 aSeq.getArray()[ 1 ].Attributes
2826 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2827 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2828 aSeq.getArray()[ 1 ].Properties = aProps;
2830 return aSeq;
2833 else
2835 OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2836 "object!" );
2838 return uno::Sequence< ucb::ContentInfo >( 0 );
2843 bool ContentProperties::isContentCreator() const
2845 return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2848 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */