Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_content.cxx
blobdcc2653beade7640bf3d51c53f41ebc63dfff143
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 u"com.sun.star.comp.ucb.TransientDocumentsContent"_ustr;
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 u"Wrong argument type!"_ustr,
343 getXWeak(),
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 u"Wrong argument type!"_ustr,
363 getXWeak(),
364 -1 ) ),
365 Environment );
366 // Unreachable
369 if ( !aProperties.hasElements() )
371 ucbhelper::cancelCommandExecution(
372 uno::Any( lang::IllegalArgumentException(
373 u"No properties!"_ustr,
374 getXWeak(),
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 u"Wrong argument type!"_ustr,
410 getXWeak(),
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 u"insert command only supported by "
430 "folders and streams!"_ustr,
431 getXWeak() ) ),
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 u"insert command not supported by "
445 "streams that are direct children "
446 "of document root!"_ustr,
447 getXWeak() ) ),
448 Environment );
449 // Unreachable
453 ucb::InsertCommandArgument aArg;
454 if ( !( aCommand.Argument >>= aArg ) )
456 ucbhelper::cancelCommandExecution(
457 uno::Any( lang::IllegalArgumentException(
458 u"Wrong argument type!"_ustr,
459 getXWeak(),
460 -1 ) ),
461 Environment );
462 // Unreachable
465 sal_Int32 nNameClash = aArg.ReplaceExisting
466 ? ucb::NameClash::OVERWRITE
467 : ucb::NameClash::ERROR;
468 insert( aArg.Data, nNameClash, Environment );
470 else if ( aCommand.Name == "delete" )
473 // delete ( Supported by folders and streams only )
477 osl::MutexGuard aGuard( m_aMutex );
479 ContentType eType = m_aProps.getType();
480 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
482 ucbhelper::cancelCommandExecution(
483 uno::Any( ucb::UnsupportedCommandException(
484 u"delete command only supported by "
485 "folders and streams!"_ustr,
486 getXWeak() ) ),
487 Environment );
488 // Unreachable
492 bool bDeletePhysical = false;
493 aCommand.Argument >>= bDeletePhysical;
494 destroy( bDeletePhysical, Environment );
496 // Remove own and all children's persistent data.
497 if ( !removeData() )
499 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
501 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
502 }));
503 ucbhelper::cancelCommandExecution(
504 ucb::IOErrorCode_CANT_WRITE,
505 aArgs,
506 Environment,
507 u"Cannot remove persistent data!"_ustr,
508 this );
509 // Unreachable
512 // Remove own and all children's Additional Core Properties.
513 removeAdditionalPropertySet();
515 else if ( aCommand.Name == "transfer" )
518 // transfer ( Supported by document and folders only )
522 osl::MutexGuard aGuard( m_aMutex );
524 ContentType eType = m_aProps.getType();
525 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
527 ucbhelper::cancelCommandExecution(
528 uno::Any( ucb::UnsupportedCommandException(
529 u"transfer command only supported "
530 "by folders and documents!"_ustr,
531 getXWeak() ) ),
532 Environment );
533 // Unreachable
537 ucb::TransferInfo aInfo;
538 if ( !( aCommand.Argument >>= aInfo ) )
540 OSL_FAIL( "Wrong argument type!" );
541 ucbhelper::cancelCommandExecution(
542 uno::Any( lang::IllegalArgumentException(
543 u"Wrong argument type!"_ustr,
544 getXWeak(),
545 -1 ) ),
546 Environment );
547 // Unreachable
550 transfer( aInfo, Environment );
552 else if ( aCommand.Name == "createNewContent" )
555 // createNewContent ( Supported by document and folders only )
559 osl::MutexGuard aGuard( m_aMutex );
561 ContentType eType = m_aProps.getType();
562 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
564 ucbhelper::cancelCommandExecution(
565 uno::Any( ucb::UnsupportedCommandException(
566 u"createNewContent command only "
567 "supported by folders and "
568 "documents!"_ustr,
569 getXWeak() ) ),
570 Environment );
571 // Unreachable
575 ucb::ContentInfo aInfo;
576 if ( !( aCommand.Argument >>= aInfo ) )
578 OSL_FAIL( "Wrong argument type!" );
579 ucbhelper::cancelCommandExecution(
580 uno::Any( lang::IllegalArgumentException(
581 u"Wrong argument type!"_ustr,
582 getXWeak(),
583 -1 ) ),
584 Environment );
585 // Unreachable
588 aRet <<= createNewContent( aInfo );
590 else
593 // Unsupported command
596 ucbhelper::cancelCommandExecution(
597 uno::Any( ucb::UnsupportedCommandException(
598 OUString(),
599 getXWeak() ) ),
600 Environment );
601 // Unreachable
604 return aRet;
608 // virtual
609 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
614 // XContentCreator methods.
617 // virtual
618 uno::Sequence< ucb::ContentInfo > SAL_CALL
619 Content::queryCreatableContentsInfo()
621 return m_aProps.getCreatableContentsInfo();
625 // virtual
626 uno::Reference< ucb::XContent > SAL_CALL
627 Content::createNewContent( const ucb::ContentInfo& Info )
629 if ( m_aProps.isContentCreator() )
631 osl::Guard< osl::Mutex > aGuard( m_aMutex );
633 if ( Info.Type.isEmpty() )
634 return uno::Reference< ucb::XContent >();
636 bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
638 // streams cannot be created as direct children of document root
639 if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
641 OSL_FAIL( "Content::createNewContent - streams cannot be "
642 "created as direct children of document root!" );
643 return uno::Reference< ucb::XContent >();
645 if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
647 OSL_FAIL( "Content::createNewContent - unsupported type!" );
648 return uno::Reference< ucb::XContent >();
651 OUString aURL = m_xIdentifier->getContentIdentifier();
653 OSL_ENSURE( !aURL.isEmpty(),
654 "Content::createNewContent - empty identifier!" );
656 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
657 aURL += "/";
659 if ( bCreateFolder )
660 aURL += "New_Folder";
661 else
662 aURL += "New_Stream";
664 uno::Reference< ucb::XContentIdentifier > xId
665 = new ::ucbhelper::ContentIdentifier( aURL );
667 return create( m_xContext, m_pProvider, xId, Info );
669 else
671 OSL_FAIL( "createNewContent called on non-contentcreator object!" );
672 return uno::Reference< ucb::XContent >();
677 // virtual
678 OUString Content::getParentURL()
680 osl::Guard< osl::Mutex > aGuard( m_aMutex );
681 Uri aUri( m_xIdentifier->getContentIdentifier() );
682 return aUri.getParentUri();
686 uno::Reference< ucb::XContentIdentifier >
687 Content::makeNewIdentifier( const OUString& rTitle )
689 osl::Guard< osl::Mutex > aGuard( m_aMutex );
691 // Assemble new content identifier...
692 Uri aUri( m_xIdentifier->getContentIdentifier() );
693 OUString aNewURL = aUri.getParentUri() + ::ucb_impl::urihelper::encodeSegment( rTitle );
695 return
696 uno::Reference< ucb::XContentIdentifier >(
697 new ::ucbhelper::ContentIdentifier( aNewURL ) );
701 void Content::queryChildren( ContentRefList& rChildren )
703 osl::Guard< osl::Mutex > aGuard( m_aMutex );
705 // Only folders (root, documents, folders) have children.
706 if ( !m_aProps.getIsFolder() )
707 return;
709 // Obtain a list with a snapshot of all currently instantiated contents
710 // from provider and extract the contents which are direct children
711 // of this content.
713 ::ucbhelper::ContentRefList aAllContents;
714 m_xProvider->queryExistingContents( aAllContents );
716 OUString aURL = m_xIdentifier->getContentIdentifier();
717 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
719 if ( nURLPos != ( aURL.getLength() - 1 ) )
721 // No trailing slash found. Append.
722 aURL += "/";
725 sal_Int32 nLen = aURL.getLength();
727 for ( const auto& rContent : aAllContents )
729 ::ucbhelper::ContentImplHelperRef xChild = rContent;
730 OUString aChildURL
731 = xChild->getIdentifier()->getContentIdentifier();
733 // Is aURL a prefix of aChildURL?
734 if ( ( aChildURL.getLength() > nLen ) &&
735 ( aChildURL.startsWith( aURL ) ) )
737 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
739 if ( ( nPos == -1 ) ||
740 ( nPos == ( aChildURL.getLength() - 1 ) ) )
742 // No further slashes / only a final slash. It's a child!
743 rChildren.emplace_back(
744 static_cast< Content * >( xChild.get() ) );
751 bool Content::exchangeIdentity(
752 const uno::Reference< ucb::XContentIdentifier >& xNewId )
754 if ( !xNewId.is() )
755 return false;
757 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
759 uno::Reference< ucb::XContent > xThis = this;
761 // Already persistent?
762 if ( m_eState != PERSISTENT )
764 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
765 return false;
768 // Only folders and streams can be renamed -> exchange identity.
769 ContentType eType = m_aProps.getType();
770 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
772 OSL_FAIL( "Content::exchangeIdentity - "
773 "Not supported by root or document!" );
774 return false;
777 // Exchange own identity.
779 // Fail, if a content with given id already exists.
780 if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
782 OUString aOldURL = m_xIdentifier->getContentIdentifier();
784 aGuard.clear();
785 if ( exchange( xNewId ) )
787 if ( eType == FOLDER )
789 // Process instantiated children...
791 ContentRefList aChildren;
792 queryChildren( aChildren );
794 for ( const auto& rChild : aChildren )
796 ContentRef xChild = rChild;
798 // Create new content identifier for the child...
799 uno::Reference< ucb::XContentIdentifier > xOldChildId
800 = xChild->getIdentifier();
801 OUString aOldChildURL
802 = xOldChildId->getContentIdentifier();
803 OUString aNewChildURL
804 = aOldChildURL.replaceAt(
806 aOldURL.getLength(),
807 xNewId->getContentIdentifier() );
808 uno::Reference< ucb::XContentIdentifier > xNewChildId
809 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
811 if ( !xChild->exchangeIdentity( xNewChildId ) )
812 return false;
815 return true;
819 OSL_FAIL( "Content::exchangeIdentity - "
820 "Panic! Cannot exchange identity!" );
821 return false;
825 // static
826 uno::Reference< sdbc::XRow > Content::getPropertyValues(
827 const uno::Reference< uno::XComponentContext >& rxContext,
828 const uno::Sequence< beans::Property >& rProperties,
829 ContentProvider* pProvider,
830 const OUString& rContentId )
832 ContentProperties aData;
833 if ( loadData( pProvider, Uri(rContentId), aData ) )
835 return getPropertyValues(
836 rxContext, rProperties, aData, pProvider, rContentId );
838 else
840 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
841 = new ::ucbhelper::PropertyValueSet( rxContext );
843 for ( const beans::Property& rProp : rProperties )
844 xRow->appendVoid( rProp );
846 return xRow;
851 // static
852 uno::Reference< sdbc::XRow > Content::getPropertyValues(
853 const uno::Reference< uno::XComponentContext >& rxContext,
854 const uno::Sequence< beans::Property >& rProperties,
855 const ContentProperties& rData,
856 ContentProvider* pProvider,
857 const OUString& rContentId )
859 // Note: Empty sequence means "get values of all supported properties".
861 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
862 = new ::ucbhelper::PropertyValueSet( rxContext );
864 if ( rProperties.hasElements() )
866 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
867 bool bTriedToGetAdditionalPropSet = false;
869 for ( const beans::Property& rProp : rProperties )
871 // Process Core properties.
873 if ( rProp.Name == "ContentType" )
875 xRow->appendString ( rProp, rData.getContentType() );
877 else if ( rProp.Name == "Title" )
879 xRow->appendString ( rProp, rData.getTitle() );
881 else if ( rProp.Name == "IsDocument" )
883 xRow->appendBoolean( rProp, rData.getIsDocument() );
885 else if ( rProp.Name == "IsFolder" )
887 xRow->appendBoolean( rProp, rData.getIsFolder() );
889 else if ( rProp.Name == "CreatableContentsInfo" )
891 xRow->appendObject(
892 rProp, uno::Any( rData.getCreatableContentsInfo() ) );
894 else if ( rProp.Name == "DateModified" )
896 // DateModified is only supported by streams.
897 ContentType eType = rData.getType();
898 if ( eType == STREAM )
900 xRow->appendObject(
901 rProp,
902 uno::Any(
903 pProvider->queryStreamDateModified( rContentId ) ) );
905 else
906 xRow->appendVoid( rProp );
908 else if ( rProp.Name == "Storage" )
910 // Storage is only supported by folders.
911 ContentType eType = rData.getType();
912 if ( eType == FOLDER )
913 xRow->appendObject(
914 rProp,
915 uno::Any(
916 pProvider->queryStorageClone( rContentId ) ) );
917 else
918 xRow->appendVoid( rProp );
920 else if ( rProp.Name == "DocumentModel" )
922 // DocumentModel is only supported by documents.
923 ContentType eType = rData.getType();
924 if ( eType == DOCUMENT )
925 xRow->appendObject(
926 rProp,
927 uno::Any(
928 pProvider->queryDocumentModel( rContentId ) ) );
929 else
930 xRow->appendVoid( rProp );
932 else
934 // Not a Core Property! Maybe it's an Additional Core Property?!
936 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
938 xAdditionalPropSet =
939 pProvider->getAdditionalPropertySet( rContentId,
940 false );
941 bTriedToGetAdditionalPropSet = true;
944 if ( xAdditionalPropSet.is() )
946 if ( !xRow->appendPropertySetValue(
947 xAdditionalPropSet,
948 rProp ) )
950 // Append empty entry.
951 xRow->appendVoid( rProp );
954 else
956 // Append empty entry.
957 xRow->appendVoid( rProp );
962 else
964 // Append all Core Properties.
965 xRow->appendString (
966 beans::Property( u"ContentType"_ustr,
968 cppu::UnoType<OUString>::get(),
969 beans::PropertyAttribute::BOUND
970 | beans::PropertyAttribute::READONLY ),
971 rData.getContentType() );
973 ContentType eType = rData.getType();
975 xRow->appendString (
976 beans::Property( u"Title"_ustr,
978 cppu::UnoType<OUString>::get(),
979 // Title is read-only for root and documents.
980 beans::PropertyAttribute::BOUND |
981 ( ( eType == ROOT ) || ( eType == DOCUMENT )
982 ? beans::PropertyAttribute::READONLY
983 : 0 ) ),
984 rData.getTitle() );
985 xRow->appendBoolean(
986 beans::Property( u"IsDocument"_ustr,
988 cppu::UnoType<bool>::get(),
989 beans::PropertyAttribute::BOUND
990 | beans::PropertyAttribute::READONLY ),
991 rData.getIsDocument() );
992 xRow->appendBoolean(
993 beans::Property( u"IsFolder"_ustr,
995 cppu::UnoType<bool>::get(),
996 beans::PropertyAttribute::BOUND
997 | beans::PropertyAttribute::READONLY ),
998 rData.getIsFolder() );
999 xRow->appendObject(
1000 beans::Property(
1001 u"CreatableContentsInfo"_ustr,
1003 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
1004 beans::PropertyAttribute::BOUND
1005 | beans::PropertyAttribute::READONLY ),
1006 uno::Any( rData.getCreatableContentsInfo() ) );
1008 // DateModified is only supported by streams.
1009 if ( eType == STREAM )
1011 xRow->appendObject(
1012 beans::Property( u"DateModified"_ustr,
1014 cppu::UnoType<css::util::DateTime>::get(),
1015 beans::PropertyAttribute::BOUND
1016 | beans::PropertyAttribute::READONLY ),
1017 uno::Any( pProvider->queryStreamDateModified( rContentId ) ) );
1020 // Storage is only supported by folders.
1021 if ( eType == FOLDER )
1022 xRow->appendObject(
1023 beans::Property( u"Storage"_ustr,
1025 cppu::UnoType<embed::XStorage>::get(),
1026 beans::PropertyAttribute::BOUND
1027 | beans::PropertyAttribute::READONLY ),
1028 uno::Any( pProvider->queryStorageClone( rContentId ) ) );
1030 // DocumentModel is only supported by documents.
1031 if ( eType == DOCUMENT )
1032 xRow->appendObject(
1033 beans::Property( u"DocumentModel"_ustr,
1035 cppu::UnoType<frame::XModel>::get(),
1036 beans::PropertyAttribute::BOUND
1037 | beans::PropertyAttribute::READONLY ),
1038 uno::Any(
1039 pProvider->queryDocumentModel( rContentId ) ) );
1041 // Append all Additional Core Properties.
1043 uno::Reference< beans::XPropertySet > xSet =
1044 pProvider->getAdditionalPropertySet( rContentId, false );
1045 xRow->appendPropertySet( xSet );
1048 return xRow;
1052 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1053 const uno::Sequence< beans::Property >& rProperties )
1055 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1056 return getPropertyValues( m_xContext,
1057 rProperties,
1058 m_aProps,
1059 m_pProvider,
1060 m_xIdentifier->getContentIdentifier() );
1064 uno::Sequence< uno::Any > Content::setPropertyValues(
1065 const uno::Sequence< beans::PropertyValue >& rValues,
1066 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1068 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1070 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1071 auto aRetRange = asNonConstRange(aRet);
1072 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1073 sal_Int32 nChanged = 0;
1075 beans::PropertyChangeEvent aEvent;
1076 aEvent.Source = getXWeak();
1077 aEvent.Further = false;
1078 aEvent.PropertyHandle = -1;
1080 const beans::PropertyValue* pValues = rValues.getConstArray();
1081 sal_Int32 nCount = rValues.getLength();
1083 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1084 bool bTriedToGetAdditionalPropSet = false;
1086 bool bExchange = false;
1087 OUString aOldTitle;
1088 sal_Int32 nTitlePos = -1;
1090 for ( sal_Int32 n = 0; n < nCount; ++n )
1092 const beans::PropertyValue& rValue = pValues[ n ];
1094 if ( rValue.Name == "ContentType" )
1096 // Read-only property!
1097 aRetRange[ n ] <<= lang::IllegalAccessException(
1098 u"Property is read-only!"_ustr,
1099 getXWeak() );
1101 else if ( rValue.Name == "IsDocument" )
1103 // Read-only property!
1104 aRetRange[ n ] <<= lang::IllegalAccessException(
1105 u"Property is read-only!"_ustr,
1106 getXWeak() );
1108 else if ( rValue.Name == "IsFolder" )
1110 // Read-only property!
1111 aRetRange[ n ] <<= lang::IllegalAccessException(
1112 u"Property is read-only!"_ustr,
1113 getXWeak() );
1115 else if ( rValue.Name == "CreatableContentsInfo" )
1117 // Read-only property!
1118 aRetRange[ n ] <<= lang::IllegalAccessException(
1119 u"Property is read-only!"_ustr,
1120 getXWeak() );
1122 else if ( rValue.Name == "Title" )
1124 // Title is read-only for root and documents.
1125 ContentType eType = m_aProps.getType();
1126 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1128 aRetRange[ n ] <<= lang::IllegalAccessException(
1129 u"Property is read-only!"_ustr,
1130 getXWeak() );
1132 else
1134 OUString aNewValue;
1135 if ( rValue.Value >>= aNewValue )
1137 // No empty titles!
1138 if ( !aNewValue.isEmpty() )
1140 if ( aNewValue != m_aProps.getTitle() )
1142 // modified title -> modified URL -> exchange !
1143 if ( m_eState == PERSISTENT )
1144 bExchange = true;
1146 aOldTitle = m_aProps.getTitle();
1147 m_aProps.setTitle( aNewValue );
1149 // property change event will be sent later...
1151 // remember position within sequence of values
1152 // (for error handling).
1153 nTitlePos = n;
1156 else
1158 aRetRange[ n ] <<= lang::IllegalArgumentException(
1159 u"Empty Title not allowed!"_ustr,
1160 getXWeak(),
1161 -1 );
1164 else
1166 aRetRange[ n ] <<= beans::IllegalTypeException(
1167 u"Title Property value has wrong type!"_ustr,
1168 getXWeak() );
1172 else if ( rValue.Name == "Storage" )
1174 ContentType eType = m_aProps.getType();
1175 if ( eType == FOLDER )
1177 aRetRange[ n ] <<= lang::IllegalAccessException(
1178 u"Property is read-only!"_ustr,
1179 getXWeak() );
1181 else
1183 // Storage is only supported by folders.
1184 aRetRange[ n ] <<= beans::UnknownPropertyException(
1185 u"Storage property only supported by folders"_ustr,
1186 getXWeak() );
1189 else if ( rValue.Name == "DocumentModel" )
1191 ContentType eType = m_aProps.getType();
1192 if ( eType == DOCUMENT )
1194 aRetRange[ n ] <<= lang::IllegalAccessException(
1195 u"Property is read-only!"_ustr,
1196 getXWeak() );
1198 else
1200 // Storage is only supported by folders.
1201 aRetRange[ n ] <<= beans::UnknownPropertyException(
1202 u"DocumentModel property only supported by documents"_ustr,
1203 getXWeak() );
1206 else
1208 // Not a Core Property! Maybe it's an Additional Core Property?!
1210 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1212 xAdditionalPropSet = getAdditionalPropertySet( false );
1213 bTriedToGetAdditionalPropSet = true;
1216 if ( xAdditionalPropSet.is() )
1220 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1221 rValue.Name );
1222 if ( aOldValue != rValue.Value )
1224 xAdditionalPropSet->setPropertyValue(
1225 rValue.Name, rValue.Value );
1227 aEvent.PropertyName = rValue.Name;
1228 aEvent.OldValue = std::move(aOldValue);
1229 aEvent.NewValue = rValue.Value;
1231 aChanges.getArray()[ nChanged ] = aEvent;
1232 nChanged++;
1235 catch ( beans::UnknownPropertyException const & e )
1237 aRetRange[ n ] <<= e;
1239 catch ( lang::WrappedTargetException const & e )
1241 aRetRange[ n ] <<= e;
1243 catch ( beans::PropertyVetoException const & e )
1245 aRetRange[ n ] <<= e;
1247 catch ( lang::IllegalArgumentException const & e )
1249 aRetRange[ n ] <<= e;
1252 else
1254 aRetRange[ n ] <<= uno::Exception(
1255 u"No property set for storing the value!"_ustr,
1256 getXWeak() );
1261 if ( bExchange )
1263 uno::Reference< ucb::XContentIdentifier > xOldId
1264 = m_xIdentifier;
1265 uno::Reference< ucb::XContentIdentifier > xNewId
1266 = makeNewIdentifier( m_aProps.getTitle() );
1268 aGuard.clear();
1269 if ( exchangeIdentity( xNewId ) )
1271 // Adapt persistent data.
1272 renameData( xOldId, xNewId );
1274 // Adapt Additional Core Properties.
1275 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1276 xNewId->getContentIdentifier() );
1278 else
1280 // Roll-back.
1281 m_aProps.setTitle( aOldTitle );
1282 aOldTitle.clear();
1284 // Set error .
1285 aRetRange[ nTitlePos ] <<= uno::Exception(
1286 u"Exchange failed!"_ustr,
1287 getXWeak() );
1291 if ( !aOldTitle.isEmpty() )
1293 aEvent.PropertyName = "Title";
1294 aEvent.OldValue <<= aOldTitle;
1295 aEvent.NewValue <<= m_aProps.getTitle();
1297 aChanges.getArray()[ nChanged ] = std::move(aEvent);
1298 nChanged++;
1301 if ( nChanged > 0 )
1303 // Save changes, if content was already made persistent.
1304 if ( !bExchange && ( m_eState == PERSISTENT ) )
1306 if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1308 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1310 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1311 }));
1312 ucbhelper::cancelCommandExecution(
1313 ucb::IOErrorCode_CANT_WRITE,
1314 aArgs,
1315 xEnv,
1316 u"Cannot store persistent data!"_ustr,
1317 this );
1318 // Unreachable
1322 aChanges.realloc( nChanged );
1324 aGuard.clear();
1325 notifyPropertiesChange( aChanges );
1328 return aRet;
1332 uno::Any Content::open(
1333 const ucb::OpenCommandArgument2& rArg,
1334 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1336 if ( rArg.Mode == ucb::OpenMode::ALL ||
1337 rArg.Mode == ucb::OpenMode::FOLDERS ||
1338 rArg.Mode == ucb::OpenMode::DOCUMENTS )
1341 // open command for a folder content
1344 uno::Reference< ucb::XDynamicResultSet > xSet
1345 = new DynamicResultSet( m_xContext, this, rArg );
1346 return uno::Any( xSet );
1348 else
1351 // open command for a document content
1354 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1355 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1357 // Currently(?) unsupported.
1358 ucbhelper::cancelCommandExecution(
1359 uno::Any( ucb::UnsupportedOpenModeException(
1360 OUString(),
1361 getXWeak(),
1362 sal_Int16( rArg.Mode ) ) ),
1363 xEnv );
1364 // Unreachable
1367 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1369 uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1370 rArg.Sink, uno::UNO_QUERY );
1371 if ( xDataStreamer.is() )
1373 // May throw CommandFailedException, DocumentPasswordRequest!
1374 uno::Reference< io::XStream > xStream = getStream( xEnv );
1375 if ( !xStream.is() )
1377 // No interaction if we are not persistent!
1378 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1380 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1381 }));
1382 ucbhelper::cancelCommandExecution(
1383 ucb::IOErrorCode_CANT_READ,
1384 aArgs,
1385 m_eState == PERSISTENT
1386 ? xEnv
1387 : uno::Reference< ucb::XCommandEnvironment >(),
1388 u"Got no data stream!"_ustr,
1389 this );
1390 // Unreachable
1393 // Done.
1394 xDataStreamer->setStream( xStream );
1396 else
1398 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1399 if ( xOut.is() )
1401 // PUSH: write data into xOut
1403 // May throw CommandFailedException, DocumentPasswordRequest!
1404 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1405 if ( !xIn.is() )
1407 // No interaction if we are not persistent!
1408 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1410 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1411 }));
1412 ucbhelper::cancelCommandExecution(
1413 ucb::IOErrorCode_CANT_READ,
1414 aArgs,
1415 m_eState == PERSISTENT
1416 ? xEnv
1417 : uno::Reference< ucb::XCommandEnvironment >(),
1418 u"Got no data stream!"_ustr,
1419 this );
1420 // Unreachable
1425 uno::Sequence< sal_Int8 > aBuffer;
1427 while (true)
1429 sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1430 if (!nRead)
1431 break;
1432 aBuffer.realloc( nRead );
1433 xOut->writeBytes( aBuffer );
1436 xOut->closeOutput();
1438 catch ( io::NotConnectedException const & )
1440 // closeOutput, readSomeBytes, writeBytes
1442 catch ( io::BufferSizeExceededException const & )
1444 // closeOutput, readSomeBytes, writeBytes
1446 catch ( io::IOException const & )
1448 // closeOutput, readSomeBytes, writeBytes
1451 else
1453 uno::Reference< io::XActiveDataSink > xDataSink(
1454 rArg.Sink, uno::UNO_QUERY );
1455 if ( xDataSink.is() )
1457 // PULL: wait for client read
1459 // May throw CommandFailedException, DocumentPasswordRequest!
1460 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1461 if ( !xIn.is() )
1463 // No interaction if we are not persistent!
1464 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1466 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1467 }));
1468 ucbhelper::cancelCommandExecution(
1469 ucb::IOErrorCode_CANT_READ,
1470 aArgs,
1471 m_eState == PERSISTENT
1472 ? xEnv
1473 : uno::Reference<
1474 ucb::XCommandEnvironment >(),
1475 u"Got no data stream!"_ustr,
1476 this );
1477 // Unreachable
1480 // Done.
1481 xDataSink->setInputStream( xIn );
1483 else
1485 ucbhelper::cancelCommandExecution(
1486 uno::Any(
1487 ucb::UnsupportedDataSinkException(
1488 OUString(),
1489 getXWeak(),
1490 rArg.Sink ) ),
1491 xEnv );
1492 // Unreachable
1498 return uno::Any();
1502 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1503 sal_Int32 nNameClashResolve,
1504 const uno::Reference<
1505 ucb::XCommandEnvironment > & xEnv )
1507 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1509 ContentType eType = m_aProps.getType();
1511 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1512 "insert command only supported by streams and folders!" );
1514 Uri aUri( m_xIdentifier->getContentIdentifier() );
1516 #if OSL_DEBUG_LEVEL > 0
1517 if ( eType == STREAM )
1519 Uri aParentUri( aUri.getParentUri() );
1520 OSL_ENSURE( !aParentUri.isDocument(),
1521 "insert command not supported by streams that are direct "
1522 "children of document root!" );
1524 #endif
1526 // Check, if all required properties were set.
1527 if ( eType == FOLDER )
1529 // Required: Title
1531 if ( m_aProps.getTitle().isEmpty() )
1532 m_aProps.setTitle( aUri.getDecodedName() );
1534 else // stream
1536 // Required: data
1538 if ( !xData.is() )
1540 ucbhelper::cancelCommandExecution(
1541 uno::Any( ucb::MissingInputStreamException(
1542 OUString(),
1543 getXWeak() ) ),
1544 xEnv );
1545 // Unreachable
1548 // Required: Title
1550 if ( m_aProps.getTitle().isEmpty() )
1551 m_aProps.setTitle( aUri.getDecodedName() );
1554 Uri aNewUri( aUri.getParentUri() + m_aProps.getTitle() );
1556 // Handle possible name clash...
1557 switch ( nNameClashResolve )
1559 // fail.
1560 case ucb::NameClash::ERROR:
1561 if ( hasData( aNewUri ) )
1563 ucbhelper::cancelCommandExecution(
1564 uno::Any( ucb::NameClashException(
1565 OUString(),
1566 getXWeak(),
1567 task::InteractionClassification_ERROR,
1568 m_aProps.getTitle() ) ),
1569 xEnv );
1570 // Unreachable
1572 break;
1574 // replace (possibly) existing object.
1575 case ucb::NameClash::OVERWRITE:
1576 break;
1578 // "invent" a new valid title.
1579 case ucb::NameClash::RENAME:
1580 if ( hasData( aNewUri ) )
1582 sal_Int32 nTry = 0;
1586 aNewUri.setUri( aNewUri.getUri() + "_" + OUString::number(++nTry) );
1588 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1590 if ( nTry == 1000 )
1592 ucbhelper::cancelCommandExecution(
1593 uno::Any(
1594 ucb::UnsupportedNameClashException(
1595 u"Unable to resolve name clash!"_ustr,
1596 getXWeak(),
1597 nNameClashResolve ) ),
1598 xEnv );
1599 // Unreachable
1601 else
1603 m_aProps.setTitle( m_aProps.getTitle() + "_" + OUString::number( ++nTry ) );
1606 break;
1608 case ucb::NameClash::KEEP: // deprecated
1609 case ucb::NameClash::ASK:
1610 default:
1611 if ( hasData( aNewUri ) )
1613 ucbhelper::cancelCommandExecution(
1614 uno::Any(
1615 ucb::UnsupportedNameClashException(
1616 OUString(),
1617 getXWeak(),
1618 nNameClashResolve ) ),
1619 xEnv );
1620 // Unreachable
1622 break;
1625 // Identifier changed?
1626 bool bNewId = ( aUri != aNewUri );
1628 if ( bNewId )
1630 m_xIdentifier
1631 = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1634 if ( !storeData( xData, xEnv ) )
1636 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1638 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1639 }));
1640 ucbhelper::cancelCommandExecution(
1641 ucb::IOErrorCode_CANT_WRITE,
1642 aArgs,
1643 xEnv,
1644 u"Cannot store persistent data!"_ustr,
1645 this );
1646 // Unreachable
1649 m_eState = PERSISTENT;
1651 if ( bNewId )
1653 //loadData( m_pProvider, m_aUri, m_aProps );
1655 aGuard.clear();
1656 inserted();
1661 void Content::destroy( bool bDeletePhysical,
1662 const uno::Reference<
1663 ucb::XCommandEnvironment > & xEnv )
1665 // @@@ take care about bDeletePhysical -> trashcan support
1667 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1669 ContentType eType = m_aProps.getType();
1671 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1672 "delete command only supported by streams and folders!" );
1674 uno::Reference< ucb::XContent > xThis = this;
1676 // Persistent?
1677 if ( m_eState != PERSISTENT )
1679 ucbhelper::cancelCommandExecution(
1680 uno::Any( ucb::UnsupportedCommandException(
1681 u"Not persistent!"_ustr,
1682 getXWeak() ) ),
1683 xEnv );
1684 // Unreachable
1687 m_eState = DEAD;
1689 aGuard.clear();
1690 deleted();
1692 if ( eType == FOLDER )
1694 // Process instantiated children...
1696 ContentRefList aChildren;
1697 queryChildren( aChildren );
1699 for ( auto& rChild : aChildren )
1701 rChild->destroy( bDeletePhysical, xEnv );
1707 void Content::notifyDocumentClosed()
1709 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1711 m_eState = DEAD;
1713 // @@@ anything else to reset or such?
1715 // callback follows!
1716 aGuard.clear();
1718 // Propagate destruction to content event listeners
1719 // Remove this from provider's content list.
1720 deleted();
1724 uno::Reference< ucb::XContent >
1725 Content::queryChildContent( std::u16string_view rRelativeChildUri )
1727 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1729 const OUString aMyId = getIdentifier()->getContentIdentifier();
1730 OUStringBuffer aBuf( aMyId );
1731 if ( !aMyId.endsWith("/") )
1732 aBuf.append( "/" );
1733 if ( !o3tl::starts_with(rRelativeChildUri, u"/") )
1734 aBuf.append( rRelativeChildUri );
1735 else
1736 aBuf.append( rRelativeChildUri.substr(1) );
1738 uno::Reference< ucb::XContentIdentifier > xChildId
1739 = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1741 uno::Reference< ucb::XContent > xChild;
1744 xChild = m_pProvider->queryContent( xChildId );
1746 catch ( ucb::IllegalIdentifierException const & )
1748 // handled below.
1751 OSL_ENSURE( xChild.is(),
1752 "Content::queryChildContent - unable to create child content!" );
1753 return xChild;
1757 void Content::notifyChildRemoved( std::u16string_view rRelativeChildUri )
1759 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1761 // Ugly! Need to create child content object, just to fill event properly.
1762 uno::Reference< ucb::XContent > xChild
1763 = queryChildContent( rRelativeChildUri );
1765 if ( !xChild.is() )
1766 return;
1768 // callback follows!
1769 aGuard.clear();
1771 // Notify "REMOVED" event.
1772 ucb::ContentEvent aEvt(
1773 getXWeak(),
1774 ucb::ContentAction::REMOVED,
1775 xChild,
1776 getIdentifier() );
1777 notifyContentEvent( aEvt );
1781 void Content::notifyChildInserted( std::u16string_view rRelativeChildUri )
1783 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1785 // Ugly! Need to create child content object, just to fill event properly.
1786 uno::Reference< ucb::XContent > xChild
1787 = queryChildContent( rRelativeChildUri );
1789 if ( !xChild.is() )
1790 return;
1792 // callback follows!
1793 aGuard.clear();
1795 // Notify "INSERTED" event.
1796 ucb::ContentEvent aEvt(
1797 getXWeak(),
1798 ucb::ContentAction::INSERTED,
1799 xChild,
1800 getIdentifier() );
1801 notifyContentEvent( aEvt );
1805 void Content::transfer(
1806 const ucb::TransferInfo& rInfo,
1807 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1809 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1811 // Persistent?
1812 if ( m_eState != PERSISTENT )
1814 ucbhelper::cancelCommandExecution(
1815 uno::Any( ucb::UnsupportedCommandException(
1816 u"Not persistent!"_ustr,
1817 getXWeak() ) ),
1818 xEnv );
1819 // Unreachable
1822 // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1824 if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1826 // Invalid length (to short).
1827 ucbhelper::cancelCommandExecution(
1828 uno::Any( ucb::InteractiveBadTransferURLException(
1829 OUString(),
1830 getXWeak() ) ),
1831 xEnv );
1832 // Unreachable
1835 OUString aScheme
1836 = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1837 .toAsciiLowerCase();
1838 if ( aScheme != TDOC_URL_SCHEME ":/" )
1840 // Invalid scheme.
1841 ucbhelper::cancelCommandExecution(
1842 uno::Any( ucb::InteractiveBadTransferURLException(
1843 OUString(),
1844 getXWeak() ) ),
1845 xEnv );
1846 // Unreachable
1849 // Does source URI describe a tdoc folder or stream?
1850 Uri aSourceUri( rInfo.SourceURL );
1851 if ( !aSourceUri.isValid() )
1853 ucbhelper::cancelCommandExecution(
1854 uno::Any( lang::IllegalArgumentException(
1855 u"Invalid source URI! Syntax!"_ustr,
1856 getXWeak(),
1857 -1 ) ),
1858 xEnv );
1859 // Unreachable
1862 if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1864 ucbhelper::cancelCommandExecution(
1865 uno::Any( lang::IllegalArgumentException(
1866 u"Invalid source URI! Must describe a folder or stream!"_ustr,
1867 getXWeak(),
1868 -1 ) ),
1869 xEnv );
1870 // Unreachable
1873 // Is source not a parent of me / not me?
1874 OUString aId = m_xIdentifier->getContentIdentifier();
1875 sal_Int32 nPos = aId.lastIndexOf( '/' );
1876 if ( nPos != ( aId.getLength() - 1 ) )
1878 // No trailing slash found. Append.
1879 aId += "/";
1882 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1884 if ( aId.startsWith( rInfo.SourceURL ) )
1886 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1888 {"Uri", uno::Any(rInfo.SourceURL)}
1889 }));
1890 ucbhelper::cancelCommandExecution(
1891 ucb::IOErrorCode_RECURSIVE,
1892 aArgs,
1893 xEnv,
1894 u"Target is equal to or is a child of source!"_ustr,
1895 this );
1896 // Unreachable
1900 if ( m_aProps.getType() == DOCUMENT )
1902 bool bOK = false;
1904 uno::Reference< embed::XStorage > xStorage
1905 = m_pProvider->queryStorage(
1906 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1907 if ( xStorage.is() )
1911 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1913 ucbhelper::cancelCommandExecution(
1914 uno::Any( lang::IllegalArgumentException(
1915 u"Invalid source URI! "
1916 "Streams cannot be created as "
1917 "children of document root!"_ustr,
1918 getXWeak(),
1919 -1 ) ),
1920 xEnv );
1921 // Unreachable
1923 bOK = true;
1925 catch ( container::NoSuchElementException const & )
1927 // handled below.
1929 catch ( lang::IllegalArgumentException const & )
1931 // handled below.
1933 catch ( embed::InvalidStorageException const & )
1935 // handled below.
1939 if ( !bOK )
1941 ucbhelper::cancelCommandExecution(
1942 uno::Any( lang::IllegalArgumentException(
1943 u"Invalid source URI! Unable to determine source type!"_ustr,
1944 getXWeak(),
1945 -1 ) ),
1946 xEnv );
1947 // Unreachable
1952 // Copy data.
1955 OUString aNewName( !rInfo.NewTitle.isEmpty()
1956 ? rInfo.NewTitle
1957 : aSourceUri.getDecodedName() );
1959 if ( !copyData( aSourceUri, aNewName ) )
1961 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1963 {"Uri", uno::Any(rInfo.SourceURL)}
1964 }));
1965 ucbhelper::cancelCommandExecution(
1966 ucb::IOErrorCode_CANT_WRITE,
1967 aArgs,
1968 xEnv,
1969 u"Cannot copy data!"_ustr,
1970 this );
1971 // Unreachable
1975 // Copy own and all children's Additional Core Properties.
1978 OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1979 if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1980 aTargetUri += "/";
1982 if ( !rInfo.NewTitle.isEmpty() )
1983 aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1984 else
1985 aTargetUri += aSourceUri.getName();
1987 if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1989 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1991 {"Uri", uno::Any(rInfo.SourceURL)}
1992 }));
1993 ucbhelper::cancelCommandExecution(
1994 ucb::IOErrorCode_CANT_WRITE,
1995 aArgs,
1996 xEnv,
1997 u"Cannot copy additional properties!"_ustr,
1998 this );
1999 // Unreachable
2003 // Propagate new content.
2006 rtl::Reference< Content > xTarget;
2009 uno::Reference< ucb::XContentIdentifier > xTargetId
2010 = new ::ucbhelper::ContentIdentifier( aTargetUri );
2012 // Note: The static cast is okay here, because its sure that
2013 // m_xProvider is always the WebDAVContentProvider.
2014 xTarget = static_cast< Content * >(
2015 m_pProvider->queryContent( xTargetId ).get() );
2018 catch ( ucb::IllegalIdentifierException const & )
2020 // queryContent
2023 if ( !xTarget.is() )
2025 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2027 {"Uri", uno::Any(aTargetUri)}
2028 }));
2029 ucbhelper::cancelCommandExecution(
2030 ucb::IOErrorCode_CANT_READ,
2031 aArgs,
2032 xEnv,
2033 u"Cannot instantiate target object!"_ustr,
2034 this );
2035 // Unreachable
2038 // Announce transferred content in its new folder.
2039 xTarget->inserted();
2042 // Remove source, if requested
2045 if ( !rInfo.MoveData )
2046 return;
2048 rtl::Reference< Content > xSource;
2051 uno::Reference< ucb::XContentIdentifier >
2052 xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2054 // Note: The static cast is okay here, because its sure
2055 // that m_xProvider is always the ContentProvider.
2056 xSource = static_cast< Content * >(
2057 m_xProvider->queryContent( xSourceId ).get() );
2059 catch ( ucb::IllegalIdentifierException const & )
2061 // queryContent
2064 if ( !xSource.is() )
2066 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2068 {"Uri", uno::Any(rInfo.SourceURL)}
2069 }));
2070 ucbhelper::cancelCommandExecution(
2071 ucb::IOErrorCode_CANT_READ,
2072 aArgs,
2073 xEnv,
2074 u"Cannot instantiate target object!"_ustr,
2075 this );
2076 // Unreachable
2079 // Propagate destruction (recursively).
2080 xSource->destroy( true, xEnv );
2082 // Remove all persistent data of source and its children.
2083 if ( !xSource->removeData() )
2085 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2087 {"Uri", uno::Any(rInfo.SourceURL)}
2088 }));
2089 ucbhelper::cancelCommandExecution(
2090 ucb::IOErrorCode_CANT_WRITE,
2091 aArgs,
2092 xEnv,
2093 u"Cannot remove persistent data of source object!"_ustr,
2094 this );
2095 // Unreachable
2098 // Remove own and all children's Additional Core Properties.
2099 if ( xSource->removeAdditionalPropertySet() )
2100 return;
2102 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2104 {"Uri", uno::Any(rInfo.SourceURL)}
2105 }));
2106 ucbhelper::cancelCommandExecution(
2107 ucb::IOErrorCode_CANT_WRITE,
2108 aArgs,
2109 xEnv,
2110 u"Cannot remove additional properties of source object!"_ustr,
2111 this );
2112 // Unreachable
2116 //static
2117 bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2119 if ( rUri.isRoot() )
2121 return true; // root has no storage
2123 else if ( rUri.isDocument() )
2125 uno::Reference< embed::XStorage > xStorage
2126 = pProvider->queryStorage( rUri.getUri(), READ );
2127 return xStorage.is();
2129 else
2131 // folder or stream
2133 // Ask parent storage. In case that rUri describes a stream,
2134 // ContentProvider::queryStorage( rUri ) would return null.
2136 uno::Reference< embed::XStorage > xStorage
2137 = pProvider->queryStorage( rUri.getParentUri(), READ );
2139 if ( !xStorage.is() )
2140 return false;
2142 return xStorage->hasByName( rUri.getDecodedName() );
2147 //static
2148 bool Content::loadData( ContentProvider const * pProvider,
2149 const Uri & rUri,
2150 ContentProperties& rProps )
2152 if ( rUri.isRoot() ) // root has no storage, but can always be created
2154 rProps
2155 = ContentProperties(
2156 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2158 else if ( rUri.isDocument() ) // document must have storage
2160 uno::Reference< embed::XStorage > xStorage
2161 = pProvider->queryStorage( rUri.getUri(), READ );
2163 if ( !xStorage.is() )
2164 return false;
2166 rProps
2167 = ContentProperties(
2168 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2170 else // stream or folder; stream has no storage; folder has storage
2172 uno::Reference< embed::XStorage > xStorage
2173 = pProvider->queryStorage( rUri.getParentUri(), READ );
2175 if ( !xStorage.is() )
2176 return false;
2178 // Check whether exists at all, is stream or folder
2181 // return: true -> folder
2182 // return: false -> stream
2183 // NoSuchElementException -> neither folder nor stream
2184 bool bIsFolder
2185 = xStorage->isStorageElement( rUri.getDecodedName() );
2187 rProps
2188 = ContentProperties(
2189 bIsFolder ? FOLDER : STREAM,
2190 pProvider->queryStorageTitle( rUri.getUri() ) );
2192 catch ( container::NoSuchElementException const & )
2194 // there is no element with such name
2195 //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2196 return false;
2198 catch ( lang::IllegalArgumentException const & )
2200 // an illegal argument is provided
2201 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2202 return false;
2204 catch ( embed::InvalidStorageException const & )
2206 // this storage is in invalid state for any reason
2207 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2208 return false;
2211 return true;
2215 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2216 const uno::Reference<
2217 ucb::XCommandEnvironment >& xEnv )
2219 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2221 ContentType eType = m_aProps.getType();
2222 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2224 OSL_FAIL( "storeData not supported by root and documents!" );
2225 return false;
2228 Uri aUri( m_xIdentifier->getContentIdentifier() );
2230 if ( eType == FOLDER )
2232 uno::Reference< embed::XStorage > xStorage
2233 = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2235 if ( !xStorage.is() )
2236 return false;
2238 uno::Reference< beans::XPropertySet > xPropSet(
2239 xStorage, uno::UNO_QUERY );
2240 OSL_ENSURE( xPropSet.is(),
2241 "Content::storeData - Got no XPropertySet interface!" );
2242 if ( !xPropSet.is() )
2243 return false;
2247 // According to MBA, if no mediatype is set, folder and all
2248 // its contents will be lost on save of the document!!!
2249 xPropSet->setPropertyValue(
2250 u"MediaType"_ustr,
2251 uno::Any(
2252 u"application/binary"_ustr ) );
2254 catch ( beans::UnknownPropertyException const & )
2256 OSL_FAIL( "Property MediaType not supported!" );
2257 return false;
2259 catch ( beans::PropertyVetoException const & )
2261 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2262 return false;
2264 catch ( lang::IllegalArgumentException const & )
2266 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2267 return false;
2269 catch ( lang::WrappedTargetException const & )
2271 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2272 return false;
2275 if ( !commitStorage( xStorage ) )
2276 return false;
2278 else if ( eType == STREAM )
2280 // stream
2282 // Important: Parent storage and output stream must be kept alive until
2283 // changes have been committed!
2284 uno::Reference< embed::XStorage > xStorage
2285 = m_pProvider->queryStorage(
2286 aUri.getParentUri(), READ_WRITE_CREATE );
2287 uno::Reference< io::XOutputStream > xOut;
2289 if ( !xStorage.is() )
2290 return false;
2292 if ( xData.is() )
2294 // May throw CommandFailedException, DocumentPasswordRequest!
2295 xOut = getTruncatedOutputStream( xEnv );
2297 OSL_ENSURE( xOut.is(), "No target data stream!" );
2301 uno::Sequence< sal_Int8 > aBuffer;
2302 while (true)
2304 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2305 if (!nRead)
2306 break;
2307 aBuffer.realloc( nRead );
2308 xOut->writeBytes( aBuffer );
2311 closeOutputStream( xOut );
2313 catch ( io::NotConnectedException const & )
2315 // readSomeBytes, writeBytes
2316 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2317 closeOutputStream( xOut );
2318 return false;
2320 catch ( io::BufferSizeExceededException const & )
2322 // readSomeBytes, writeBytes
2323 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2324 closeOutputStream( xOut );
2325 return false;
2327 catch ( io::IOException const & )
2329 // readSomeBytes, writeBytes
2330 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2331 closeOutputStream( xOut );
2332 return false;
2334 catch ( ... )
2336 closeOutputStream( xOut );
2337 throw;
2341 // Commit changes.
2342 if ( !commitStorage( xStorage ) )
2343 return false;
2345 else
2347 OSL_FAIL( "Unknown content type!" );
2348 return false;
2350 return true;
2354 void Content::renameData(
2355 const uno::Reference< ucb::XContentIdentifier >& xOldId,
2356 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2358 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2360 ContentType eType = m_aProps.getType();
2361 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2363 OSL_FAIL( "renameData not supported by root and documents!" );
2364 return;
2367 Uri aOldUri( xOldId->getContentIdentifier() );
2368 uno::Reference< embed::XStorage > xStorage
2369 = m_pProvider->queryStorage(
2370 aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2372 if ( !xStorage.is() )
2373 return;
2377 Uri aNewUri( xNewId->getContentIdentifier() );
2378 xStorage->renameElement(
2379 aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2381 catch ( embed::InvalidStorageException const & )
2383 // this storage is in invalid state for any reason
2384 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2385 return;
2387 catch ( lang::IllegalArgumentException const & )
2389 // an illegal argument is provided
2390 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2391 return;
2393 catch ( container::NoSuchElementException const & )
2395 // there is no element with old name in this storage
2396 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2397 return;
2399 catch ( container::ElementExistException const & )
2401 // an element with new name already exists in this storage
2402 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2403 return;
2405 catch ( io::IOException const & )
2407 // in case of io errors during renaming
2408 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2409 return;
2411 catch ( embed::StorageWrappedTargetException const & )
2413 // wraps other exceptions
2414 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2415 return;
2418 commitStorage( xStorage );
2422 bool Content::removeData()
2424 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2426 ContentType eType = m_aProps.getType();
2427 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2429 OSL_FAIL( "removeData not supported by root and documents!" );
2430 return false;
2433 Uri aUri( m_xIdentifier->getContentIdentifier() );
2434 uno::Reference< embed::XStorage > xStorage
2435 = m_pProvider->queryStorage(
2436 aUri.getParentUri(), READ_WRITE_NOCREATE );
2438 if ( !xStorage.is() )
2439 return false;
2443 xStorage->removeElement( aUri.getDecodedName() );
2445 catch ( embed::InvalidStorageException const & )
2447 // this storage is in invalid state for any reason
2448 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2449 return false;
2451 catch ( lang::IllegalArgumentException const & )
2453 // an illegal argument is provided
2454 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2455 return false;
2457 catch ( container::NoSuchElementException const & )
2459 // there is no element with this name in this storage
2460 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2461 return false;
2463 catch ( io::IOException const & )
2465 // in case of io errors during renaming
2466 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2467 return false;
2469 catch ( embed::StorageWrappedTargetException const & )
2471 // wraps other exceptions
2472 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2473 return false;
2476 return commitStorage( xStorage );
2480 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2482 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2484 ContentType eType = m_aProps.getType();
2485 if ( ( eType == ROOT ) || ( eType == STREAM ) )
2487 OSL_FAIL( "copyData not supported by root and streams!" );
2488 return false;
2491 Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2492 uno::Reference< embed::XStorage > xDestStorage
2493 = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2495 if ( !xDestStorage.is() )
2496 return false;
2498 uno::Reference< embed::XStorage > xSourceStorage
2499 = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2501 if ( !xSourceStorage.is() )
2502 return false;
2506 xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2507 xDestStorage,
2508 rNewName );
2510 catch ( embed::InvalidStorageException const & )
2512 // this storage is in invalid state for any reason
2513 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2514 return false;
2516 catch ( lang::IllegalArgumentException const & )
2518 // an illegal argument is provided
2519 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2520 return false;
2522 catch ( container::NoSuchElementException const & )
2524 // there is no element with this name in this storage
2525 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2526 return false;
2528 catch ( container::ElementExistException const & )
2530 // there is no element with this name in this storage
2531 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2532 return false;
2534 catch ( io::IOException const & )
2536 // in case of io errors during renaming
2537 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2538 return false;
2540 catch ( embed::StorageWrappedTargetException const & )
2542 // wraps other exceptions
2543 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2544 return false;
2547 return commitStorage( xDestStorage );
2551 // static
2552 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2554 // Commit changes
2555 uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2557 OSL_ENSURE( xTO.is(),
2558 "Required interface css.embed.XTransactedObject missing!" );
2561 xTO->commit();
2563 catch ( io::IOException const & )
2565 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2566 return false;
2568 catch ( lang::WrappedTargetException const & )
2570 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2571 return false;
2574 return true;
2578 // static
2579 bool Content::closeOutputStream(
2580 const uno::Reference< io::XOutputStream > & xOut )
2582 if ( xOut.is() )
2586 xOut->closeOutput();
2587 return true;
2589 catch ( io::NotConnectedException const & )
2591 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2593 catch ( io::BufferSizeExceededException const & )
2595 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2597 catch ( io::IOException const & )
2599 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2602 return false;
2605 /// @throws ucb::CommandFailedException
2606 /// @throws task::DocumentPasswordRequest
2607 static OUString obtainPassword(
2608 const OUString & rName,
2609 task::PasswordRequestMode eMode,
2610 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2612 rtl::Reference< DocumentPasswordRequest > xRequest
2613 = new DocumentPasswordRequest( eMode, rName );
2615 if ( xEnv.is() )
2617 uno::Reference< task::XInteractionHandler > xIH
2618 = xEnv->getInteractionHandler();
2619 if ( xIH.is() )
2621 xIH->handle( xRequest );
2623 rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2624 = xRequest->getSelection();
2626 if ( xSelection.is() )
2628 // Handler handled the request.
2629 uno::Reference< task::XInteractionAbort > xAbort(
2630 xSelection->getXWeak(), uno::UNO_QUERY );
2631 if ( xAbort.is() )
2633 throw ucb::CommandFailedException(
2634 u"Abort requested by Interaction Handler."_ustr,
2635 uno::Reference< uno::XInterface >(),
2636 xRequest->getRequest() );
2639 uno::Reference< task::XInteractionPassword > xPassword(
2640 xSelection->getXWeak(), uno::UNO_QUERY );
2641 if ( xPassword.is() )
2643 return xPassword->getPassword();
2646 // Unknown selection. Should never happen.
2647 throw ucb::CommandFailedException(
2648 u"Interaction Handler selected unknown continuation!"_ustr,
2649 uno::Reference< uno::XInterface >(),
2650 xRequest->getRequest() );
2655 // No IH or IH did not handle exception.
2656 task::DocumentPasswordRequest aRequest;
2657 xRequest->getRequest() >>= aRequest;
2658 throw aRequest;
2662 uno::Reference< io::XInputStream > Content::getInputStream(
2663 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2665 OUString aUri;
2666 OUString aPassword;
2667 bool bPasswordRequested = false;
2670 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2672 OSL_ENSURE( m_aProps.getType() == STREAM,
2673 "Content::getInputStream - content is no stream!" );
2675 aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2678 for ( ;; )
2682 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2683 return m_pProvider->queryInputStream( aUri, aPassword );
2685 catch ( packages::WrongPasswordException const & )
2687 // Obtain (new) password.
2688 aPassword
2689 = obtainPassword( aUri, /* @@@ find better title */
2690 bPasswordRequested
2691 ? task::PasswordRequestMode_PASSWORD_REENTER
2692 : task::PasswordRequestMode_PASSWORD_ENTER,
2693 xEnv );
2694 bPasswordRequested = true;
2699 /// @throws ucb::CommandFailedException
2700 /// @throws task::DocumentPasswordRequest
2701 /// @throws uno::RuntimeException
2702 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2703 const OUString & rUri,
2704 ContentProvider const * pProvider,
2705 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2707 OUString aPassword;
2708 bool bPasswordRequested = false;
2709 for ( ;; )
2713 return pProvider->queryOutputStream(
2714 rUri, aPassword, true /* truncate */ );
2716 catch ( packages::WrongPasswordException const & )
2718 // Obtain (new) password.
2719 aPassword
2720 = obtainPassword( rUri, /* @@@ find better title */
2721 bPasswordRequested
2722 ? task::PasswordRequestMode_PASSWORD_REENTER
2723 : task::PasswordRequestMode_PASSWORD_ENTER,
2724 xEnv );
2725 bPasswordRequested = true;
2731 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2732 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2734 OSL_ENSURE( m_aProps.getType() == STREAM,
2735 "Content::getTruncatedOutputStream - content is no stream!" );
2737 return lcl_getTruncatedOutputStream(
2738 Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2739 m_pProvider,
2740 xEnv );
2744 uno::Reference< io::XStream > Content::getStream(
2745 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2747 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2749 OSL_ENSURE( m_aProps.getType() == STREAM,
2750 "Content::getStream - content is no stream!" );
2752 OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2753 OUString aPassword;
2754 bool bPasswordRequested = false;
2755 for ( ;; )
2759 return m_pProvider->queryStream(
2760 aUri, aPassword, false /* no truncate */ );
2762 catch ( packages::WrongPasswordException const & )
2764 // Obtain (new) password.
2765 aPassword
2766 = obtainPassword( aUri, /* @@@ find better title */
2767 bPasswordRequested
2768 ? task::PasswordRequestMode_PASSWORD_REENTER
2769 : task::PasswordRequestMode_PASSWORD_ENTER,
2770 xEnv );
2771 bPasswordRequested = true;
2777 // ContentProperties Implementation.
2780 uno::Sequence< ucb::ContentInfo >
2781 ContentProperties::getCreatableContentsInfo() const
2783 if ( isContentCreator() )
2785 uno::Sequence< beans::Property > aProps( 1 );
2786 aProps.getArray()[ 0 ] = beans::Property(
2787 u"Title"_ustr,
2789 cppu::UnoType<OUString>::get(),
2790 beans::PropertyAttribute::BOUND );
2792 if ( getType() == DOCUMENT )
2794 // streams cannot be created as direct children of document root
2795 uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2797 // Folder.
2798 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2799 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2800 aSeq.getArray()[ 0 ].Properties = std::move(aProps);
2802 return aSeq;
2804 else
2806 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2808 // Folder.
2809 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2810 aSeq.getArray()[ 0 ].Attributes
2811 = ucb::ContentInfoAttribute::KIND_FOLDER;
2812 aSeq.getArray()[ 0 ].Properties = aProps;
2814 // Stream.
2815 aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2816 aSeq.getArray()[ 1 ].Attributes
2817 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2818 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2819 aSeq.getArray()[ 1 ].Properties = std::move(aProps);
2821 return aSeq;
2824 else
2826 OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2827 "object!" );
2829 return uno::Sequence< ucb::ContentInfo >( 0 );
2834 bool ContentProperties::isContentCreator() const
2836 return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2839 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */