1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 /**************************************************************************
23 **************************************************************************
24 *************************************************************************/
25 #include <osl/diagnose.h>
27 #include <rtl/ustring.hxx>
28 #include <com/sun/star/beans/IllegalTypeException.hpp>
29 #include <com/sun/star/beans/PropertyAttribute.hpp>
30 #include <com/sun/star/beans/PropertyExistException.hpp>
31 #include <com/sun/star/beans/PropertyState.hpp>
32 #include <com/sun/star/container/XEnumerationAccess.hpp>
33 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
34 #include <com/sun/star/container/XNameContainer.hpp>
35 #include <com/sun/star/container/XNamed.hpp>
36 #include <com/sun/star/io/BufferSizeExceededException.hpp>
37 #include <com/sun/star/io/NotConnectedException.hpp>
38 #include <com/sun/star/io/XActiveDataSink.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/lang/IllegalAccessException.hpp>
41 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
42 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
43 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
44 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
45 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
46 #include <com/sun/star/ucb/NameClash.hpp>
47 #include <com/sun/star/ucb/NameClashException.hpp>
48 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
49 #include <com/sun/star/ucb/OpenMode.hpp>
50 #include <com/sun/star/ucb/TransferInfo.hpp>
51 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
52 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
53 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
54 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
56 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
57 #include <com/sun/star/util/XChangesBatch.hpp>
58 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
59 #include <com/sun/star/uno/Any.hxx>
60 #include <com/sun/star/uno/Sequence.hxx>
61 #include <comphelper/propertysequence.hxx>
62 #include <cppuhelper/queryinterface.hxx>
63 #include <ucbhelper/contentidentifier.hxx>
64 #include <ucbhelper/propertyvalueset.hxx>
65 #include <ucbhelper/cancelcommandexecution.hxx>
66 #include <ucbhelper/macros.hxx>
67 #include "pkgcontent.hxx"
68 #include "pkgprovider.hxx"
69 #include "pkgresultset.hxx"
71 #include "../inc/urihelper.hxx"
73 using namespace com::sun::star
;
74 using namespace package_ucp
;
76 #define NONE_MODIFIED sal_uInt32( 0x00 )
77 #define MEDIATYPE_MODIFIED sal_uInt32( 0x01 )
78 #define COMPRESSED_MODIFIED sal_uInt32( 0x02 )
79 #define ENCRYPTED_MODIFIED sal_uInt32( 0x04 )
80 #define ENCRYPTIONKEY_MODIFIED sal_uInt32( 0x08 )
83 // ContentProperties Implementation.
86 ContentProperties::ContentProperties( const OUString
& rContentType
)
87 : aContentType( rContentType
),
91 bHasEncryptedEntries( false )
93 bIsFolder
= rContentType
== PACKAGE_FOLDER_CONTENT_TYPE
|| rContentType
== PACKAGE_ZIP_FOLDER_CONTENT_TYPE
;
94 bIsDocument
= !bIsFolder
;
96 OSL_ENSURE( bIsFolder
|| rContentType
== PACKAGE_STREAM_CONTENT_TYPE
|| rContentType
== PACKAGE_ZIP_STREAM_CONTENT_TYPE
,
97 "ContentProperties::ContentProperties - Unknown type!" );
101 uno::Sequence
< ucb::ContentInfo
>
102 ContentProperties::getCreatableContentsInfo( PackageUri
const & rUri
) const
106 uno::Sequence
< beans::Property
> aProps( 1 );
107 aProps
.getArray()[ 0 ] = beans::Property(
110 cppu::UnoType
<OUString
>::get(),
111 beans::PropertyAttribute::BOUND
);
113 uno::Sequence
< ucb::ContentInfo
> aSeq( 2 );
116 aSeq
.getArray()[ 0 ].Type
117 = Content::getContentType( rUri
.getScheme(), true );
118 aSeq
.getArray()[ 0 ].Attributes
119 = ucb::ContentInfoAttribute::KIND_FOLDER
;
120 aSeq
.getArray()[ 0 ].Properties
= aProps
;
123 aSeq
.getArray()[ 1 ].Type
124 = Content::getContentType( rUri
.getScheme(), false );
125 aSeq
.getArray()[ 1 ].Attributes
126 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
127 | ucb::ContentInfoAttribute::KIND_DOCUMENT
;
128 aSeq
.getArray()[ 1 ].Properties
= aProps
;
134 return uno::Sequence
< ucb::ContentInfo
>( 0 );
139 // Content Implementation.
142 // static ( "virtual" ctor )
143 Content
* Content::create(
144 const uno::Reference
< uno::XComponentContext
>& rxContext
,
145 ContentProvider
* pProvider
,
146 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
148 OUString aURL
= Identifier
->getContentIdentifier();
149 PackageUri
aURI( aURL
);
150 ContentProperties aProps
;
151 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
153 if ( loadData( pProvider
, aURI
, aProps
, xPackage
) )
157 sal_Int32 nLastSlash
= aURL
.lastIndexOf( '/' );
158 if ( ( nLastSlash
+ 1 ) == aURL
.getLength() )
160 // Client explicitly requested a folder!
161 if ( !aProps
.bIsFolder
)
165 uno::Reference
< ucb::XContentIdentifier
> xId
166 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
167 return new Content( rxContext
, pProvider
, xId
, xPackage
, aURI
, aProps
);
171 // resource doesn't exist
173 bool bFolder
= false;
175 // Guess type according to URI.
176 sal_Int32 nLastSlash
= aURL
.lastIndexOf( '/' );
177 if ( ( nLastSlash
+ 1 ) == aURL
.getLength() )
180 uno::Reference
< ucb::XContentIdentifier
> xId
181 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
183 ucb::ContentInfo aInfo
;
184 if ( bFolder
|| aURI
.isRootFolder() )
185 aInfo
.Type
= getContentType( aURI
.getScheme(), true );
187 aInfo
.Type
= getContentType( aURI
.getScheme(), false );
189 return new Content( rxContext
, pProvider
, xId
, xPackage
, aURI
, aInfo
);
194 // static ( "virtual" ctor )
195 Content
* Content::create(
196 const uno::Reference
< uno::XComponentContext
>& rxContext
,
197 ContentProvider
* pProvider
,
198 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
199 const ucb::ContentInfo
& Info
)
201 if ( Info
.Type
.isEmpty() )
204 PackageUri
aURI( Identifier
->getContentIdentifier() );
206 if ( !Info
.Type
.equalsIgnoreAsciiCase(
207 getContentType( aURI
.getScheme(), true ) ) &&
208 !Info
.Type
.equalsIgnoreAsciiCase(
209 getContentType( aURI
.getScheme(), false ) ) )
212 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
= pProvider
->createPackage( aURI
);
214 uno::Reference
< ucb::XContentIdentifier
> xId
215 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
216 return new Content( rxContext
, pProvider
, xId
, xPackage
, aURI
, Info
);
221 OUString
Content::getContentType(
222 const OUString
& aScheme
, bool bFolder
)
224 return ( "application/"
227 ? OUStringLiteral("-folder")
228 : OUStringLiteral("-stream") ) );
233 const uno::Reference
< uno::XComponentContext
>& rxContext
,
234 ContentProvider
* pProvider
,
235 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
236 const uno::Reference
< container::XHierarchicalNameAccess
> & Package
,
237 const PackageUri
& rUri
,
238 const ContentProperties
& rProps
)
239 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
242 m_eState( PERSISTENT
),
243 m_xPackage( Package
),
244 m_pProvider( pProvider
),
245 m_nModifiedProps( NONE_MODIFIED
)
251 const uno::Reference
< uno::XComponentContext
>& rxContext
,
252 ContentProvider
* pProvider
,
253 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
254 const uno::Reference
< container::XHierarchicalNameAccess
> & Package
,
255 const PackageUri
& rUri
,
256 const ucb::ContentInfo
& Info
)
257 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
259 m_aProps( Info
.Type
),
260 m_eState( TRANSIENT
),
261 m_xPackage( Package
),
262 m_pProvider( pProvider
),
263 m_nModifiedProps( NONE_MODIFIED
)
274 // XInterface methods.
278 void SAL_CALL
Content::acquire()
281 ContentImplHelper::acquire();
286 void SAL_CALL
Content::release()
289 ContentImplHelper::release();
294 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
299 aRet
= cppu::queryInterface(
300 rType
, static_cast< ucb::XContentCreator
* >( this ) );
302 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
306 // XTypeProvider methods.
309 XTYPEPROVIDER_COMMON_IMPL( Content
);
313 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
317 static cppu::OTypeCollection
s_aFolderTypes(
318 CPPU_TYPE_REF( lang::XTypeProvider
),
319 CPPU_TYPE_REF( lang::XServiceInfo
),
320 CPPU_TYPE_REF( lang::XComponent
),
321 CPPU_TYPE_REF( ucb::XContent
),
322 CPPU_TYPE_REF( ucb::XCommandProcessor
),
323 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
324 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
325 CPPU_TYPE_REF( beans::XPropertyContainer
),
326 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
327 CPPU_TYPE_REF( container::XChild
),
328 CPPU_TYPE_REF( ucb::XContentCreator
) );
330 return s_aFolderTypes
.getTypes();
335 static cppu::OTypeCollection
s_aDocumentTypes(
336 CPPU_TYPE_REF( lang::XTypeProvider
),
337 CPPU_TYPE_REF( lang::XServiceInfo
),
338 CPPU_TYPE_REF( lang::XComponent
),
339 CPPU_TYPE_REF( ucb::XContent
),
340 CPPU_TYPE_REF( ucb::XCommandProcessor
),
341 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
342 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
343 CPPU_TYPE_REF( beans::XPropertyContainer
),
344 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
345 CPPU_TYPE_REF( container::XChild
) );
347 return s_aDocumentTypes
.getTypes();
352 // XServiceInfo methods.
356 OUString SAL_CALL
Content::getImplementationName()
358 return "com.sun.star.comp.ucb.PackageContent";
363 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
365 return { isFolder()? OUString("com.sun.star.ucb.PackageFolderContent"):OUString("com.sun.star.ucb.PackageStreamContent") } ;
373 OUString SAL_CALL
Content::getContentType()
375 return m_aProps
.aContentType
;
379 // XCommandProcessor methods.
383 uno::Any SAL_CALL
Content::execute(
384 const ucb::Command
& aCommand
,
385 sal_Int32
/*CommandId*/,
386 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
390 if ( aCommand
.Name
== "getPropertyValues" )
396 uno::Sequence
< beans::Property
> Properties
;
397 if ( !( aCommand
.Argument
>>= Properties
) )
399 ucbhelper::cancelCommandExecution(
400 uno::makeAny( lang::IllegalArgumentException(
401 "Wrong argument type!",
402 static_cast< cppu::OWeakObject
* >( this ),
408 aRet
<<= getPropertyValues( Properties
);
410 else if ( aCommand
.Name
== "setPropertyValues" )
416 uno::Sequence
< beans::PropertyValue
> aProperties
;
417 if ( !( aCommand
.Argument
>>= aProperties
) )
419 ucbhelper::cancelCommandExecution(
420 uno::makeAny( lang::IllegalArgumentException(
421 "Wrong argument type!",
422 static_cast< cppu::OWeakObject
* >( this ),
428 if ( !aProperties
.hasElements() )
430 ucbhelper::cancelCommandExecution(
431 uno::makeAny( lang::IllegalArgumentException(
433 static_cast< cppu::OWeakObject
* >( this ),
439 aRet
<<= setPropertyValues( aProperties
, Environment
);
441 else if ( aCommand
.Name
== "getPropertySetInfo" )
444 // getPropertySetInfo
447 // Note: Implemented by base class.
448 aRet
<<= getPropertySetInfo( Environment
);
450 else if ( aCommand
.Name
== "getCommandInfo" )
456 // Note: Implemented by base class.
457 aRet
<<= getCommandInfo( Environment
);
459 else if ( aCommand
.Name
== "open" )
465 ucb::OpenCommandArgument2 aOpenCommand
;
466 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
468 ucbhelper::cancelCommandExecution(
469 uno::makeAny( lang::IllegalArgumentException(
470 "Wrong argument type!",
471 static_cast< cppu::OWeakObject
* >( this ),
477 aRet
= open( aOpenCommand
, Environment
);
479 else if ( !m_aUri
.isRootFolder() && aCommand
.Name
== "insert" )
485 ucb::InsertCommandArgument aArg
;
486 if ( !( aCommand
.Argument
>>= aArg
) )
488 ucbhelper::cancelCommandExecution(
489 uno::makeAny( lang::IllegalArgumentException(
490 "Wrong argument type!",
491 static_cast< cppu::OWeakObject
* >( this ),
497 sal_Int32 nNameClash
= aArg
.ReplaceExisting
498 ? ucb::NameClash::OVERWRITE
499 : ucb::NameClash::ERROR
;
500 insert( aArg
.Data
, nNameClash
, Environment
);
502 else if ( !m_aUri
.isRootFolder() && aCommand
.Name
== "delete" )
508 bool bDeletePhysical
= false;
509 aCommand
.Argument
>>= bDeletePhysical
;
510 destroy( bDeletePhysical
, Environment
);
512 // Remove own and all children's persistent data.
515 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
517 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
519 ucbhelper::cancelCommandExecution(
520 ucb::IOErrorCode_CANT_WRITE
,
523 "Cannot remove persistent data!",
528 // Remove own and all children's Additional Core Properties.
529 removeAdditionalPropertySet();
531 else if ( aCommand
.Name
== "transfer" )
535 // ( Not available at stream objects )
538 ucb::TransferInfo aInfo
;
539 if ( !( aCommand
.Argument
>>= aInfo
) )
541 ucbhelper::cancelCommandExecution(
542 uno::makeAny( lang::IllegalArgumentException(
543 "Wrong argument type!",
544 static_cast< cppu::OWeakObject
* >( this ),
550 transfer( aInfo
, Environment
);
552 else if ( aCommand
.Name
== "createNewContent" && isFolder() )
556 // ( Not available at stream objects )
559 ucb::ContentInfo aInfo
;
560 if ( !( aCommand
.Argument
>>= aInfo
) )
562 OSL_FAIL( "Wrong argument type!" );
563 ucbhelper::cancelCommandExecution(
564 uno::makeAny( lang::IllegalArgumentException(
565 "Wrong argument type!",
566 static_cast< cppu::OWeakObject
* >( this ),
572 aRet
<<= createNewContent( aInfo
);
574 else if ( aCommand
.Name
== "flush" )
578 // ( Not available at stream objects )
583 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
585 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
587 ucbhelper::cancelCommandExecution(
588 ucb::IOErrorCode_CANT_WRITE
,
591 "Cannot write file to disk!",
599 // Unsupported command
602 ucbhelper::cancelCommandExecution(
603 uno::makeAny( ucb::UnsupportedCommandException(
605 static_cast< cppu::OWeakObject
* >( this ) ) ),
615 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
617 // @@@ Implement logic to abort running commands, if this makes
618 // sense for your content.
622 // XContentCreator methods.
626 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
627 Content::queryCreatableContentsInfo()
629 return m_aProps
.getCreatableContentsInfo( m_aUri
);
634 uno::Reference
< ucb::XContent
> SAL_CALL
635 Content::createNewContent( const ucb::ContentInfo
& Info
)
639 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
641 if ( Info
.Type
.isEmpty() )
642 return uno::Reference
< ucb::XContent
>();
644 if ( !Info
.Type
.equalsIgnoreAsciiCase(
645 getContentType( m_aUri
.getScheme(), true ) ) &&
646 !Info
.Type
.equalsIgnoreAsciiCase(
647 getContentType( m_aUri
.getScheme(), false ) ) )
648 return uno::Reference
< ucb::XContent
>();
650 OUString aURL
= m_aUri
.getUri() + "/";
652 if ( Info
.Type
.equalsIgnoreAsciiCase(
653 getContentType( m_aUri
.getScheme(), true ) ) )
654 aURL
+= "New_Folder";
656 aURL
+= "New_Stream";
658 uno::Reference
< ucb::XContentIdentifier
> xId(
659 new ::ucbhelper::ContentIdentifier( aURL
) );
661 return create( m_xContext
, m_pProvider
, xId
, Info
);
665 OSL_FAIL( "createNewContent called on non-folder object!" );
666 return uno::Reference
< ucb::XContent
>();
671 // Non-interface methods.
675 OUString
Content::getParentURL()
677 return m_aUri
.getParentUri();
682 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
683 const uno::Reference
< uno::XComponentContext
>& rxContext
,
684 const uno::Sequence
< beans::Property
>& rProperties
,
685 ContentProvider
* pProvider
,
686 const OUString
& rContentId
)
688 ContentProperties aData
;
689 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
690 if ( loadData( pProvider
, PackageUri( rContentId
), aData
, xPackage
) )
692 return getPropertyValues( rxContext
,
696 ::ucbhelper::ContentProviderImplHelper
>(
702 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
703 = new ::ucbhelper::PropertyValueSet( rxContext
);
705 for ( const beans::Property
& rProp
: rProperties
)
706 xRow
->appendVoid( rProp
);
708 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
714 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
715 const uno::Reference
< uno::XComponentContext
>& rxContext
,
716 const uno::Sequence
< beans::Property
>& rProperties
,
717 const ContentProperties
& rData
,
718 const rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
>&
720 const OUString
& rContentId
)
722 // Note: Empty sequence means "get values of all supported properties".
724 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
725 = new ::ucbhelper::PropertyValueSet( rxContext
);
727 if ( rProperties
.hasElements() )
729 uno::Reference
< beans::XPropertySet
> xAdditionalPropSet
;
730 bool bTriedToGetAdditionalPropSet
= false;
732 for ( const beans::Property
& rProp
: rProperties
)
734 // Process Core properties.
736 if ( rProp
.Name
== "ContentType" )
738 xRow
->appendString ( rProp
, rData
.aContentType
);
740 else if ( rProp
.Name
== "Title" )
742 xRow
->appendString ( rProp
, rData
.aTitle
);
744 else if ( rProp
.Name
== "IsDocument" )
746 xRow
->appendBoolean( rProp
, rData
.bIsDocument
);
748 else if ( rProp
.Name
== "IsFolder" )
750 xRow
->appendBoolean( rProp
, rData
.bIsFolder
);
752 else if ( rProp
.Name
== "CreatableContentsInfo" )
756 rData
.getCreatableContentsInfo(
757 PackageUri( rContentId
) ) ) );
759 else if ( rProp
.Name
== "MediaType" )
761 xRow
->appendString ( rProp
, rData
.aMediaType
);
763 else if ( rProp
.Name
== "Size" )
765 // Property only available for streams.
766 if ( rData
.bIsDocument
)
767 xRow
->appendLong( rProp
, rData
.nSize
);
769 xRow
->appendVoid( rProp
);
771 else if ( rProp
.Name
== "Compressed" )
773 // Property only available for streams.
774 if ( rData
.bIsDocument
)
775 xRow
->appendBoolean( rProp
, rData
.bCompressed
);
777 xRow
->appendVoid( rProp
);
779 else if ( rProp
.Name
== "Encrypted" )
781 // Property only available for streams.
782 if ( rData
.bIsDocument
)
783 xRow
->appendBoolean( rProp
, rData
.bEncrypted
);
785 xRow
->appendVoid( rProp
);
787 else if ( rProp
.Name
== "HasEncryptedEntries" )
789 // Property only available for root folder.
790 PackageUri
aURI( rContentId
);
791 if ( aURI
.isRootFolder() )
792 xRow
->appendBoolean( rProp
, rData
.bHasEncryptedEntries
);
794 xRow
->appendVoid( rProp
);
798 // Not a Core Property! Maybe it's an Additional Core Property?!
800 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
803 rProvider
->getAdditionalPropertySet( rContentId
,
805 bTriedToGetAdditionalPropSet
= true;
808 if ( xAdditionalPropSet
.is() )
810 if ( !xRow
->appendPropertySetValue(
814 // Append empty entry.
815 xRow
->appendVoid( rProp
);
820 // Append empty entry.
821 xRow
->appendVoid( rProp
);
828 // Append all Core Properties.
833 cppu::UnoType
<OUString
>::get(),
834 beans::PropertyAttribute::BOUND
835 | beans::PropertyAttribute::READONLY
),
836 rData
.aContentType
);
841 cppu::UnoType
<OUString
>::get(),
842 beans::PropertyAttribute::BOUND
),
848 cppu::UnoType
<bool>::get(),
849 beans::PropertyAttribute::BOUND
850 | beans::PropertyAttribute::READONLY
),
856 cppu::UnoType
<bool>::get(),
857 beans::PropertyAttribute::BOUND
858 | beans::PropertyAttribute::READONLY
),
862 "CreatableContentsInfo",
864 cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
865 beans::PropertyAttribute::BOUND
866 | beans::PropertyAttribute::READONLY
),
868 rData
.getCreatableContentsInfo( PackageUri( rContentId
) ) ) );
873 cppu::UnoType
<OUString
>::get(),
874 beans::PropertyAttribute::BOUND
),
877 // Properties only available for streams.
878 if ( rData
.bIsDocument
)
884 cppu::UnoType
<sal_Int64
>::get(),
885 beans::PropertyAttribute::BOUND
886 | beans::PropertyAttribute::READONLY
),
893 cppu::UnoType
<bool>::get(),
894 beans::PropertyAttribute::BOUND
),
901 cppu::UnoType
<bool>::get(),
902 beans::PropertyAttribute::BOUND
),
906 // Properties only available for root folder.
907 PackageUri
aURI( rContentId
);
908 if ( aURI
.isRootFolder() )
912 "HasEncryptedEntries",
914 cppu::UnoType
<bool>::get(),
915 beans::PropertyAttribute::BOUND
916 | beans::PropertyAttribute::READONLY
),
917 rData
.bHasEncryptedEntries
);
920 // Append all Additional Core Properties.
922 uno::Reference
< beans::XPropertySet
> xSet
=
923 rProvider
->getAdditionalPropertySet( rContentId
, false );
924 xRow
->appendPropertySet( xSet
);
927 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
931 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
932 const uno::Sequence
< beans::Property
>& rProperties
)
934 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
935 return getPropertyValues( m_xContext
,
939 ::ucbhelper::ContentProviderImplHelper
>(
941 m_xIdentifier
->getContentIdentifier() );
945 uno::Sequence
< uno::Any
> Content::setPropertyValues(
946 const uno::Sequence
< beans::PropertyValue
>& rValues
,
947 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
949 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
951 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
952 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
953 sal_Int32 nChanged
= 0;
955 beans::PropertyChangeEvent aEvent
;
956 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
957 aEvent
.Further
= false;
958 // aEvent.PropertyName =
959 aEvent
.PropertyHandle
= -1;
963 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
964 sal_Int32 nCount
= rValues
.getLength();
966 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
967 bool bTriedToGetAdditionalPropSet
= false;
968 bool bExchange
= false;
971 sal_Int32 nTitlePos
= -1;
973 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
975 const beans::PropertyValue
& rValue
= pValues
[ n
];
977 if ( rValue
.Name
== "ContentType" )
979 // Read-only property!
980 aRet
[ n
] <<= lang::IllegalAccessException(
981 "Property is read-only!",
982 static_cast< cppu::OWeakObject
* >( this ) );
984 else if ( rValue
.Name
== "IsDocument" )
986 // Read-only property!
987 aRet
[ n
] <<= lang::IllegalAccessException(
988 "Property is read-only!",
989 static_cast< cppu::OWeakObject
* >( this ) );
991 else if ( rValue
.Name
== "IsFolder" )
993 // Read-only property!
994 aRet
[ n
] <<= lang::IllegalAccessException(
995 "Property is read-only!",
996 static_cast< cppu::OWeakObject
* >( this ) );
998 else if ( rValue
.Name
== "CreatableContentsInfo" )
1000 // Read-only property!
1001 aRet
[ n
] <<= lang::IllegalAccessException(
1002 "Property is read-only!",
1003 static_cast< cppu::OWeakObject
* >( this ) );
1005 else if ( rValue
.Name
== "Title" )
1007 if ( m_aUri
.isRootFolder() )
1009 // Read-only property!
1010 aRet
[ n
] <<= lang::IllegalAccessException(
1011 "Property is read-only!",
1012 static_cast< cppu::OWeakObject
* >( this ) );
1017 if ( rValue
.Value
>>= aNewValue
)
1020 if ( !aNewValue
.isEmpty() )
1022 if ( aNewValue
!= m_aProps
.aTitle
)
1024 // modified title -> modified URL -> exchange !
1025 if ( m_eState
== PERSISTENT
)
1028 // new value will be set later...
1029 aNewTitle
= aNewValue
;
1031 // remember position within sequence of values
1032 // (for error handling).
1039 lang::IllegalArgumentException(
1040 "Empty title not allowed!",
1041 static_cast< cppu::OWeakObject
* >( this ),
1048 beans::IllegalTypeException(
1049 "Property value has wrong type!",
1050 static_cast< cppu::OWeakObject
* >( this ) );
1054 else if ( rValue
.Name
== "MediaType" )
1057 if ( rValue
.Value
>>= aNewValue
)
1059 if ( aNewValue
!= m_aProps
.aMediaType
)
1061 aEvent
.PropertyName
= rValue
.Name
;
1062 aEvent
.OldValue
<<= m_aProps
.aMediaType
;
1063 aEvent
.NewValue
<<= aNewValue
;
1065 m_aProps
.aMediaType
= aNewValue
;
1068 m_nModifiedProps
|= MEDIATYPE_MODIFIED
;
1073 aRet
[ n
] <<= beans::IllegalTypeException(
1074 "Property value has wrong type!",
1075 static_cast< cppu::OWeakObject
* >( this ) );
1078 else if ( rValue
.Name
== "Size" )
1080 // Read-only property!
1081 aRet
[ n
] <<= lang::IllegalAccessException(
1082 "Property is read-only!",
1083 static_cast< cppu::OWeakObject
* >( this ) );
1085 else if ( rValue
.Name
== "Compressed" )
1087 // Property only available for streams.
1088 if ( m_aProps
.bIsDocument
)
1091 if ( rValue
.Value
>>= bNewValue
)
1093 if ( bNewValue
!= m_aProps
.bCompressed
)
1095 aEvent
.PropertyName
= rValue
.Name
;
1096 aEvent
.OldValue
<<= m_aProps
.bCompressed
;
1097 aEvent
.NewValue
<<= bNewValue
;
1099 m_aProps
.bCompressed
= bNewValue
;
1102 m_nModifiedProps
|= COMPRESSED_MODIFIED
;
1107 aRet
[ n
] <<= beans::IllegalTypeException(
1108 "Property value has wrong type!",
1109 static_cast< cppu::OWeakObject
* >( this ) );
1114 aRet
[ n
] <<= beans::UnknownPropertyException(
1115 "Compressed only supported by streams!",
1116 static_cast< cppu::OWeakObject
* >( this ) );
1119 else if ( rValue
.Name
== "Encrypted" )
1121 // Property only available for streams.
1122 if ( m_aProps
.bIsDocument
)
1125 if ( rValue
.Value
>>= bNewValue
)
1127 if ( bNewValue
!= m_aProps
.bEncrypted
)
1129 aEvent
.PropertyName
= rValue
.Name
;
1130 aEvent
.OldValue
<<= m_aProps
.bEncrypted
;
1131 aEvent
.NewValue
<<= bNewValue
;
1133 m_aProps
.bEncrypted
= bNewValue
;
1136 m_nModifiedProps
|= ENCRYPTED_MODIFIED
;
1141 aRet
[ n
] <<= beans::IllegalTypeException(
1142 "Property value has wrong type!",
1143 static_cast< cppu::OWeakObject
* >( this ) );
1148 aRet
[ n
] <<= beans::UnknownPropertyException(
1149 "Encrypted only supported by streams!",
1150 static_cast< cppu::OWeakObject
* >( this ) );
1153 else if ( rValue
.Name
== "HasEncryptedEntries" )
1155 // Read-only property!
1156 aRet
[ n
] <<= lang::IllegalAccessException(
1157 "Property is read-only!",
1158 static_cast< cppu::OWeakObject
* >( this ) );
1160 else if ( rValue
.Name
== "EncryptionKey" )
1162 // @@@ This is a temporary solution. In the future submitting
1163 // the key should be done using an interaction handler!
1165 // Write-Only property. Only supported by root folder and streams
1166 // (all non-root folders of a package have the same encryption key).
1167 if ( m_aUri
.isRootFolder() || m_aProps
.bIsDocument
)
1169 uno::Sequence
< sal_Int8
> aNewValue
;
1170 if ( rValue
.Value
>>= aNewValue
)
1172 if ( aNewValue
!= m_aProps
.aEncryptionKey
)
1174 aEvent
.PropertyName
= rValue
.Name
;
1175 aEvent
.OldValue
<<= m_aProps
.aEncryptionKey
;
1176 aEvent
.NewValue
<<= aNewValue
;
1178 m_aProps
.aEncryptionKey
= aNewValue
;
1181 m_nModifiedProps
|= ENCRYPTIONKEY_MODIFIED
;
1186 aRet
[ n
] <<= beans::IllegalTypeException(
1187 "Property value has wrong type!",
1188 static_cast< cppu::OWeakObject
* >( this ) );
1193 aRet
[ n
] <<= beans::UnknownPropertyException(
1194 "EncryptionKey not supported by non-root folder!",
1195 static_cast< cppu::OWeakObject
* >( this ) );
1200 // Not a Core Property! Maybe it's an Additional Core Property?!
1202 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1204 xAdditionalPropSet
= getAdditionalPropertySet( false );
1205 bTriedToGetAdditionalPropSet
= true;
1208 if ( xAdditionalPropSet
.is() )
1213 = xAdditionalPropSet
->getPropertyValue( rValue
.Name
);
1214 if ( aOldValue
!= rValue
.Value
)
1216 xAdditionalPropSet
->setPropertyValue(
1217 rValue
.Name
, rValue
.Value
);
1219 aEvent
.PropertyName
= rValue
.Name
;
1220 aEvent
.OldValue
= aOldValue
;
1221 aEvent
.NewValue
= rValue
.Value
;
1223 aChanges
.getArray()[ nChanged
] = aEvent
;
1227 catch ( beans::UnknownPropertyException
const & e
)
1231 catch ( lang::WrappedTargetException
const & e
)
1235 catch ( beans::PropertyVetoException
const & e
)
1239 catch ( lang::IllegalArgumentException
const & e
)
1246 aRet
[ n
] <<= uno::Exception(
1247 "No property set for storing the value!",
1248 static_cast< cppu::OWeakObject
* >( this ) );
1255 uno::Reference
< ucb::XContentIdentifier
> xOldId
= m_xIdentifier
;
1257 // Assemble new content identifier...
1258 OUString aNewURL
= m_aUri
.getParentUri() + "/";
1259 aNewURL
+= ::ucb_impl::urihelper::encodeSegment( aNewTitle
);
1260 uno::Reference
< ucb::XContentIdentifier
> xNewId
1261 = new ::ucbhelper::ContentIdentifier( aNewURL
);
1264 if ( exchangeIdentity( xNewId
) )
1266 // Adapt persistent data.
1267 renameData( xOldId
, xNewId
);
1269 // Adapt Additional Core Properties.
1270 renameAdditionalPropertySet( xOldId
->getContentIdentifier(),
1271 xNewId
->getContentIdentifier() );
1275 // Do not set new title!
1279 aRet
[ nTitlePos
] <<= uno::Exception(
1281 static_cast< cppu::OWeakObject
* >( this ) );
1285 if ( !aNewTitle
.isEmpty() )
1287 aEvent
.PropertyName
= "Title";
1288 aEvent
.OldValue
<<= m_aProps
.aTitle
;
1289 aEvent
.NewValue
<<= aNewTitle
;
1291 m_aProps
.aTitle
= aNewTitle
;
1293 aChanges
.getArray()[ nChanged
] = aEvent
;
1299 // Save changes, if content was already made persistent.
1300 if ( ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
) ||
1301 ( bStore
&& ( m_eState
== PERSISTENT
) ) )
1303 if ( !storeData( uno::Reference
< io::XInputStream
>() ) )
1305 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1307 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1309 ucbhelper::cancelCommandExecution(
1310 ucb::IOErrorCode_CANT_WRITE
,
1313 "Cannot store persistent data!",
1320 aChanges
.realloc( nChanged
);
1321 notifyPropertiesChange( aChanges
);
1328 uno::Any
Content::open(
1329 const ucb::OpenCommandArgument2
& rArg
,
1330 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1332 if ( rArg
.Mode
== ucb::OpenMode::ALL
||
1333 rArg
.Mode
== ucb::OpenMode::FOLDERS
||
1334 rArg
.Mode
== ucb::OpenMode::DOCUMENTS
)
1337 // open command for a folder content
1340 uno::Reference
< ucb::XDynamicResultSet
> xSet
1341 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
1342 return uno::makeAny( xSet
);
1347 // open command for a document content
1350 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1351 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
1353 // Currently(?) unsupported.
1354 ucbhelper::cancelCommandExecution(
1355 uno::makeAny( ucb::UnsupportedOpenModeException(
1357 static_cast< cppu::OWeakObject
* >( this ),
1358 sal_Int16( rArg
.Mode
) ) ),
1363 uno::Reference
< io::XOutputStream
> xOut( rArg
.Sink
, uno::UNO_QUERY
);
1366 // PUSH: write data into xOut
1368 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1371 // No interaction if we are not persistent!
1372 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1374 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1376 ucbhelper::cancelCommandExecution(
1377 ucb::IOErrorCode_CANT_READ
,
1379 m_eState
== PERSISTENT
1381 : uno::Reference
< ucb::XCommandEnvironment
>(),
1382 "Got no data stream!",
1389 uno::Sequence
< sal_Int8
> aBuffer
;
1392 sal_Int32 nRead
= xIn
->readSomeBytes( aBuffer
, 65536 );
1395 aBuffer
.realloc( nRead
);
1396 xOut
->writeBytes( aBuffer
);
1399 xOut
->closeOutput();
1401 catch ( io::NotConnectedException
const & )
1403 // closeOutput, readSomeBytes, writeBytes
1405 catch ( io::BufferSizeExceededException
const & )
1407 // closeOutput, readSomeBytes, writeBytes
1409 catch ( io::IOException
const & )
1411 // closeOutput, readSomeBytes, writeBytes
1416 uno::Reference
< io::XActiveDataSink
> xDataSink(
1417 rArg
.Sink
, uno::UNO_QUERY
);
1418 if ( xDataSink
.is() )
1420 // PULL: wait for client read
1422 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1425 // No interaction if we are not persistent!
1426 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1428 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1430 ucbhelper::cancelCommandExecution(
1431 ucb::IOErrorCode_CANT_READ
,
1433 m_eState
== PERSISTENT
1436 ucb::XCommandEnvironment
>(),
1437 "Got no data stream!",
1443 xDataSink
->setInputStream( xIn
);
1447 // Note: aOpenCommand.Sink may contain an XStream
1448 // implementation. Support for this type of
1449 // sink is optional...
1450 ucbhelper::cancelCommandExecution(
1452 ucb::UnsupportedDataSinkException(
1454 static_cast< cppu::OWeakObject
* >( this ),
1466 void Content::insert(
1467 const uno::Reference
< io::XInputStream
>& xStream
,
1468 sal_Int32 nNameClashResolve
,
1469 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1471 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1473 // Check, if all required properties were set.
1478 if ( m_aProps
.aTitle
.isEmpty() )
1479 m_aProps
.aTitle
= m_aUri
.getName();
1483 // Required: rArg.Data
1485 if ( !xStream
.is() )
1487 ucbhelper::cancelCommandExecution(
1488 uno::makeAny( ucb::MissingInputStreamException(
1490 static_cast< cppu::OWeakObject
* >( this ) ) ),
1497 if ( m_aProps
.aTitle
.isEmpty() )
1498 m_aProps
.aTitle
= m_aUri
.getName();
1501 OUString aNewURL
= m_aUri
.getParentUri();
1502 if (1 + aNewURL
.lastIndexOf('/') != aNewURL
.getLength())
1504 aNewURL
+= ::ucb_impl::urihelper::encodeSegment( m_aProps
.aTitle
);
1505 PackageUri
aNewUri( aNewURL
);
1507 // Handle possible name clash...
1508 switch ( nNameClashResolve
)
1511 case ucb::NameClash::ERROR
:
1512 if ( hasData( aNewUri
) )
1514 ucbhelper::cancelCommandExecution(
1515 uno::makeAny( ucb::NameClashException(
1517 static_cast< cppu::OWeakObject
* >( this ),
1518 task::InteractionClassification_ERROR
,
1519 m_aProps
.aTitle
) ),
1525 // replace (possibly) existing object.
1526 case ucb::NameClash::OVERWRITE
:
1529 // "invent" a new valid title.
1530 case ucb::NameClash::RENAME
:
1531 if ( hasData( aNewUri
) )
1537 OUString aNew
= aNewUri
.getUri() + "_";
1538 aNew
+= OUString::number( ++nTry
);
1539 aNewUri
.setUri( aNew
);
1541 while ( hasData( aNewUri
) && ( nTry
< 1000 ) );
1545 ucbhelper::cancelCommandExecution(
1547 ucb::UnsupportedNameClashException(
1548 "Unable to resolve name clash!",
1549 static_cast< cppu::OWeakObject
* >( this ),
1550 nNameClashResolve
) ),
1556 m_aProps
.aTitle
+= "_";
1557 m_aProps
.aTitle
+= OUString::number( nTry
);
1562 case ucb::NameClash::KEEP
: // deprecated
1563 case ucb::NameClash::ASK
:
1565 if ( hasData( aNewUri
) )
1567 ucbhelper::cancelCommandExecution(
1569 ucb::UnsupportedNameClashException(
1571 static_cast< cppu::OWeakObject
* >( this ),
1572 nNameClashResolve
) ),
1579 // Identifier changed?
1580 bool bNewId
= ( m_aUri
.getUri() != aNewUri
.getUri() );
1584 m_xIdentifier
= new ::ucbhelper::ContentIdentifier( aNewURL
);
1588 if ( !storeData( xStream
) )
1590 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1592 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1594 ucbhelper::cancelCommandExecution(
1595 ucb::IOErrorCode_CANT_WRITE
,
1598 "Cannot store persistent data!",
1603 m_eState
= PERSISTENT
;
1607 // Take over correct default values from underlying packager...
1608 uno::Reference
< container::XHierarchicalNameAccess
> xXHierarchicalNameAccess
;
1609 loadData( m_pProvider
,
1612 xXHierarchicalNameAccess
);
1620 void Content::destroy(
1621 bool bDeletePhysical
,
1622 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1624 // @@@ take care about bDeletePhysical -> trashcan support
1626 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1628 uno::Reference
< ucb::XContent
> xThis
= this;
1631 if ( m_eState
!= PERSISTENT
)
1633 ucbhelper::cancelCommandExecution(
1634 uno::makeAny( ucb::UnsupportedCommandException(
1636 static_cast< cppu::OWeakObject
* >( this ) ) ),
1648 // Process instantiated children...
1650 ContentRefList aChildren
;
1651 queryChildren( aChildren
);
1653 for ( auto& rChild
: aChildren
)
1655 rChild
->destroy( bDeletePhysical
, xEnv
);
1661 void Content::transfer(
1662 const ucb::TransferInfo
& rInfo
,
1663 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1665 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1668 if ( m_eState
!= PERSISTENT
)
1670 ucbhelper::cancelCommandExecution(
1671 uno::makeAny( ucb::UnsupportedCommandException(
1673 static_cast< cppu::OWeakObject
* >( this ) ) ),
1678 // Is source a package content?
1679 if ( ( rInfo
.SourceURL
.isEmpty() ) ||
1680 ( rInfo
.SourceURL
.compareTo(
1681 m_aUri
.getUri(), PACKAGE_URL_SCHEME_LENGTH
+ 3 ) != 0 ) )
1683 ucbhelper::cancelCommandExecution(
1684 uno::makeAny( ucb::InteractiveBadTransferURLException(
1686 static_cast< cppu::OWeakObject
* >( this ) ) ),
1691 // Is source not a parent of me / not me?
1692 OUString aId
= m_aUri
.getParentUri() + "/";
1694 if ( rInfo
.SourceURL
.getLength() <= aId
.getLength() )
1696 if ( aId
.startsWith( rInfo
.SourceURL
) )
1698 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1700 {"Uri", uno::Any(rInfo
.SourceURL
)}
1702 ucbhelper::cancelCommandExecution(
1703 ucb::IOErrorCode_RECURSIVE
,
1706 "Target is equal to or is a child of source!",
1713 // 0) Obtain content object for source.
1716 uno::Reference
< ucb::XContentIdentifier
> xId
1717 = new ::ucbhelper::ContentIdentifier( rInfo
.SourceURL
);
1719 // Note: The static cast is okay here, because its sure that
1720 // m_xProvider is always the PackageContentProvider.
1721 rtl::Reference
< Content
> xSource
;
1725 xSource
= static_cast< Content
* >(
1726 m_xProvider
->queryContent( xId
).get() );
1728 catch ( ucb::IllegalIdentifierException
const & )
1733 if ( !xSource
.is() )
1735 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1737 {"Uri", uno::Any(xId
->getContentIdentifier())}
1739 ucbhelper::cancelCommandExecution(
1740 ucb::IOErrorCode_CANT_READ
,
1743 "Cannot instantiate source object!",
1749 // 1) Create new child content.
1752 OUString aType
= xSource
->isFolder()
1753 ? getContentType( m_aUri
.getScheme(), true )
1754 : getContentType( m_aUri
.getScheme(), false );
1755 ucb::ContentInfo aContentInfo
;
1756 aContentInfo
.Type
= aType
;
1757 aContentInfo
.Attributes
= 0;
1759 // Note: The static cast is okay here, because its sure that
1760 // createNewContent always creates a Content.
1761 rtl::Reference
< Content
> xTarget
1762 = static_cast< Content
* >( createNewContent( aContentInfo
).get() );
1763 if ( !xTarget
.is() )
1765 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1767 {"Folder", uno::Any(aId
)}
1769 ucbhelper::cancelCommandExecution(
1770 ucb::IOErrorCode_CANT_CREATE
,
1773 "XContentCreator::createNewContent failed!",
1779 // 2) Copy data from source content to child content.
1782 uno::Sequence
< beans::Property
> aSourceProps
1783 = xSource
->getPropertySetInfo( xEnv
)->getProperties();
1784 sal_Int32 nCount
= aSourceProps
.getLength();
1788 bool bHadTitle
= rInfo
.NewTitle
.isEmpty();
1790 // Get all source values.
1791 uno::Reference
< sdbc::XRow
> xRow
1792 = xSource
->getPropertyValues( aSourceProps
);
1794 uno::Sequence
< beans::PropertyValue
> aValues( nCount
);
1795 beans::PropertyValue
* pValues
= aValues
.getArray();
1797 const beans::Property
* pProps
= aSourceProps
.getConstArray();
1798 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1800 const beans::Property
& rProp
= pProps
[ n
];
1801 beans::PropertyValue
& rValue
= pValues
[ n
];
1803 rValue
.Name
= rProp
.Name
;
1804 rValue
.Handle
= rProp
.Handle
;
1806 if ( !bHadTitle
&& rProp
.Name
== "Title" )
1808 // Set new title instead of original.
1810 rValue
.Value
<<= rInfo
.NewTitle
;
1814 = xRow
->getObject( n
+ 1,
1816 container::XNameAccess
>() );
1818 rValue
.State
= beans::PropertyState_DIRECT_VALUE
;
1820 if ( rProp
.Attributes
& beans::PropertyAttribute::REMOVABLE
)
1822 // Add Additional Core Property.
1825 xTarget
->addProperty( rProp
.Name
,
1829 catch ( beans::PropertyExistException
const & )
1832 catch ( beans::IllegalTypeException
const & )
1835 catch ( lang::IllegalArgumentException
const & )
1841 // Set target values.
1842 xTarget
->setPropertyValues( aValues
, xEnv
);
1846 // 3) Commit (insert) child.
1849 xTarget
->insert( xSource
->getInputStream(), rInfo
.NameClash
, xEnv
);
1852 // 4) Transfer (copy) children of source.
1855 if ( xSource
->isFolder() )
1857 uno::Reference
< container::XEnumeration
> xIter
1858 = xSource
->getIterator();
1861 while ( xIter
->hasMoreElements() )
1865 uno::Reference
< container::XNamed
> xNamed
;
1866 xIter
->nextElement() >>= xNamed
;
1870 OSL_FAIL( "Content::transfer - Got no XNamed!" );
1874 OUString aName
= xNamed
->getName();
1876 if ( aName
.isEmpty() )
1878 OSL_FAIL( "Content::transfer - Empty name!" );
1882 OUString aChildId
= xId
->getContentIdentifier();
1883 if ( ( aChildId
.lastIndexOf( '/' ) + 1 )
1884 != aChildId
.getLength() )
1887 aChildId
+= ::ucb_impl::urihelper::encodeSegment( aName
);
1889 ucb::TransferInfo aInfo
;
1890 aInfo
.MoveData
= false;
1891 aInfo
.NewTitle
.clear();
1892 aInfo
.SourceURL
= aChildId
;
1893 aInfo
.NameClash
= rInfo
.NameClash
;
1895 // Transfer child to target.
1896 xTarget
->transfer( aInfo
, xEnv
);
1898 catch ( container::NoSuchElementException
const & )
1901 catch ( lang::WrappedTargetException
const & )
1909 // 5) Destroy source ( when moving only ) .
1912 if ( rInfo
.MoveData
)
1914 xSource
->destroy( true, xEnv
);
1916 // Remove all persistent data of source and its children.
1917 if ( !xSource
->removeData() )
1919 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1921 {"Uri", uno::Any(xSource
->m_xIdentifier
->getContentIdentifier())}
1923 ucbhelper::cancelCommandExecution(
1924 ucb::IOErrorCode_CANT_WRITE
,
1927 "Cannot remove persistent data of source object!",
1932 // Remove own and all children's Additional Core Properties.
1933 xSource
->removeAdditionalPropertySet();
1938 bool Content::exchangeIdentity(
1939 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1944 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1946 uno::Reference
< ucb::XContent
> xThis
= this;
1948 // Already persistent?
1949 if ( m_eState
!= PERSISTENT
)
1951 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
1955 // Exchange own identitity.
1957 // Fail, if a content with given id already exists.
1958 PackageUri
aNewUri( xNewId
->getContentIdentifier() );
1959 if ( !hasData( aNewUri
) )
1961 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
1964 if ( exchange( xNewId
) )
1969 // Process instantiated children...
1971 ContentRefList aChildren
;
1972 queryChildren( aChildren
);
1974 for ( const auto& rChild
: aChildren
)
1976 ContentRef xChild
= rChild
;
1978 // Create new content identifier for the child...
1979 uno::Reference
< ucb::XContentIdentifier
> xOldChildId
1980 = xChild
->getIdentifier();
1981 OUString aOldChildURL
1982 = xOldChildId
->getContentIdentifier();
1983 OUString aNewChildURL
1984 = aOldChildURL
.replaceAt(
1986 aOldURL
.getLength(),
1987 xNewId
->getContentIdentifier() );
1988 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
1989 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1991 if ( !xChild
->exchangeIdentity( xNewChildId
) )
1999 OSL_FAIL( "Content::exchangeIdentity - Panic! Cannot exchange identity!" );
2004 void Content::queryChildren( ContentRefList
& rChildren
)
2006 // Obtain a list with a snapshot of all currently instantiated contents
2007 // from provider and extract the contents which are direct children
2010 ::ucbhelper::ContentRefList aAllContents
;
2011 m_xProvider
->queryExistingContents( aAllContents
);
2013 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2015 OSL_ENSURE( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ),
2016 "Content::queryChildren - Invalid URL!" );
2020 sal_Int32 nLen
= aURL
.getLength();
2022 for ( const auto& rContent
: aAllContents
)
2024 ::ucbhelper::ContentImplHelperRef xChild
= rContent
;
2026 = xChild
->getIdentifier()->getContentIdentifier();
2028 // Is aURL a prefix of aChildURL?
2029 if ( ( aChildURL
.getLength() > nLen
) &&
2030 ( aChildURL
.startsWith( aURL
) ) )
2032 if ( aChildURL
.indexOf( '/', nLen
) == -1 )
2034 // No further slashes. It's a child!
2035 rChildren
.emplace_back(
2036 static_cast< Content
* >( xChild
.get() ) );
2043 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage(
2044 const PackageUri
& rURI
)
2046 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2048 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2050 if ( !m_xPackage
.is() )
2051 m_xPackage
= m_pProvider
->createPackage( m_aUri
);
2056 return m_pProvider
->createPackage( rURI
);
2060 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage()
2062 return getPackage( m_aUri
);
2067 bool Content::hasData(
2068 ContentProvider
* pProvider
,
2069 const PackageUri
& rURI
,
2070 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2072 rxPackage
= pProvider
->createPackage( rURI
);
2073 return rxPackage
->hasByHierarchicalName( rURI
.getPath() );
2077 bool Content::hasData( const PackageUri
& rURI
)
2079 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2081 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
2082 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2084 xPackage
= getPackage();
2085 return xPackage
->hasByHierarchicalName( rURI
.getPath() );
2088 return hasData( m_pProvider
, rURI
, xPackage
);
2093 bool Content::loadData(
2094 ContentProvider
* pProvider
,
2095 const PackageUri
& rURI
,
2096 ContentProperties
& rProps
,
2097 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2099 rxPackage
= pProvider
->createPackage( rURI
);
2101 if ( rURI
.isRootFolder() )
2103 // Properties available only from package
2104 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2105 rxPackage
, uno::UNO_QUERY
);
2107 OSL_ENSURE( xPackagePropSet
.is(),
2108 "Content::loadData - "
2109 "Got no XPropertySet interface from package!" );
2111 if ( xPackagePropSet
.is() )
2113 // HasEncryptedEntries (only available at root folder)
2116 uno::Any aHasEncryptedEntries
2117 = xPackagePropSet
->getPropertyValue( "HasEncryptedEntries" );
2118 if ( !( aHasEncryptedEntries
>>= rProps
.bHasEncryptedEntries
) )
2120 OSL_FAIL( "Content::loadData - "
2121 "Got no HasEncryptedEntries value!" );
2125 catch ( beans::UnknownPropertyException
const & )
2127 OSL_FAIL( "Content::loadData - "
2128 "Got no HasEncryptedEntries value!" );
2131 catch ( lang::WrappedTargetException
const & )
2133 OSL_FAIL( "Content::loadData - "
2134 "Got no HasEncryptedEntries value!" );
2140 if ( !rxPackage
->hasByHierarchicalName( rURI
.getPath() ) )
2145 uno::Any aEntry
= rxPackage
->getByHierarchicalName( rURI
.getPath() );
2146 if ( aEntry
.hasValue() )
2148 uno::Reference
< beans::XPropertySet
> xPropSet
;
2149 aEntry
>>= xPropSet
;
2151 if ( !xPropSet
.is() )
2153 OSL_FAIL( "Content::loadData - Got no XPropertySet interface!" );
2158 rProps
.aTitle
= rURI
.getName();
2163 uno::Any aMediaType
= xPropSet
->getPropertyValue("MediaType");
2164 if ( !( aMediaType
>>= rProps
.aMediaType
) )
2166 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2170 catch ( beans::UnknownPropertyException
const & )
2172 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2175 catch ( lang::WrappedTargetException
const & )
2177 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2181 uno::Reference
< container::XEnumerationAccess
> xEnumAccess
;
2182 aEntry
>>= xEnumAccess
;
2184 // ContentType / IsFolder / IsDocument
2185 if ( xEnumAccess
.is() )
2188 rProps
.aContentType
= getContentType( rURI
.getScheme(), true );
2189 rProps
.bIsDocument
= false;
2190 rProps
.bIsFolder
= true;
2195 rProps
.aContentType
= getContentType( rURI
.getScheme(), false );
2196 rProps
.bIsDocument
= true;
2197 rProps
.bIsFolder
= false;
2200 if ( rProps
.bIsDocument
)
2202 // Size ( only available for streams )
2205 uno::Any aSize
= xPropSet
->getPropertyValue("Size");
2206 if ( !( aSize
>>= rProps
.nSize
) )
2208 OSL_FAIL( "Content::loadData - Got no Size value!" );
2212 catch ( beans::UnknownPropertyException
const & )
2214 OSL_FAIL( "Content::loadData - Got no Size value!" );
2217 catch ( lang::WrappedTargetException
const & )
2219 OSL_FAIL( "Content::loadData - Got no Size value!" );
2223 // Compressed ( only available for streams )
2226 uno::Any aCompressed
= xPropSet
->getPropertyValue("Compressed");
2227 if ( !( aCompressed
>>= rProps
.bCompressed
) )
2229 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2233 catch ( beans::UnknownPropertyException
const & )
2235 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2238 catch ( lang::WrappedTargetException
const & )
2240 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2244 // Encrypted ( only available for streams )
2247 uno::Any aEncrypted
= xPropSet
->getPropertyValue("Encrypted");
2248 if ( !( aEncrypted
>>= rProps
.bEncrypted
) )
2250 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2254 catch ( beans::UnknownPropertyException
const & )
2256 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2259 catch ( lang::WrappedTargetException
const & )
2261 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2268 catch ( container::NoSuchElementException
const & )
2270 // getByHierarchicalName
2277 void Content::renameData(
2278 const uno::Reference
< ucb::XContentIdentifier
>& xOldId
,
2279 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
2281 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2283 PackageUri
aURI( xOldId
->getContentIdentifier() );
2284 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage(
2287 if ( !xNA
->hasByHierarchicalName( aURI
.getPath() ) )
2292 uno::Any aEntry
= xNA
->getByHierarchicalName( aURI
.getPath() );
2293 uno::Reference
< container::XNamed
> xNamed
;
2298 OSL_FAIL( "Content::renameData - Got no XNamed interface!" );
2302 PackageUri
aNewURI( xNewId
->getContentIdentifier() );
2304 // No success indicator!? No return value / exceptions specified.
2305 xNamed
->setName( aNewURI
.getName() );
2307 catch ( container::NoSuchElementException
const & )
2309 // getByHierarchicalName
2314 bool Content::storeData( const uno::Reference
< io::XInputStream
>& xStream
)
2316 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2318 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2320 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2321 xNA
, uno::UNO_QUERY
);
2322 OSL_ENSURE( xPackagePropSet
.is(),
2323 "Content::storeData - "
2324 "Got no XPropertySet interface from package!" );
2326 if ( !xPackagePropSet
.is() )
2329 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2331 if ( m_aUri
.isRootFolder() )
2333 // Property available only from package and from streams (see below)
2336 xPackagePropSet
->setPropertyValue(
2338 uno::makeAny( m_aProps
.aEncryptionKey
) );
2339 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2341 catch ( beans::UnknownPropertyException
const & )
2345 catch ( beans::PropertyVetoException
const & )
2349 catch ( lang::IllegalArgumentException
const & )
2353 catch ( lang::WrappedTargetException
const & )
2360 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2367 // Create new resource...
2368 uno::Reference
< lang::XSingleServiceFactory
> xFac(
2369 xNA
, uno::UNO_QUERY
);
2372 OSL_FAIL( "Content::storeData - "
2373 "Got no XSingleServiceFactory interface!" );
2377 uno::Sequence
< uno::Any
> aArgs( 1 );
2378 aArgs
[ 0 ] <<= isFolder();
2380 uno::Reference
< uno::XInterface
> xNew
2381 = xFac
->createInstanceWithArguments( aArgs
);
2385 OSL_FAIL( "Content::storeData - createInstance failed!" );
2389 PackageUri
aParentUri( getParentURL() );
2391 = xNA
->getByHierarchicalName( aParentUri
.getPath() );
2392 uno::Reference
< container::XNameContainer
> xParentContainer
;
2393 aEntry
>>= xParentContainer
;
2395 if ( !xParentContainer
.is() )
2397 OSL_FAIL( "Content::storeData - "
2398 "Got no XNameContainer interface!" );
2402 xParentContainer
->insertByName( m_aProps
.aTitle
,
2403 uno::makeAny( xNew
) );
2405 catch ( lang::IllegalArgumentException
const & )
2408 OSL_FAIL( "Content::storeData - insertByName failed!" );
2411 catch ( uno::RuntimeException
const & )
2415 catch ( container::ElementExistException
const & )
2418 OSL_FAIL( "Content::storeData - insertByName failed!" );
2421 catch ( lang::WrappedTargetException
const & )
2424 OSL_FAIL( "Content::storeData - insertByName failed!" );
2427 catch ( container::NoSuchElementException
const & )
2429 // getByHierarchicalName
2430 OSL_FAIL( "Content::storeData - getByHierarchicalName failed!" );
2433 catch ( uno::Exception
const & )
2435 // createInstanceWithArguments
2436 OSL_FAIL( "Content::storeData - Error!" );
2441 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2446 uno::Reference
< beans::XPropertySet
> xPropSet
;
2447 xNA
->getByHierarchicalName( m_aUri
.getPath() ) >>= xPropSet
;
2449 if ( !xPropSet
.is() )
2451 OSL_FAIL( "Content::storeData - Got no XPropertySet interface!" );
2456 // Store property values...
2459 if ( m_nModifiedProps
& MEDIATYPE_MODIFIED
)
2461 xPropSet
->setPropertyValue(
2463 uno::makeAny( m_aProps
.aMediaType
) );
2464 m_nModifiedProps
&= ~MEDIATYPE_MODIFIED
;
2467 if ( m_nModifiedProps
& COMPRESSED_MODIFIED
)
2470 xPropSet
->setPropertyValue(
2472 uno::makeAny( m_aProps
.bCompressed
) );
2474 m_nModifiedProps
&= ~COMPRESSED_MODIFIED
;
2477 if ( m_nModifiedProps
& ENCRYPTED_MODIFIED
)
2480 xPropSet
->setPropertyValue(
2482 uno::makeAny( m_aProps
.bEncrypted
) );
2484 m_nModifiedProps
&= ~ENCRYPTED_MODIFIED
;
2487 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2490 xPropSet
->setPropertyValue(
2492 uno::makeAny( m_aProps
.aEncryptionKey
) );
2494 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2498 // Store data stream...
2501 if ( xStream
.is() && !isFolder() )
2503 uno::Reference
< io::XActiveDataSink
> xSink(
2504 xPropSet
, uno::UNO_QUERY
);
2508 OSL_FAIL( "Content::storeData - "
2509 "Got no XActiveDataSink interface!" );
2513 xSink
->setInputStream( xStream
);
2518 catch ( container::NoSuchElementException
const & )
2520 // getByHierarchicalName
2522 catch ( beans::UnknownPropertyException
const & )
2526 catch ( beans::PropertyVetoException
const & )
2530 catch ( lang::IllegalArgumentException
const & )
2534 catch ( lang::WrappedTargetException
const & )
2539 OSL_FAIL( "Content::storeData - Error!" );
2544 bool Content::removeData()
2546 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2548 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2550 PackageUri
aParentUri( getParentURL() );
2551 if ( !xNA
->hasByHierarchicalName( aParentUri
.getPath() ) )
2556 uno::Any aEntry
= xNA
->getByHierarchicalName( aParentUri
.getPath() );
2557 uno::Reference
< container::XNameContainer
> xContainer
;
2558 aEntry
>>= xContainer
;
2560 if ( !xContainer
.is() )
2562 OSL_FAIL( "Content::removeData - "
2563 "Got no XNameContainer interface!" );
2567 xContainer
->removeByName( m_aUri
.getName() );
2570 catch ( container::NoSuchElementException
const & )
2572 // getByHierarchicalName, removeByName
2574 catch ( lang::WrappedTargetException
const & )
2579 OSL_FAIL( "Content::removeData - Error!" );
2584 bool Content::flushData()
2586 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2588 // Note: XChangesBatch is only implemented by the package itself, not
2589 // by the single entries. Maybe this has to change...
2591 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2593 uno::Reference
< util::XChangesBatch
> xBatch( xNA
, uno::UNO_QUERY
);
2596 OSL_FAIL( "Content::flushData - Got no XChangesBatch interface!" );
2602 xBatch
->commitChanges();
2605 catch ( lang::WrappedTargetException
const & )
2609 OSL_FAIL( "Content::flushData - Error!" );
2614 uno::Reference
< io::XInputStream
> Content::getInputStream()
2616 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2618 uno::Reference
< io::XInputStream
> xStream
;
2619 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2621 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2626 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2627 uno::Reference
< io::XActiveDataSink
> xSink
;
2632 OSL_FAIL( "Content::getInputStream - "
2633 "Got no XActiveDataSink interface!" );
2637 xStream
= xSink
->getInputStream();
2639 OSL_ENSURE( xStream
.is(),
2640 "Content::getInputStream - Got no stream!" );
2642 catch ( container::NoSuchElementException
const & )
2644 // getByHierarchicalName
2651 uno::Reference
< container::XEnumeration
> Content::getIterator()
2653 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2655 uno::Reference
< container::XEnumeration
> xIter
;
2656 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2658 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2663 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2664 uno::Reference
< container::XEnumerationAccess
> xIterFac
;
2665 aEntry
>>= xIterFac
;
2667 if ( !xIterFac
.is() )
2669 OSL_FAIL( "Content::getIterator - "
2670 "Got no XEnumerationAccess interface!" );
2674 xIter
= xIterFac
->createEnumeration();
2676 OSL_ENSURE( xIter
.is(),
2677 "Content::getIterator - Got no iterator!" );
2679 catch ( container::NoSuchElementException
const & )
2681 // getByHierarchicalName
2687 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */