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 rtl::Reference
<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 rtl::Reference
<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 std::u16string_view aScheme
, bool bFolder
)
224 return ( OUString::Concat("application/")
227 ? OUStringLiteral(u
"-folder")
228 : OUStringLiteral(u
"-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
);
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
);
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 m_xIdentifier
->getContentIdentifier() );
943 uno::Sequence
< uno::Any
> Content::setPropertyValues(
944 const uno::Sequence
< beans::PropertyValue
>& rValues
,
945 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
947 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
949 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
950 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
951 sal_Int32 nChanged
= 0;
953 beans::PropertyChangeEvent aEvent
;
954 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
955 aEvent
.Further
= false;
956 // aEvent.PropertyName =
957 aEvent
.PropertyHandle
= -1;
961 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
962 sal_Int32 nCount
= rValues
.getLength();
964 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
965 bool bTriedToGetAdditionalPropSet
= false;
966 bool bExchange
= false;
969 sal_Int32 nTitlePos
= -1;
971 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
973 const beans::PropertyValue
& rValue
= pValues
[ n
];
975 if ( rValue
.Name
== "ContentType" )
977 // Read-only property!
978 aRet
[ n
] <<= lang::IllegalAccessException(
979 "Property is read-only!",
980 static_cast< cppu::OWeakObject
* >( this ) );
982 else if ( rValue
.Name
== "IsDocument" )
984 // Read-only property!
985 aRet
[ n
] <<= lang::IllegalAccessException(
986 "Property is read-only!",
987 static_cast< cppu::OWeakObject
* >( this ) );
989 else if ( rValue
.Name
== "IsFolder" )
991 // Read-only property!
992 aRet
[ n
] <<= lang::IllegalAccessException(
993 "Property is read-only!",
994 static_cast< cppu::OWeakObject
* >( this ) );
996 else if ( rValue
.Name
== "CreatableContentsInfo" )
998 // Read-only property!
999 aRet
[ n
] <<= lang::IllegalAccessException(
1000 "Property is read-only!",
1001 static_cast< cppu::OWeakObject
* >( this ) );
1003 else if ( rValue
.Name
== "Title" )
1005 if ( m_aUri
.isRootFolder() )
1007 // Read-only property!
1008 aRet
[ n
] <<= lang::IllegalAccessException(
1009 "Property is read-only!",
1010 static_cast< cppu::OWeakObject
* >( this ) );
1015 if ( rValue
.Value
>>= aNewValue
)
1018 if ( !aNewValue
.isEmpty() )
1020 if ( aNewValue
!= m_aProps
.aTitle
)
1022 // modified title -> modified URL -> exchange !
1023 if ( m_eState
== PERSISTENT
)
1026 // new value will be set later...
1027 aNewTitle
= aNewValue
;
1029 // remember position within sequence of values
1030 // (for error handling).
1037 lang::IllegalArgumentException(
1038 "Empty title not allowed!",
1039 static_cast< cppu::OWeakObject
* >( this ),
1046 beans::IllegalTypeException(
1047 "Property value has wrong type!",
1048 static_cast< cppu::OWeakObject
* >( this ) );
1052 else if ( rValue
.Name
== "MediaType" )
1055 if ( rValue
.Value
>>= aNewValue
)
1057 if ( aNewValue
!= m_aProps
.aMediaType
)
1059 aEvent
.PropertyName
= rValue
.Name
;
1060 aEvent
.OldValue
<<= m_aProps
.aMediaType
;
1061 aEvent
.NewValue
<<= aNewValue
;
1063 m_aProps
.aMediaType
= aNewValue
;
1066 m_nModifiedProps
|= MEDIATYPE_MODIFIED
;
1071 aRet
[ n
] <<= beans::IllegalTypeException(
1072 "Property value has wrong type!",
1073 static_cast< cppu::OWeakObject
* >( this ) );
1076 else if ( rValue
.Name
== "Size" )
1078 // Read-only property!
1079 aRet
[ n
] <<= lang::IllegalAccessException(
1080 "Property is read-only!",
1081 static_cast< cppu::OWeakObject
* >( this ) );
1083 else if ( rValue
.Name
== "Compressed" )
1085 // Property only available for streams.
1086 if ( m_aProps
.bIsDocument
)
1089 if ( rValue
.Value
>>= bNewValue
)
1091 if ( bNewValue
!= m_aProps
.bCompressed
)
1093 aEvent
.PropertyName
= rValue
.Name
;
1094 aEvent
.OldValue
<<= m_aProps
.bCompressed
;
1095 aEvent
.NewValue
<<= bNewValue
;
1097 m_aProps
.bCompressed
= bNewValue
;
1100 m_nModifiedProps
|= COMPRESSED_MODIFIED
;
1105 aRet
[ n
] <<= beans::IllegalTypeException(
1106 "Property value has wrong type!",
1107 static_cast< cppu::OWeakObject
* >( this ) );
1112 aRet
[ n
] <<= beans::UnknownPropertyException(
1113 "Compressed only supported by streams!",
1114 static_cast< cppu::OWeakObject
* >( this ) );
1117 else if ( rValue
.Name
== "Encrypted" )
1119 // Property only available for streams.
1120 if ( m_aProps
.bIsDocument
)
1123 if ( rValue
.Value
>>= bNewValue
)
1125 if ( bNewValue
!= m_aProps
.bEncrypted
)
1127 aEvent
.PropertyName
= rValue
.Name
;
1128 aEvent
.OldValue
<<= m_aProps
.bEncrypted
;
1129 aEvent
.NewValue
<<= bNewValue
;
1131 m_aProps
.bEncrypted
= bNewValue
;
1134 m_nModifiedProps
|= ENCRYPTED_MODIFIED
;
1139 aRet
[ n
] <<= beans::IllegalTypeException(
1140 "Property value has wrong type!",
1141 static_cast< cppu::OWeakObject
* >( this ) );
1146 aRet
[ n
] <<= beans::UnknownPropertyException(
1147 "Encrypted only supported by streams!",
1148 static_cast< cppu::OWeakObject
* >( this ) );
1151 else if ( rValue
.Name
== "HasEncryptedEntries" )
1153 // Read-only property!
1154 aRet
[ n
] <<= lang::IllegalAccessException(
1155 "Property is read-only!",
1156 static_cast< cppu::OWeakObject
* >( this ) );
1158 else if ( rValue
.Name
== "EncryptionKey" )
1160 // @@@ This is a temporary solution. In the future submitting
1161 // the key should be done using an interaction handler!
1163 // Write-Only property. Only supported by root folder and streams
1164 // (all non-root folders of a package have the same encryption key).
1165 if ( m_aUri
.isRootFolder() || m_aProps
.bIsDocument
)
1167 uno::Sequence
< sal_Int8
> aNewValue
;
1168 if ( rValue
.Value
>>= aNewValue
)
1170 if ( aNewValue
!= m_aProps
.aEncryptionKey
)
1172 aEvent
.PropertyName
= rValue
.Name
;
1173 aEvent
.OldValue
<<= m_aProps
.aEncryptionKey
;
1174 aEvent
.NewValue
<<= aNewValue
;
1176 m_aProps
.aEncryptionKey
= aNewValue
;
1179 m_nModifiedProps
|= ENCRYPTIONKEY_MODIFIED
;
1184 aRet
[ n
] <<= beans::IllegalTypeException(
1185 "Property value has wrong type!",
1186 static_cast< cppu::OWeakObject
* >( this ) );
1191 aRet
[ n
] <<= beans::UnknownPropertyException(
1192 "EncryptionKey not supported by non-root folder!",
1193 static_cast< cppu::OWeakObject
* >( this ) );
1198 // Not a Core Property! Maybe it's an Additional Core Property?!
1200 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1202 xAdditionalPropSet
= getAdditionalPropertySet( false );
1203 bTriedToGetAdditionalPropSet
= true;
1206 if ( xAdditionalPropSet
.is() )
1211 = xAdditionalPropSet
->getPropertyValue( rValue
.Name
);
1212 if ( aOldValue
!= rValue
.Value
)
1214 xAdditionalPropSet
->setPropertyValue(
1215 rValue
.Name
, rValue
.Value
);
1217 aEvent
.PropertyName
= rValue
.Name
;
1218 aEvent
.OldValue
= aOldValue
;
1219 aEvent
.NewValue
= rValue
.Value
;
1221 aChanges
.getArray()[ nChanged
] = aEvent
;
1225 catch ( beans::UnknownPropertyException
const & e
)
1229 catch ( lang::WrappedTargetException
const & e
)
1233 catch ( beans::PropertyVetoException
const & e
)
1237 catch ( lang::IllegalArgumentException
const & e
)
1244 aRet
[ n
] <<= uno::Exception(
1245 "No property set for storing the value!",
1246 static_cast< cppu::OWeakObject
* >( this ) );
1253 uno::Reference
< ucb::XContentIdentifier
> xOldId
= m_xIdentifier
;
1255 // Assemble new content identifier...
1256 OUString aNewURL
= m_aUri
.getParentUri() + "/";
1257 aNewURL
+= ::ucb_impl::urihelper::encodeSegment( aNewTitle
);
1258 uno::Reference
< ucb::XContentIdentifier
> xNewId
1259 = new ::ucbhelper::ContentIdentifier( aNewURL
);
1262 if ( exchangeIdentity( xNewId
) )
1264 // Adapt persistent data.
1265 renameData( xOldId
, xNewId
);
1267 // Adapt Additional Core Properties.
1268 renameAdditionalPropertySet( xOldId
->getContentIdentifier(),
1269 xNewId
->getContentIdentifier() );
1273 // Do not set new title!
1277 aRet
[ nTitlePos
] <<= uno::Exception(
1279 static_cast< cppu::OWeakObject
* >( this ) );
1283 if ( !aNewTitle
.isEmpty() )
1285 aEvent
.PropertyName
= "Title";
1286 aEvent
.OldValue
<<= m_aProps
.aTitle
;
1287 aEvent
.NewValue
<<= aNewTitle
;
1289 m_aProps
.aTitle
= aNewTitle
;
1291 aChanges
.getArray()[ nChanged
] = aEvent
;
1297 // Save changes, if content was already made persistent.
1298 if ( ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
) ||
1299 ( bStore
&& ( m_eState
== PERSISTENT
) ) )
1301 if ( !storeData( uno::Reference
< io::XInputStream
>() ) )
1303 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1305 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1307 ucbhelper::cancelCommandExecution(
1308 ucb::IOErrorCode_CANT_WRITE
,
1311 "Cannot store persistent data!",
1318 aChanges
.realloc( nChanged
);
1319 notifyPropertiesChange( aChanges
);
1326 uno::Any
Content::open(
1327 const ucb::OpenCommandArgument2
& rArg
,
1328 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1330 if ( rArg
.Mode
== ucb::OpenMode::ALL
||
1331 rArg
.Mode
== ucb::OpenMode::FOLDERS
||
1332 rArg
.Mode
== ucb::OpenMode::DOCUMENTS
)
1335 // open command for a folder content
1338 uno::Reference
< ucb::XDynamicResultSet
> xSet
1339 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
1340 return uno::makeAny( xSet
);
1345 // open command for a document content
1348 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1349 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
1351 // Currently(?) unsupported.
1352 ucbhelper::cancelCommandExecution(
1353 uno::makeAny( ucb::UnsupportedOpenModeException(
1355 static_cast< cppu::OWeakObject
* >( this ),
1356 sal_Int16( rArg
.Mode
) ) ),
1361 uno::Reference
< io::XOutputStream
> xOut( rArg
.Sink
, uno::UNO_QUERY
);
1364 // PUSH: write data into xOut
1366 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1369 // No interaction if we are not persistent!
1370 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1372 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1374 ucbhelper::cancelCommandExecution(
1375 ucb::IOErrorCode_CANT_READ
,
1377 m_eState
== PERSISTENT
1379 : uno::Reference
< ucb::XCommandEnvironment
>(),
1380 "Got no data stream!",
1387 uno::Sequence
< sal_Int8
> aBuffer
;
1390 sal_Int32 nRead
= xIn
->readSomeBytes( aBuffer
, 65536 );
1393 aBuffer
.realloc( nRead
);
1394 xOut
->writeBytes( aBuffer
);
1397 xOut
->closeOutput();
1399 catch ( io::NotConnectedException
const & )
1401 // closeOutput, readSomeBytes, writeBytes
1403 catch ( io::BufferSizeExceededException
const & )
1405 // closeOutput, readSomeBytes, writeBytes
1407 catch ( io::IOException
const & )
1409 // closeOutput, readSomeBytes, writeBytes
1414 uno::Reference
< io::XActiveDataSink
> xDataSink(
1415 rArg
.Sink
, uno::UNO_QUERY
);
1416 if ( xDataSink
.is() )
1418 // PULL: wait for client read
1420 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1423 // No interaction if we are not persistent!
1424 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1426 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1428 ucbhelper::cancelCommandExecution(
1429 ucb::IOErrorCode_CANT_READ
,
1431 m_eState
== PERSISTENT
1434 ucb::XCommandEnvironment
>(),
1435 "Got no data stream!",
1441 xDataSink
->setInputStream( xIn
);
1445 // Note: aOpenCommand.Sink may contain an XStream
1446 // implementation. Support for this type of
1447 // sink is optional...
1448 ucbhelper::cancelCommandExecution(
1450 ucb::UnsupportedDataSinkException(
1452 static_cast< cppu::OWeakObject
* >( this ),
1464 void Content::insert(
1465 const uno::Reference
< io::XInputStream
>& xStream
,
1466 sal_Int32 nNameClashResolve
,
1467 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1469 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1471 // Check, if all required properties were set.
1476 if ( m_aProps
.aTitle
.isEmpty() )
1477 m_aProps
.aTitle
= m_aUri
.getName();
1481 // Required: rArg.Data
1483 if ( !xStream
.is() )
1485 ucbhelper::cancelCommandExecution(
1486 uno::makeAny( ucb::MissingInputStreamException(
1488 static_cast< cppu::OWeakObject
* >( this ) ) ),
1495 if ( m_aProps
.aTitle
.isEmpty() )
1496 m_aProps
.aTitle
= m_aUri
.getName();
1499 OUString aNewURL
= m_aUri
.getParentUri();
1500 if (1 + aNewURL
.lastIndexOf('/') != aNewURL
.getLength())
1502 aNewURL
+= ::ucb_impl::urihelper::encodeSegment( m_aProps
.aTitle
);
1503 PackageUri
aNewUri( aNewURL
);
1505 // Handle possible name clash...
1506 switch ( nNameClashResolve
)
1509 case ucb::NameClash::ERROR
:
1510 if ( hasData( aNewUri
) )
1512 ucbhelper::cancelCommandExecution(
1513 uno::makeAny( ucb::NameClashException(
1515 static_cast< cppu::OWeakObject
* >( this ),
1516 task::InteractionClassification_ERROR
,
1517 m_aProps
.aTitle
) ),
1523 // replace (possibly) existing object.
1524 case ucb::NameClash::OVERWRITE
:
1527 // "invent" a new valid title.
1528 case ucb::NameClash::RENAME
:
1529 if ( hasData( aNewUri
) )
1535 OUString aNew
= aNewUri
.getUri() + "_";
1536 aNew
+= OUString::number( ++nTry
);
1537 aNewUri
.setUri( aNew
);
1539 while ( hasData( aNewUri
) && ( nTry
< 1000 ) );
1543 ucbhelper::cancelCommandExecution(
1545 ucb::UnsupportedNameClashException(
1546 "Unable to resolve name clash!",
1547 static_cast< cppu::OWeakObject
* >( this ),
1548 nNameClashResolve
) ),
1554 m_aProps
.aTitle
+= "_";
1555 m_aProps
.aTitle
+= OUString::number( nTry
);
1560 case ucb::NameClash::KEEP
: // deprecated
1561 case ucb::NameClash::ASK
:
1563 if ( hasData( aNewUri
) )
1565 ucbhelper::cancelCommandExecution(
1567 ucb::UnsupportedNameClashException(
1569 static_cast< cppu::OWeakObject
* >( this ),
1570 nNameClashResolve
) ),
1577 // Identifier changed?
1578 bool bNewId
= ( m_aUri
.getUri() != aNewUri
.getUri() );
1582 m_xIdentifier
= new ::ucbhelper::ContentIdentifier( aNewURL
);
1586 if ( !storeData( xStream
) )
1588 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1590 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1592 ucbhelper::cancelCommandExecution(
1593 ucb::IOErrorCode_CANT_WRITE
,
1596 "Cannot store persistent data!",
1601 m_eState
= PERSISTENT
;
1605 // Take over correct default values from underlying packager...
1606 uno::Reference
< container::XHierarchicalNameAccess
> xXHierarchicalNameAccess
;
1607 loadData( m_pProvider
,
1610 xXHierarchicalNameAccess
);
1618 void Content::destroy(
1619 bool bDeletePhysical
,
1620 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1622 // @@@ take care about bDeletePhysical -> trashcan support
1624 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1626 uno::Reference
< ucb::XContent
> xThis
= this;
1629 if ( m_eState
!= PERSISTENT
)
1631 ucbhelper::cancelCommandExecution(
1632 uno::makeAny( ucb::UnsupportedCommandException(
1634 static_cast< cppu::OWeakObject
* >( this ) ) ),
1646 // Process instantiated children...
1648 ContentRefList aChildren
;
1649 queryChildren( aChildren
);
1651 for ( auto& rChild
: aChildren
)
1653 rChild
->destroy( bDeletePhysical
, xEnv
);
1659 void Content::transfer(
1660 const ucb::TransferInfo
& rInfo
,
1661 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1663 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1666 if ( m_eState
!= PERSISTENT
)
1668 ucbhelper::cancelCommandExecution(
1669 uno::makeAny( ucb::UnsupportedCommandException(
1671 static_cast< cppu::OWeakObject
* >( this ) ) ),
1676 // Is source a package content?
1677 if ( ( rInfo
.SourceURL
.isEmpty() ) ||
1678 ( rInfo
.SourceURL
.compareTo(
1679 m_aUri
.getUri(), PACKAGE_URL_SCHEME_LENGTH
+ 3 ) != 0 ) )
1681 ucbhelper::cancelCommandExecution(
1682 uno::makeAny( ucb::InteractiveBadTransferURLException(
1684 static_cast< cppu::OWeakObject
* >( this ) ) ),
1689 // Is source not a parent of me / not me?
1690 OUString aId
= m_aUri
.getParentUri() + "/";
1692 if ( rInfo
.SourceURL
.getLength() <= aId
.getLength() )
1694 if ( aId
.startsWith( rInfo
.SourceURL
) )
1696 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1698 {"Uri", uno::Any(rInfo
.SourceURL
)}
1700 ucbhelper::cancelCommandExecution(
1701 ucb::IOErrorCode_RECURSIVE
,
1704 "Target is equal to or is a child of source!",
1711 // 0) Obtain content object for source.
1714 uno::Reference
< ucb::XContentIdentifier
> xId
1715 = new ::ucbhelper::ContentIdentifier( rInfo
.SourceURL
);
1717 // Note: The static cast is okay here, because its sure that
1718 // m_xProvider is always the PackageContentProvider.
1719 rtl::Reference
< Content
> xSource
;
1723 xSource
= static_cast< Content
* >(
1724 m_xProvider
->queryContent( xId
).get() );
1726 catch ( ucb::IllegalIdentifierException
const & )
1731 if ( !xSource
.is() )
1733 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1735 {"Uri", uno::Any(xId
->getContentIdentifier())}
1737 ucbhelper::cancelCommandExecution(
1738 ucb::IOErrorCode_CANT_READ
,
1741 "Cannot instantiate source object!",
1747 // 1) Create new child content.
1750 OUString aType
= xSource
->isFolder()
1751 ? getContentType( m_aUri
.getScheme(), true )
1752 : getContentType( m_aUri
.getScheme(), false );
1753 ucb::ContentInfo aContentInfo
;
1754 aContentInfo
.Type
= aType
;
1755 aContentInfo
.Attributes
= 0;
1757 // Note: The static cast is okay here, because its sure that
1758 // createNewContent always creates a Content.
1759 rtl::Reference
< Content
> xTarget
1760 = static_cast< Content
* >( createNewContent( aContentInfo
).get() );
1761 if ( !xTarget
.is() )
1763 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1765 {"Folder", uno::Any(aId
)}
1767 ucbhelper::cancelCommandExecution(
1768 ucb::IOErrorCode_CANT_CREATE
,
1771 "XContentCreator::createNewContent failed!",
1777 // 2) Copy data from source content to child content.
1780 uno::Sequence
< beans::Property
> aSourceProps
1781 = xSource
->getPropertySetInfo( xEnv
)->getProperties();
1782 sal_Int32 nCount
= aSourceProps
.getLength();
1786 bool bHadTitle
= rInfo
.NewTitle
.isEmpty();
1788 // Get all source values.
1789 uno::Reference
< sdbc::XRow
> xRow
1790 = xSource
->getPropertyValues( aSourceProps
);
1792 uno::Sequence
< beans::PropertyValue
> aValues( nCount
);
1793 beans::PropertyValue
* pValues
= aValues
.getArray();
1795 const beans::Property
* pProps
= aSourceProps
.getConstArray();
1796 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1798 const beans::Property
& rProp
= pProps
[ n
];
1799 beans::PropertyValue
& rValue
= pValues
[ n
];
1801 rValue
.Name
= rProp
.Name
;
1802 rValue
.Handle
= rProp
.Handle
;
1804 if ( !bHadTitle
&& rProp
.Name
== "Title" )
1806 // Set new title instead of original.
1808 rValue
.Value
<<= rInfo
.NewTitle
;
1812 = xRow
->getObject( n
+ 1,
1814 container::XNameAccess
>() );
1816 rValue
.State
= beans::PropertyState_DIRECT_VALUE
;
1818 if ( rProp
.Attributes
& beans::PropertyAttribute::REMOVABLE
)
1820 // Add Additional Core Property.
1823 xTarget
->addProperty( rProp
.Name
,
1827 catch ( beans::PropertyExistException
const & )
1830 catch ( beans::IllegalTypeException
const & )
1833 catch ( lang::IllegalArgumentException
const & )
1839 // Set target values.
1840 xTarget
->setPropertyValues( aValues
, xEnv
);
1844 // 3) Commit (insert) child.
1847 xTarget
->insert( xSource
->getInputStream(), rInfo
.NameClash
, xEnv
);
1850 // 4) Transfer (copy) children of source.
1853 if ( xSource
->isFolder() )
1855 uno::Reference
< container::XEnumeration
> xIter
1856 = xSource
->getIterator();
1859 while ( xIter
->hasMoreElements() )
1863 uno::Reference
< container::XNamed
> xNamed
;
1864 xIter
->nextElement() >>= xNamed
;
1868 OSL_FAIL( "Content::transfer - Got no XNamed!" );
1872 OUString aName
= xNamed
->getName();
1874 if ( aName
.isEmpty() )
1876 OSL_FAIL( "Content::transfer - Empty name!" );
1880 OUString aChildId
= xId
->getContentIdentifier();
1881 if ( ( aChildId
.lastIndexOf( '/' ) + 1 )
1882 != aChildId
.getLength() )
1885 aChildId
+= ::ucb_impl::urihelper::encodeSegment( aName
);
1887 ucb::TransferInfo aInfo
;
1888 aInfo
.MoveData
= false;
1889 aInfo
.NewTitle
.clear();
1890 aInfo
.SourceURL
= aChildId
;
1891 aInfo
.NameClash
= rInfo
.NameClash
;
1893 // Transfer child to target.
1894 xTarget
->transfer( aInfo
, xEnv
);
1896 catch ( container::NoSuchElementException
const & )
1899 catch ( lang::WrappedTargetException
const & )
1907 // 5) Destroy source ( when moving only ) .
1910 if ( !rInfo
.MoveData
)
1913 xSource
->destroy( true, xEnv
);
1915 // Remove all persistent data of source and its children.
1916 if ( !xSource
->removeData() )
1918 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1920 {"Uri", uno::Any(xSource
->m_xIdentifier
->getContentIdentifier())}
1922 ucbhelper::cancelCommandExecution(
1923 ucb::IOErrorCode_CANT_WRITE
,
1926 "Cannot remove persistent data of source object!",
1931 // Remove own and all children's Additional Core Properties.
1932 xSource
->removeAdditionalPropertySet();
1936 bool Content::exchangeIdentity(
1937 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1942 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1944 uno::Reference
< ucb::XContent
> xThis
= this;
1946 // Already persistent?
1947 if ( m_eState
!= PERSISTENT
)
1949 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
1953 // Exchange own identity.
1955 // Fail, if a content with given id already exists.
1956 PackageUri
aNewUri( xNewId
->getContentIdentifier() );
1957 if ( !hasData( aNewUri
) )
1959 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
1962 if ( exchange( xNewId
) )
1967 // Process instantiated children...
1969 ContentRefList aChildren
;
1970 queryChildren( aChildren
);
1972 for ( const auto& rChild
: aChildren
)
1974 ContentRef xChild
= rChild
;
1976 // Create new content identifier for the child...
1977 uno::Reference
< ucb::XContentIdentifier
> xOldChildId
1978 = xChild
->getIdentifier();
1979 OUString aOldChildURL
1980 = xOldChildId
->getContentIdentifier();
1981 OUString aNewChildURL
1982 = aOldChildURL
.replaceAt(
1984 aOldURL
.getLength(),
1985 xNewId
->getContentIdentifier() );
1986 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
1987 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1989 if ( !xChild
->exchangeIdentity( xNewChildId
) )
1997 OSL_FAIL( "Content::exchangeIdentity - Panic! Cannot exchange identity!" );
2002 void Content::queryChildren( ContentRefList
& rChildren
)
2004 // Obtain a list with a snapshot of all currently instantiated contents
2005 // from provider and extract the contents which are direct children
2008 ::ucbhelper::ContentRefList aAllContents
;
2009 m_xProvider
->queryExistingContents( aAllContents
);
2011 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2013 OSL_ENSURE( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ),
2014 "Content::queryChildren - Invalid URL!" );
2018 sal_Int32 nLen
= aURL
.getLength();
2020 for ( const auto& rContent
: aAllContents
)
2022 ::ucbhelper::ContentImplHelperRef xChild
= rContent
;
2024 = xChild
->getIdentifier()->getContentIdentifier();
2026 // Is aURL a prefix of aChildURL?
2027 if ( ( aChildURL
.getLength() > nLen
) &&
2028 ( aChildURL
.startsWith( aURL
) ) )
2030 if ( aChildURL
.indexOf( '/', nLen
) == -1 )
2032 // No further slashes. It's a child!
2033 rChildren
.emplace_back(
2034 static_cast< Content
* >( xChild
.get() ) );
2041 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage(
2042 const PackageUri
& rURI
)
2044 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2046 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2048 if ( !m_xPackage
.is() )
2049 m_xPackage
= m_pProvider
->createPackage( m_aUri
);
2054 return m_pProvider
->createPackage( rURI
);
2058 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage()
2060 return getPackage( m_aUri
);
2065 bool Content::hasData(
2066 ContentProvider
* pProvider
,
2067 const PackageUri
& rURI
,
2068 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2070 rxPackage
= pProvider
->createPackage( rURI
);
2071 return rxPackage
->hasByHierarchicalName( rURI
.getPath() );
2075 bool Content::hasData( const PackageUri
& rURI
)
2077 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2079 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
2080 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2082 xPackage
= getPackage();
2083 return xPackage
->hasByHierarchicalName( rURI
.getPath() );
2086 return hasData( m_pProvider
, rURI
, xPackage
);
2091 bool Content::loadData(
2092 ContentProvider
* pProvider
,
2093 const PackageUri
& rURI
,
2094 ContentProperties
& rProps
,
2095 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2097 rxPackage
= pProvider
->createPackage( rURI
);
2099 if ( rURI
.isRootFolder() )
2101 // Properties available only from package
2102 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2103 rxPackage
, uno::UNO_QUERY
);
2105 OSL_ENSURE( xPackagePropSet
.is(),
2106 "Content::loadData - "
2107 "Got no XPropertySet interface from package!" );
2109 if ( xPackagePropSet
.is() )
2111 // HasEncryptedEntries (only available at root folder)
2114 uno::Any aHasEncryptedEntries
2115 = xPackagePropSet
->getPropertyValue( "HasEncryptedEntries" );
2116 if ( !( aHasEncryptedEntries
>>= rProps
.bHasEncryptedEntries
) )
2118 OSL_FAIL( "Content::loadData - "
2119 "Got no HasEncryptedEntries value!" );
2123 catch ( beans::UnknownPropertyException
const & )
2125 OSL_FAIL( "Content::loadData - "
2126 "Got no HasEncryptedEntries value!" );
2129 catch ( lang::WrappedTargetException
const & )
2131 OSL_FAIL( "Content::loadData - "
2132 "Got no HasEncryptedEntries value!" );
2138 if ( !rxPackage
->hasByHierarchicalName( rURI
.getPath() ) )
2143 uno::Any aEntry
= rxPackage
->getByHierarchicalName( rURI
.getPath() );
2144 if ( aEntry
.hasValue() )
2146 uno::Reference
< beans::XPropertySet
> xPropSet
;
2147 aEntry
>>= xPropSet
;
2149 if ( !xPropSet
.is() )
2151 OSL_FAIL( "Content::loadData - Got no XPropertySet interface!" );
2156 rProps
.aTitle
= rURI
.getName();
2161 uno::Any aMediaType
= xPropSet
->getPropertyValue("MediaType");
2162 if ( !( aMediaType
>>= rProps
.aMediaType
) )
2164 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2168 catch ( beans::UnknownPropertyException
const & )
2170 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2173 catch ( lang::WrappedTargetException
const & )
2175 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2179 uno::Reference
< container::XEnumerationAccess
> xEnumAccess
;
2180 aEntry
>>= xEnumAccess
;
2182 // ContentType / IsFolder / IsDocument
2183 if ( xEnumAccess
.is() )
2186 rProps
.aContentType
= getContentType( rURI
.getScheme(), true );
2187 rProps
.bIsDocument
= false;
2188 rProps
.bIsFolder
= true;
2193 rProps
.aContentType
= getContentType( rURI
.getScheme(), false );
2194 rProps
.bIsDocument
= true;
2195 rProps
.bIsFolder
= false;
2198 if ( rProps
.bIsDocument
)
2200 // Size ( only available for streams )
2203 uno::Any aSize
= xPropSet
->getPropertyValue("Size");
2204 if ( !( aSize
>>= rProps
.nSize
) )
2206 OSL_FAIL( "Content::loadData - Got no Size value!" );
2210 catch ( beans::UnknownPropertyException
const & )
2212 OSL_FAIL( "Content::loadData - Got no Size value!" );
2215 catch ( lang::WrappedTargetException
const & )
2217 OSL_FAIL( "Content::loadData - Got no Size value!" );
2221 // Compressed ( only available for streams )
2224 uno::Any aCompressed
= xPropSet
->getPropertyValue("Compressed");
2225 if ( !( aCompressed
>>= rProps
.bCompressed
) )
2227 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2231 catch ( beans::UnknownPropertyException
const & )
2233 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2236 catch ( lang::WrappedTargetException
const & )
2238 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2242 // Encrypted ( only available for streams )
2245 uno::Any aEncrypted
= xPropSet
->getPropertyValue("Encrypted");
2246 if ( !( aEncrypted
>>= rProps
.bEncrypted
) )
2248 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2252 catch ( beans::UnknownPropertyException
const & )
2254 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2257 catch ( lang::WrappedTargetException
const & )
2259 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2266 catch ( container::NoSuchElementException
const & )
2268 // getByHierarchicalName
2275 void Content::renameData(
2276 const uno::Reference
< ucb::XContentIdentifier
>& xOldId
,
2277 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
2279 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2281 PackageUri
aURI( xOldId
->getContentIdentifier() );
2282 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage(
2285 if ( !xNA
->hasByHierarchicalName( aURI
.getPath() ) )
2290 uno::Any aEntry
= xNA
->getByHierarchicalName( aURI
.getPath() );
2291 uno::Reference
< container::XNamed
> xNamed
;
2296 OSL_FAIL( "Content::renameData - Got no XNamed interface!" );
2300 PackageUri
aNewURI( xNewId
->getContentIdentifier() );
2302 // No success indicator!? No return value / exceptions specified.
2303 xNamed
->setName( aNewURI
.getName() );
2305 catch ( container::NoSuchElementException
const & )
2307 // getByHierarchicalName
2312 bool Content::storeData( const uno::Reference
< io::XInputStream
>& xStream
)
2314 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2316 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2318 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2319 xNA
, uno::UNO_QUERY
);
2320 OSL_ENSURE( xPackagePropSet
.is(),
2321 "Content::storeData - "
2322 "Got no XPropertySet interface from package!" );
2324 if ( !xPackagePropSet
.is() )
2327 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2329 if ( m_aUri
.isRootFolder() )
2331 // Property available only from package and from streams (see below)
2334 xPackagePropSet
->setPropertyValue(
2336 uno::makeAny( m_aProps
.aEncryptionKey
) );
2337 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2339 catch ( beans::UnknownPropertyException
const & )
2343 catch ( beans::PropertyVetoException
const & )
2347 catch ( lang::IllegalArgumentException
const & )
2351 catch ( lang::WrappedTargetException
const & )
2358 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2365 // Create new resource...
2366 uno::Reference
< lang::XSingleServiceFactory
> xFac(
2367 xNA
, uno::UNO_QUERY
);
2370 OSL_FAIL( "Content::storeData - "
2371 "Got no XSingleServiceFactory interface!" );
2375 uno::Sequence
< uno::Any
> aArgs( 1 );
2376 aArgs
[ 0 ] <<= isFolder();
2378 uno::Reference
< uno::XInterface
> xNew
2379 = xFac
->createInstanceWithArguments( aArgs
);
2383 OSL_FAIL( "Content::storeData - createInstance failed!" );
2387 PackageUri
aParentUri( getParentURL() );
2389 = xNA
->getByHierarchicalName( aParentUri
.getPath() );
2390 uno::Reference
< container::XNameContainer
> xParentContainer
;
2391 aEntry
>>= xParentContainer
;
2393 if ( !xParentContainer
.is() )
2395 OSL_FAIL( "Content::storeData - "
2396 "Got no XNameContainer interface!" );
2400 xParentContainer
->insertByName( m_aProps
.aTitle
,
2401 uno::makeAny( xNew
) );
2403 catch ( lang::IllegalArgumentException
const & )
2406 OSL_FAIL( "Content::storeData - insertByName failed!" );
2409 catch ( uno::RuntimeException
const & )
2413 catch ( container::ElementExistException
const & )
2416 OSL_FAIL( "Content::storeData - insertByName failed!" );
2419 catch ( lang::WrappedTargetException
const & )
2422 OSL_FAIL( "Content::storeData - insertByName failed!" );
2425 catch ( container::NoSuchElementException
const & )
2427 // getByHierarchicalName
2428 OSL_FAIL( "Content::storeData - getByHierarchicalName failed!" );
2431 catch ( uno::Exception
const & )
2433 // createInstanceWithArguments
2434 OSL_FAIL( "Content::storeData - Error!" );
2439 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2444 uno::Reference
< beans::XPropertySet
> xPropSet
;
2445 xNA
->getByHierarchicalName( m_aUri
.getPath() ) >>= xPropSet
;
2447 if ( !xPropSet
.is() )
2449 OSL_FAIL( "Content::storeData - Got no XPropertySet interface!" );
2454 // Store property values...
2457 if ( m_nModifiedProps
& MEDIATYPE_MODIFIED
)
2459 xPropSet
->setPropertyValue(
2461 uno::makeAny( m_aProps
.aMediaType
) );
2462 m_nModifiedProps
&= ~MEDIATYPE_MODIFIED
;
2465 if ( m_nModifiedProps
& COMPRESSED_MODIFIED
)
2468 xPropSet
->setPropertyValue(
2470 uno::makeAny( m_aProps
.bCompressed
) );
2472 m_nModifiedProps
&= ~COMPRESSED_MODIFIED
;
2475 if ( m_nModifiedProps
& ENCRYPTED_MODIFIED
)
2478 xPropSet
->setPropertyValue(
2480 uno::makeAny( m_aProps
.bEncrypted
) );
2482 m_nModifiedProps
&= ~ENCRYPTED_MODIFIED
;
2485 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2488 xPropSet
->setPropertyValue(
2490 uno::makeAny( m_aProps
.aEncryptionKey
) );
2492 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2496 // Store data stream...
2499 if ( xStream
.is() && !isFolder() )
2501 uno::Reference
< io::XActiveDataSink
> xSink(
2502 xPropSet
, uno::UNO_QUERY
);
2506 OSL_FAIL( "Content::storeData - "
2507 "Got no XActiveDataSink interface!" );
2511 xSink
->setInputStream( xStream
);
2516 catch ( container::NoSuchElementException
const & )
2518 // getByHierarchicalName
2520 catch ( beans::UnknownPropertyException
const & )
2524 catch ( beans::PropertyVetoException
const & )
2528 catch ( lang::IllegalArgumentException
const & )
2532 catch ( lang::WrappedTargetException
const & )
2537 OSL_FAIL( "Content::storeData - Error!" );
2542 bool Content::removeData()
2544 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2546 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2548 PackageUri
aParentUri( getParentURL() );
2549 if ( !xNA
->hasByHierarchicalName( aParentUri
.getPath() ) )
2554 uno::Any aEntry
= xNA
->getByHierarchicalName( aParentUri
.getPath() );
2555 uno::Reference
< container::XNameContainer
> xContainer
;
2556 aEntry
>>= xContainer
;
2558 if ( !xContainer
.is() )
2560 OSL_FAIL( "Content::removeData - "
2561 "Got no XNameContainer interface!" );
2565 xContainer
->removeByName( m_aUri
.getName() );
2568 catch ( container::NoSuchElementException
const & )
2570 // getByHierarchicalName, removeByName
2572 catch ( lang::WrappedTargetException
const & )
2577 OSL_FAIL( "Content::removeData - Error!" );
2582 bool Content::flushData()
2584 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2586 // Note: XChangesBatch is only implemented by the package itself, not
2587 // by the single entries. Maybe this has to change...
2589 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2591 uno::Reference
< util::XChangesBatch
> xBatch( xNA
, uno::UNO_QUERY
);
2594 OSL_FAIL( "Content::flushData - Got no XChangesBatch interface!" );
2600 xBatch
->commitChanges();
2603 catch ( lang::WrappedTargetException
const & )
2607 OSL_FAIL( "Content::flushData - Error!" );
2612 uno::Reference
< io::XInputStream
> Content::getInputStream()
2614 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2616 uno::Reference
< io::XInputStream
> xStream
;
2617 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2619 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2624 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2625 uno::Reference
< io::XActiveDataSink
> xSink
;
2630 OSL_FAIL( "Content::getInputStream - "
2631 "Got no XActiveDataSink interface!" );
2635 xStream
= xSink
->getInputStream();
2637 OSL_ENSURE( xStream
.is(),
2638 "Content::getInputStream - Got no stream!" );
2640 catch ( container::NoSuchElementException
const & )
2642 // getByHierarchicalName
2649 uno::Reference
< container::XEnumeration
> Content::getIterator()
2651 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2653 uno::Reference
< container::XEnumeration
> xIter
;
2654 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2656 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2661 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2662 uno::Reference
< container::XEnumerationAccess
> xIterFac
;
2663 aEntry
>>= xIterFac
;
2665 if ( !xIterFac
.is() )
2667 OSL_FAIL( "Content::getIterator - "
2668 "Got no XEnumerationAccess interface!" );
2672 xIter
= xIterFac
->createEnumeration();
2674 OSL_ENSURE( xIter
.is(),
2675 "Content::getIterator - Got no iterator!" );
2677 catch ( container::NoSuchElementException
const & )
2679 // getByHierarchicalName
2685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */