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 <sal/config.h>
27 #include <string_view>
29 #include <osl/diagnose.h>
31 #include <rtl/ustring.hxx>
32 #include <com/sun/star/beans/IllegalTypeException.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/beans/PropertyExistException.hpp>
35 #include <com/sun/star/beans/PropertyState.hpp>
36 #include <com/sun/star/container/XEnumerationAccess.hpp>
37 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
38 #include <com/sun/star/container/XNameContainer.hpp>
39 #include <com/sun/star/container/XNamed.hpp>
40 #include <com/sun/star/io/BufferSizeExceededException.hpp>
41 #include <com/sun/star/io/NotConnectedException.hpp>
42 #include <com/sun/star/io/XActiveDataSink.hpp>
43 #include <com/sun/star/io/XOutputStream.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
46 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
47 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
48 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
49 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
50 #include <com/sun/star/ucb/NameClash.hpp>
51 #include <com/sun/star/ucb/NameClashException.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
56 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
57 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
58 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
59 #include <com/sun/star/ucb/XCommandInfo.hpp>
60 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
61 #include <com/sun/star/util/XChangesBatch.hpp>
62 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
63 #include <com/sun/star/uno/Any.hxx>
64 #include <com/sun/star/uno/Sequence.hxx>
65 #include <comphelper/propertysequence.hxx>
66 #include <cppuhelper/queryinterface.hxx>
67 #include <ucbhelper/contentidentifier.hxx>
68 #include <ucbhelper/propertyvalueset.hxx>
69 #include <ucbhelper/cancelcommandexecution.hxx>
70 #include <ucbhelper/macros.hxx>
72 #include "pkgcontent.hxx"
73 #include "pkgprovider.hxx"
74 #include "pkgresultset.hxx"
76 #include "../inc/urihelper.hxx"
78 using namespace com::sun::star
;
79 using namespace package_ucp
;
81 #define NONE_MODIFIED sal_uInt32( 0x00 )
82 #define MEDIATYPE_MODIFIED sal_uInt32( 0x01 )
83 #define COMPRESSED_MODIFIED sal_uInt32( 0x02 )
84 #define ENCRYPTED_MODIFIED sal_uInt32( 0x04 )
85 #define ENCRYPTIONKEY_MODIFIED sal_uInt32( 0x08 )
88 // ContentProperties Implementation.
91 ContentProperties::ContentProperties( const OUString
& rContentType
)
92 : aContentType( rContentType
),
96 bHasEncryptedEntries( false )
98 bIsFolder
= rContentType
== PACKAGE_FOLDER_CONTENT_TYPE
|| rContentType
== PACKAGE_ZIP_FOLDER_CONTENT_TYPE
;
99 bIsDocument
= !bIsFolder
;
101 OSL_ENSURE( bIsFolder
|| rContentType
== PACKAGE_STREAM_CONTENT_TYPE
|| rContentType
== PACKAGE_ZIP_STREAM_CONTENT_TYPE
,
102 "ContentProperties::ContentProperties - Unknown type!" );
106 uno::Sequence
< ucb::ContentInfo
>
107 ContentProperties::getCreatableContentsInfo( PackageUri
const & rUri
) const
111 uno::Sequence
< beans::Property
> aProps( 1 );
112 aProps
.getArray()[ 0 ] = beans::Property(
115 cppu::UnoType
<OUString
>::get(),
116 beans::PropertyAttribute::BOUND
);
118 uno::Sequence
< ucb::ContentInfo
> aSeq( 2 );
121 aSeq
.getArray()[ 0 ].Type
122 = Content::getContentType( rUri
.getScheme(), true );
123 aSeq
.getArray()[ 0 ].Attributes
124 = ucb::ContentInfoAttribute::KIND_FOLDER
;
125 aSeq
.getArray()[ 0 ].Properties
= aProps
;
128 aSeq
.getArray()[ 1 ].Type
129 = Content::getContentType( rUri
.getScheme(), false );
130 aSeq
.getArray()[ 1 ].Attributes
131 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
132 | ucb::ContentInfoAttribute::KIND_DOCUMENT
;
133 aSeq
.getArray()[ 1 ].Properties
= std::move(aProps
);
139 return uno::Sequence
< ucb::ContentInfo
>( 0 );
144 // Content Implementation.
147 // static ( "virtual" ctor )
148 rtl::Reference
<Content
> Content::create(
149 const uno::Reference
< uno::XComponentContext
>& rxContext
,
150 ContentProvider
* pProvider
,
151 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
153 OUString aURL
= Identifier
->getContentIdentifier();
154 PackageUri
aURI( aURL
);
155 ContentProperties aProps
;
156 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
158 if ( loadData( pProvider
, aURI
, aProps
, xPackage
) )
162 sal_Int32 nLastSlash
= aURL
.lastIndexOf( '/' );
163 if ( ( nLastSlash
+ 1 ) == aURL
.getLength() )
165 // Client explicitly requested a folder!
166 if ( !aProps
.bIsFolder
)
170 uno::Reference
< ucb::XContentIdentifier
> xId
171 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
172 return new Content( rxContext
, pProvider
, xId
, xPackage
, std::move(aURI
), std::move(aProps
) );
176 // resource doesn't exist
178 bool bFolder
= false;
180 // Guess type according to URI.
181 sal_Int32 nLastSlash
= aURL
.lastIndexOf( '/' );
182 if ( ( nLastSlash
+ 1 ) == aURL
.getLength() )
185 uno::Reference
< ucb::XContentIdentifier
> xId
186 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
188 ucb::ContentInfo aInfo
;
189 if ( bFolder
|| aURI
.isRootFolder() )
190 aInfo
.Type
= getContentType( aURI
.getScheme(), true );
192 aInfo
.Type
= getContentType( aURI
.getScheme(), false );
194 return new Content( rxContext
, pProvider
, xId
, xPackage
, std::move(aURI
), std::move(aInfo
) );
199 // static ( "virtual" ctor )
200 rtl::Reference
<Content
> Content::create(
201 const uno::Reference
< uno::XComponentContext
>& rxContext
,
202 ContentProvider
* pProvider
,
203 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
204 const ucb::ContentInfo
& Info
)
206 if ( Info
.Type
.isEmpty() )
209 PackageUri
aURI( Identifier
->getContentIdentifier() );
211 if ( !Info
.Type
.equalsIgnoreAsciiCase(
212 getContentType( aURI
.getScheme(), true ) ) &&
213 !Info
.Type
.equalsIgnoreAsciiCase(
214 getContentType( aURI
.getScheme(), false ) ) )
217 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
= pProvider
->createPackage( aURI
);
219 uno::Reference
< ucb::XContentIdentifier
> xId
220 = new ::ucbhelper::ContentIdentifier( aURI
.getUri() );
221 return new Content( rxContext
, pProvider
, xId
, xPackage
, std::move(aURI
), Info
);
226 OUString
Content::getContentType(
227 std::u16string_view aScheme
, bool bFolder
)
229 return ( OUString::Concat("application/")
232 ? std::u16string_view(u
"-folder")
233 : std::u16string_view(u
"-stream") ) );
238 const uno::Reference
< uno::XComponentContext
>& rxContext
,
239 ContentProvider
* pProvider
,
240 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
241 uno::Reference
< container::XHierarchicalNameAccess
> Package
,
243 ContentProperties aProps
)
244 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
245 m_aUri(std::move( aUri
)),
246 m_aProps(std::move( aProps
)),
247 m_eState( PERSISTENT
),
248 m_xPackage(std::move( Package
)),
249 m_pProvider( pProvider
),
250 m_nModifiedProps( NONE_MODIFIED
)
256 const uno::Reference
< uno::XComponentContext
>& rxContext
,
257 ContentProvider
* pProvider
,
258 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
259 uno::Reference
< container::XHierarchicalNameAccess
> Package
,
261 const ucb::ContentInfo
& Info
)
262 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
263 m_aUri(std::move( aUri
)),
264 m_aProps( Info
.Type
),
265 m_eState( TRANSIENT
),
266 m_xPackage(std::move( Package
)),
267 m_pProvider( pProvider
),
268 m_nModifiedProps( NONE_MODIFIED
)
279 // XInterface methods.
283 void SAL_CALL
Content::acquire()
286 ContentImplHelper::acquire();
291 void SAL_CALL
Content::release()
294 ContentImplHelper::release();
299 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
304 aRet
= cppu::queryInterface(
305 rType
, static_cast< ucb::XContentCreator
* >( this ) );
307 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
311 // XTypeProvider methods.
314 XTYPEPROVIDER_COMMON_IMPL( Content
);
318 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
322 static cppu::OTypeCollection
s_aFolderTypes(
323 CPPU_TYPE_REF( lang::XTypeProvider
),
324 CPPU_TYPE_REF( lang::XServiceInfo
),
325 CPPU_TYPE_REF( lang::XComponent
),
326 CPPU_TYPE_REF( ucb::XContent
),
327 CPPU_TYPE_REF( ucb::XCommandProcessor
),
328 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
329 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
330 CPPU_TYPE_REF( beans::XPropertyContainer
),
331 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
332 CPPU_TYPE_REF( container::XChild
),
333 CPPU_TYPE_REF( ucb::XContentCreator
) );
335 return s_aFolderTypes
.getTypes();
340 static cppu::OTypeCollection
s_aDocumentTypes(
341 CPPU_TYPE_REF( lang::XTypeProvider
),
342 CPPU_TYPE_REF( lang::XServiceInfo
),
343 CPPU_TYPE_REF( lang::XComponent
),
344 CPPU_TYPE_REF( ucb::XContent
),
345 CPPU_TYPE_REF( ucb::XCommandProcessor
),
346 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
347 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
348 CPPU_TYPE_REF( beans::XPropertyContainer
),
349 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
350 CPPU_TYPE_REF( container::XChild
) );
352 return s_aDocumentTypes
.getTypes();
357 // XServiceInfo methods.
361 OUString SAL_CALL
Content::getImplementationName()
363 return u
"com.sun.star.comp.ucb.PackageContent"_ustr
;
368 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
370 return { isFolder()? u
"com.sun.star.ucb.PackageFolderContent"_ustr
:u
"com.sun.star.ucb.PackageStreamContent"_ustr
} ;
378 OUString SAL_CALL
Content::getContentType()
380 return m_aProps
.aContentType
;
384 // XCommandProcessor methods.
388 uno::Any SAL_CALL
Content::execute(
389 const ucb::Command
& aCommand
,
390 sal_Int32
/*CommandId*/,
391 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
395 if ( aCommand
.Name
== "getPropertyValues" )
401 uno::Sequence
< beans::Property
> Properties
;
402 if ( !( aCommand
.Argument
>>= Properties
) )
404 ucbhelper::cancelCommandExecution(
405 uno::Any( lang::IllegalArgumentException(
406 u
"Wrong argument type!"_ustr
,
413 aRet
<<= getPropertyValues( Properties
);
415 else if ( aCommand
.Name
== "setPropertyValues" )
421 uno::Sequence
< beans::PropertyValue
> aProperties
;
422 if ( !( aCommand
.Argument
>>= aProperties
) )
424 ucbhelper::cancelCommandExecution(
425 uno::Any( lang::IllegalArgumentException(
426 u
"Wrong argument type!"_ustr
,
433 if ( !aProperties
.hasElements() )
435 ucbhelper::cancelCommandExecution(
436 uno::Any( lang::IllegalArgumentException(
437 u
"No properties!"_ustr
,
444 aRet
<<= setPropertyValues( aProperties
, Environment
);
446 else if ( aCommand
.Name
== "getPropertySetInfo" )
449 // getPropertySetInfo
452 // Note: Implemented by base class.
453 aRet
<<= getPropertySetInfo( Environment
);
455 else if ( aCommand
.Name
== "getCommandInfo" )
461 // Note: Implemented by base class.
462 aRet
<<= getCommandInfo( Environment
);
464 else if ( aCommand
.Name
== "open" )
470 ucb::OpenCommandArgument2 aOpenCommand
;
471 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
473 ucbhelper::cancelCommandExecution(
474 uno::Any( lang::IllegalArgumentException(
475 u
"Wrong argument type!"_ustr
,
482 aRet
= open( aOpenCommand
, Environment
);
484 else if ( !m_aUri
.isRootFolder() && aCommand
.Name
== "insert" )
490 ucb::InsertCommandArgument aArg
;
491 if ( !( aCommand
.Argument
>>= aArg
) )
493 ucbhelper::cancelCommandExecution(
494 uno::Any( lang::IllegalArgumentException(
495 u
"Wrong argument type!"_ustr
,
502 sal_Int32 nNameClash
= aArg
.ReplaceExisting
503 ? ucb::NameClash::OVERWRITE
504 : ucb::NameClash::ERROR
;
505 insert( aArg
.Data
, nNameClash
, Environment
);
507 else if ( !m_aUri
.isRootFolder() && aCommand
.Name
== "delete" )
513 bool bDeletePhysical
= false;
514 aCommand
.Argument
>>= bDeletePhysical
;
515 destroy( bDeletePhysical
, Environment
);
517 // Remove own and all children's persistent data.
520 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
522 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
524 ucbhelper::cancelCommandExecution(
525 ucb::IOErrorCode_CANT_WRITE
,
528 u
"Cannot remove persistent data!"_ustr
,
533 // Remove own and all children's Additional Core Properties.
534 removeAdditionalPropertySet();
536 else if ( aCommand
.Name
== "transfer" )
540 // ( Not available at stream objects )
543 ucb::TransferInfo aInfo
;
544 if ( !( aCommand
.Argument
>>= aInfo
) )
546 ucbhelper::cancelCommandExecution(
547 uno::Any( lang::IllegalArgumentException(
548 u
"Wrong argument type!"_ustr
,
555 transfer( aInfo
, Environment
);
557 else if ( aCommand
.Name
== "createNewContent" && isFolder() )
561 // ( Not available at stream objects )
564 ucb::ContentInfo aInfo
;
565 if ( !( aCommand
.Argument
>>= aInfo
) )
567 OSL_FAIL( "Wrong argument type!" );
568 ucbhelper::cancelCommandExecution(
569 uno::Any( lang::IllegalArgumentException(
570 u
"Wrong argument type!"_ustr
,
577 aRet
<<= createNewContent( aInfo
);
579 else if ( aCommand
.Name
== "flush" )
583 // ( Not available at stream objects )
588 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
590 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
592 ucbhelper::cancelCommandExecution(
593 ucb::IOErrorCode_CANT_WRITE
,
596 u
"Cannot write file to disk!"_ustr
,
604 // Unsupported command
607 ucbhelper::cancelCommandExecution(
608 uno::Any( ucb::UnsupportedCommandException(
620 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
622 // @@@ Implement logic to abort running commands, if this makes
623 // sense for your content.
627 // XContentCreator methods.
631 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
632 Content::queryCreatableContentsInfo()
634 return m_aProps
.getCreatableContentsInfo( m_aUri
);
639 uno::Reference
< ucb::XContent
> SAL_CALL
640 Content::createNewContent( const ucb::ContentInfo
& Info
)
644 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
646 if ( Info
.Type
.isEmpty() )
647 return uno::Reference
< ucb::XContent
>();
649 if ( !Info
.Type
.equalsIgnoreAsciiCase(
650 getContentType( m_aUri
.getScheme(), true ) ) &&
651 !Info
.Type
.equalsIgnoreAsciiCase(
652 getContentType( m_aUri
.getScheme(), false ) ) )
653 return uno::Reference
< ucb::XContent
>();
655 OUString aURL
= m_aUri
.getUri() + "/";
657 if ( Info
.Type
.equalsIgnoreAsciiCase(
658 getContentType( m_aUri
.getScheme(), true ) ) )
659 aURL
+= "New_Folder";
661 aURL
+= "New_Stream";
663 uno::Reference
< ucb::XContentIdentifier
> xId(
664 new ::ucbhelper::ContentIdentifier( aURL
) );
666 return create( m_xContext
, m_pProvider
, xId
, Info
);
670 OSL_FAIL( "createNewContent called on non-folder object!" );
671 return uno::Reference
< ucb::XContent
>();
676 // Non-interface methods.
680 OUString
Content::getParentURL()
682 return m_aUri
.getParentUri();
687 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
688 const uno::Reference
< uno::XComponentContext
>& rxContext
,
689 const uno::Sequence
< beans::Property
>& rProperties
,
690 ContentProvider
* pProvider
,
691 const OUString
& rContentId
)
693 ContentProperties aData
;
694 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
695 if ( loadData( pProvider
, PackageUri( rContentId
), aData
, xPackage
) )
697 return getPropertyValues( rxContext
,
701 ::ucbhelper::ContentProviderImplHelper
>(
707 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
708 = new ::ucbhelper::PropertyValueSet( rxContext
);
710 for ( const beans::Property
& rProp
: rProperties
)
711 xRow
->appendVoid( rProp
);
719 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
720 const uno::Reference
< uno::XComponentContext
>& rxContext
,
721 const uno::Sequence
< beans::Property
>& rProperties
,
722 const ContentProperties
& rData
,
723 const rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
>&
725 const OUString
& rContentId
)
727 // Note: Empty sequence means "get values of all supported properties".
729 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
730 = new ::ucbhelper::PropertyValueSet( rxContext
);
732 if ( rProperties
.hasElements() )
734 uno::Reference
< beans::XPropertySet
> xAdditionalPropSet
;
735 bool bTriedToGetAdditionalPropSet
= false;
737 for ( const beans::Property
& rProp
: rProperties
)
739 // Process Core properties.
741 if ( rProp
.Name
== "ContentType" )
743 xRow
->appendString ( rProp
, rData
.aContentType
);
745 else if ( rProp
.Name
== "Title" )
747 xRow
->appendString ( rProp
, rData
.aTitle
);
749 else if ( rProp
.Name
== "IsDocument" )
751 xRow
->appendBoolean( rProp
, rData
.bIsDocument
);
753 else if ( rProp
.Name
== "IsFolder" )
755 xRow
->appendBoolean( rProp
, rData
.bIsFolder
);
757 else if ( rProp
.Name
== "CreatableContentsInfo" )
761 rData
.getCreatableContentsInfo(
762 PackageUri( rContentId
) ) ) );
764 else if ( rProp
.Name
== "MediaType" )
766 xRow
->appendString ( rProp
, rData
.aMediaType
);
768 else if ( rProp
.Name
== "Size" )
770 // Property only available for streams.
771 if ( rData
.bIsDocument
)
772 xRow
->appendLong( rProp
, rData
.nSize
);
774 xRow
->appendVoid( rProp
);
776 else if ( rProp
.Name
== "Compressed" )
778 // Property only available for streams.
779 if ( rData
.bIsDocument
)
780 xRow
->appendBoolean( rProp
, rData
.bCompressed
);
782 xRow
->appendVoid( rProp
);
784 else if ( rProp
.Name
== "Encrypted" )
786 // Property only available for streams.
787 if ( rData
.bIsDocument
)
788 xRow
->appendBoolean( rProp
, rData
.bEncrypted
);
790 xRow
->appendVoid( rProp
);
792 else if ( rProp
.Name
== "HasEncryptedEntries" )
794 // Property only available for root folder.
795 PackageUri
aURI( rContentId
);
796 if ( aURI
.isRootFolder() )
797 xRow
->appendBoolean( rProp
, rData
.bHasEncryptedEntries
);
799 xRow
->appendVoid( rProp
);
803 // Not a Core Property! Maybe it's an Additional Core Property?!
805 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
808 rProvider
->getAdditionalPropertySet( rContentId
,
810 bTriedToGetAdditionalPropSet
= true;
813 if ( xAdditionalPropSet
.is() )
815 if ( !xRow
->appendPropertySetValue(
819 // Append empty entry.
820 xRow
->appendVoid( rProp
);
825 // Append empty entry.
826 xRow
->appendVoid( rProp
);
833 // Append all Core Properties.
838 cppu::UnoType
<OUString
>::get(),
839 beans::PropertyAttribute::BOUND
840 | beans::PropertyAttribute::READONLY
),
841 rData
.aContentType
);
846 cppu::UnoType
<OUString
>::get(),
847 beans::PropertyAttribute::BOUND
),
853 cppu::UnoType
<bool>::get(),
854 beans::PropertyAttribute::BOUND
855 | beans::PropertyAttribute::READONLY
),
861 cppu::UnoType
<bool>::get(),
862 beans::PropertyAttribute::BOUND
863 | beans::PropertyAttribute::READONLY
),
867 u
"CreatableContentsInfo"_ustr
,
869 cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
870 beans::PropertyAttribute::BOUND
871 | beans::PropertyAttribute::READONLY
),
873 rData
.getCreatableContentsInfo( PackageUri( rContentId
) ) ) );
878 cppu::UnoType
<OUString
>::get(),
879 beans::PropertyAttribute::BOUND
),
882 // Properties only available for streams.
883 if ( rData
.bIsDocument
)
889 cppu::UnoType
<sal_Int64
>::get(),
890 beans::PropertyAttribute::BOUND
891 | beans::PropertyAttribute::READONLY
),
898 cppu::UnoType
<bool>::get(),
899 beans::PropertyAttribute::BOUND
),
906 cppu::UnoType
<bool>::get(),
907 beans::PropertyAttribute::BOUND
),
911 // Properties only available for root folder.
912 PackageUri
aURI( rContentId
);
913 if ( aURI
.isRootFolder() )
917 u
"HasEncryptedEntries"_ustr
,
919 cppu::UnoType
<bool>::get(),
920 beans::PropertyAttribute::BOUND
921 | beans::PropertyAttribute::READONLY
),
922 rData
.bHasEncryptedEntries
);
925 // Append all Additional Core Properties.
927 uno::Reference
< beans::XPropertySet
> xSet
=
928 rProvider
->getAdditionalPropertySet( rContentId
, false );
929 xRow
->appendPropertySet( xSet
);
936 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
937 const uno::Sequence
< beans::Property
>& rProperties
)
939 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
940 return getPropertyValues( m_xContext
,
944 m_xIdentifier
->getContentIdentifier() );
948 uno::Sequence
< uno::Any
> Content::setPropertyValues(
949 const uno::Sequence
< beans::PropertyValue
>& rValues
,
950 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
952 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
954 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
955 auto aRetRange
= asNonConstRange(aRet
);
956 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
957 sal_Int32 nChanged
= 0;
959 beans::PropertyChangeEvent aEvent
;
960 aEvent
.Source
= getXWeak();
961 aEvent
.Further
= false;
962 // aEvent.PropertyName =
963 aEvent
.PropertyHandle
= -1;
967 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
968 sal_Int32 nCount
= rValues
.getLength();
970 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
971 bool bTriedToGetAdditionalPropSet
= false;
972 bool bExchange
= false;
975 sal_Int32 nTitlePos
= -1;
977 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
979 const beans::PropertyValue
& rValue
= pValues
[ n
];
981 if ( rValue
.Name
== "ContentType" )
983 // Read-only property!
984 aRetRange
[ n
] <<= lang::IllegalAccessException(
985 u
"Property is read-only!"_ustr
,
988 else if ( rValue
.Name
== "IsDocument" )
990 // Read-only property!
991 aRetRange
[ n
] <<= lang::IllegalAccessException(
992 u
"Property is read-only!"_ustr
,
995 else if ( rValue
.Name
== "IsFolder" )
997 // Read-only property!
998 aRetRange
[ n
] <<= lang::IllegalAccessException(
999 u
"Property is read-only!"_ustr
,
1002 else if ( rValue
.Name
== "CreatableContentsInfo" )
1004 // Read-only property!
1005 aRetRange
[ n
] <<= lang::IllegalAccessException(
1006 u
"Property is read-only!"_ustr
,
1009 else if ( rValue
.Name
== "Title" )
1011 if ( m_aUri
.isRootFolder() )
1013 // Read-only property!
1014 aRetRange
[ n
] <<= lang::IllegalAccessException(
1015 u
"Property is read-only!"_ustr
,
1021 if ( rValue
.Value
>>= aNewValue
)
1024 if ( !aNewValue
.isEmpty() )
1026 if ( aNewValue
!= m_aProps
.aTitle
)
1028 // modified title -> modified URL -> exchange !
1029 if ( m_eState
== PERSISTENT
)
1032 // new value will be set later...
1033 aNewTitle
= aNewValue
;
1035 // remember position within sequence of values
1036 // (for error handling).
1043 lang::IllegalArgumentException(
1044 u
"Empty title not allowed!"_ustr
,
1052 beans::IllegalTypeException(
1053 u
"Property value has wrong type!"_ustr
,
1058 else if ( rValue
.Name
== "MediaType" )
1061 if ( rValue
.Value
>>= aNewValue
)
1063 if ( aNewValue
!= m_aProps
.aMediaType
)
1065 aEvent
.PropertyName
= rValue
.Name
;
1066 aEvent
.OldValue
<<= m_aProps
.aMediaType
;
1067 aEvent
.NewValue
<<= aNewValue
;
1069 m_aProps
.aMediaType
= aNewValue
;
1072 m_nModifiedProps
|= MEDIATYPE_MODIFIED
;
1077 aRetRange
[ n
] <<= beans::IllegalTypeException(
1078 u
"Property value has wrong type!"_ustr
,
1082 else if ( rValue
.Name
== "Size" )
1084 // Read-only property!
1085 aRetRange
[ n
] <<= lang::IllegalAccessException(
1086 u
"Property is read-only!"_ustr
,
1089 else if ( rValue
.Name
== "Compressed" )
1091 // Property only available for streams.
1092 if ( m_aProps
.bIsDocument
)
1095 if ( rValue
.Value
>>= bNewValue
)
1097 if ( bNewValue
!= m_aProps
.bCompressed
)
1099 aEvent
.PropertyName
= rValue
.Name
;
1100 aEvent
.OldValue
<<= m_aProps
.bCompressed
;
1101 aEvent
.NewValue
<<= bNewValue
;
1103 m_aProps
.bCompressed
= bNewValue
;
1106 m_nModifiedProps
|= COMPRESSED_MODIFIED
;
1111 aRetRange
[ n
] <<= beans::IllegalTypeException(
1112 u
"Property value has wrong type!"_ustr
,
1118 aRetRange
[ n
] <<= beans::UnknownPropertyException(
1119 u
"Compressed only supported by streams!"_ustr
,
1123 else if ( rValue
.Name
== "Encrypted" )
1125 // Property only available for streams.
1126 if ( m_aProps
.bIsDocument
)
1129 if ( rValue
.Value
>>= bNewValue
)
1131 if ( bNewValue
!= m_aProps
.bEncrypted
)
1133 aEvent
.PropertyName
= rValue
.Name
;
1134 aEvent
.OldValue
<<= m_aProps
.bEncrypted
;
1135 aEvent
.NewValue
<<= bNewValue
;
1137 m_aProps
.bEncrypted
= bNewValue
;
1140 m_nModifiedProps
|= ENCRYPTED_MODIFIED
;
1145 aRetRange
[ n
] <<= beans::IllegalTypeException(
1146 u
"Property value has wrong type!"_ustr
,
1152 aRetRange
[ n
] <<= beans::UnknownPropertyException(
1153 u
"Encrypted only supported by streams!"_ustr
,
1157 else if ( rValue
.Name
== "HasEncryptedEntries" )
1159 // Read-only property!
1160 aRetRange
[ n
] <<= lang::IllegalAccessException(
1161 u
"Property is read-only!"_ustr
,
1164 else if ( rValue
.Name
== "EncryptionKey" )
1166 // @@@ This is a temporary solution. In the future submitting
1167 // the key should be done using an interaction handler!
1169 // Write-Only property. Only supported by root folder and streams
1170 // (all non-root folders of a package have the same encryption key).
1171 if ( m_aUri
.isRootFolder() || m_aProps
.bIsDocument
)
1173 uno::Sequence
< sal_Int8
> aNewValue
;
1174 if ( rValue
.Value
>>= aNewValue
)
1176 if ( aNewValue
!= m_aProps
.aEncryptionKey
)
1178 aEvent
.PropertyName
= rValue
.Name
;
1179 aEvent
.OldValue
<<= m_aProps
.aEncryptionKey
;
1180 aEvent
.NewValue
<<= aNewValue
;
1182 m_aProps
.aEncryptionKey
= std::move(aNewValue
);
1185 m_nModifiedProps
|= ENCRYPTIONKEY_MODIFIED
;
1190 aRetRange
[ n
] <<= beans::IllegalTypeException(
1191 u
"Property value has wrong type!"_ustr
,
1197 aRetRange
[ n
] <<= beans::UnknownPropertyException(
1198 u
"EncryptionKey not supported by non-root folder!"_ustr
,
1204 // Not a Core Property! Maybe it's an Additional Core Property?!
1206 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1208 xAdditionalPropSet
= getAdditionalPropertySet( false );
1209 bTriedToGetAdditionalPropSet
= true;
1212 if ( xAdditionalPropSet
.is() )
1217 = xAdditionalPropSet
->getPropertyValue( rValue
.Name
);
1218 if ( aOldValue
!= rValue
.Value
)
1220 xAdditionalPropSet
->setPropertyValue(
1221 rValue
.Name
, rValue
.Value
);
1223 aEvent
.PropertyName
= rValue
.Name
;
1224 aEvent
.OldValue
= std::move(aOldValue
);
1225 aEvent
.NewValue
= rValue
.Value
;
1227 aChanges
.getArray()[ nChanged
] = aEvent
;
1231 catch ( beans::UnknownPropertyException
const & e
)
1233 aRetRange
[ n
] <<= e
;
1235 catch ( lang::WrappedTargetException
const & e
)
1237 aRetRange
[ n
] <<= e
;
1239 catch ( beans::PropertyVetoException
const & e
)
1241 aRetRange
[ n
] <<= e
;
1243 catch ( lang::IllegalArgumentException
const & e
)
1245 aRetRange
[ n
] <<= e
;
1250 aRetRange
[ n
] <<= uno::Exception(
1251 u
"No property set for storing the value!"_ustr
,
1259 uno::Reference
< ucb::XContentIdentifier
> xOldId
= m_xIdentifier
;
1261 // Assemble new content identifier...
1262 OUString aNewURL
= m_aUri
.getParentUri() + "/" +
1263 ::ucb_impl::urihelper::encodeSegment( aNewTitle
);
1264 uno::Reference
< ucb::XContentIdentifier
> xNewId
1265 = new ::ucbhelper::ContentIdentifier( aNewURL
);
1268 if ( exchangeIdentity( xNewId
) )
1270 // Adapt persistent data.
1271 renameData( xOldId
, xNewId
);
1273 // Adapt Additional Core Properties.
1274 renameAdditionalPropertySet( xOldId
->getContentIdentifier(),
1275 xNewId
->getContentIdentifier() );
1279 // Do not set new title!
1283 aRetRange
[ nTitlePos
] <<= uno::Exception(
1284 u
"Exchange failed!"_ustr
,
1289 if ( !aNewTitle
.isEmpty() )
1291 aEvent
.PropertyName
= "Title";
1292 aEvent
.OldValue
<<= m_aProps
.aTitle
;
1293 aEvent
.NewValue
<<= aNewTitle
;
1295 m_aProps
.aTitle
= aNewTitle
;
1297 aChanges
.getArray()[ nChanged
] = std::move(aEvent
);
1303 // Save changes, if content was already made persistent.
1304 if ( ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
) ||
1305 ( bStore
&& ( m_eState
== PERSISTENT
) ) )
1307 if ( !storeData( uno::Reference
< io::XInputStream
>() ) )
1309 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1311 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1313 ucbhelper::cancelCommandExecution(
1314 ucb::IOErrorCode_CANT_WRITE
,
1317 u
"Cannot store persistent data!"_ustr
,
1324 aChanges
.realloc( nChanged
);
1325 notifyPropertiesChange( aChanges
);
1332 uno::Any
Content::open(
1333 const ucb::OpenCommandArgument2
& rArg
,
1334 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1336 if ( rArg
.Mode
== ucb::OpenMode::ALL
||
1337 rArg
.Mode
== ucb::OpenMode::FOLDERS
||
1338 rArg
.Mode
== ucb::OpenMode::DOCUMENTS
)
1341 // open command for a folder content
1344 uno::Reference
< ucb::XDynamicResultSet
> xSet
1345 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
1346 return uno::Any( xSet
);
1351 // open command for a document content
1354 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1355 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
1357 // Currently(?) unsupported.
1358 ucbhelper::cancelCommandExecution(
1359 uno::Any( ucb::UnsupportedOpenModeException(
1362 sal_Int16( rArg
.Mode
) ) ),
1367 uno::Reference
< io::XOutputStream
> xOut( rArg
.Sink
, uno::UNO_QUERY
);
1370 // PUSH: write data into xOut
1372 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1375 // No interaction if we are not persistent!
1376 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1378 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1380 ucbhelper::cancelCommandExecution(
1381 ucb::IOErrorCode_CANT_READ
,
1383 m_eState
== PERSISTENT
1385 : uno::Reference
< ucb::XCommandEnvironment
>(),
1386 u
"Got no data stream!"_ustr
,
1393 uno::Sequence
< sal_Int8
> aBuffer
;
1396 sal_Int32 nRead
= xIn
->readSomeBytes( aBuffer
, 65536 );
1399 aBuffer
.realloc( nRead
);
1400 xOut
->writeBytes( aBuffer
);
1403 xOut
->closeOutput();
1405 catch ( io::NotConnectedException
const & )
1407 // closeOutput, readSomeBytes, writeBytes
1409 catch ( io::BufferSizeExceededException
const & )
1411 // closeOutput, readSomeBytes, writeBytes
1413 catch ( io::IOException
const & )
1415 // closeOutput, readSomeBytes, writeBytes
1420 uno::Reference
< io::XActiveDataSink
> xDataSink(
1421 rArg
.Sink
, uno::UNO_QUERY
);
1422 if ( xDataSink
.is() )
1424 // PULL: wait for client read
1426 uno::Reference
< io::XInputStream
> xIn
= getInputStream();
1429 // No interaction if we are not persistent!
1430 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1432 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1434 ucbhelper::cancelCommandExecution(
1435 ucb::IOErrorCode_CANT_READ
,
1437 m_eState
== PERSISTENT
1440 ucb::XCommandEnvironment
>(),
1441 u
"Got no data stream!"_ustr
,
1447 xDataSink
->setInputStream( xIn
);
1451 // Note: aOpenCommand.Sink may contain an XStream
1452 // implementation. Support for this type of
1453 // sink is optional...
1454 ucbhelper::cancelCommandExecution(
1456 ucb::UnsupportedDataSinkException(
1470 void Content::insert(
1471 const uno::Reference
< io::XInputStream
>& xStream
,
1472 sal_Int32 nNameClashResolve
,
1473 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1475 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1477 // Check, if all required properties were set.
1482 if ( m_aProps
.aTitle
.isEmpty() )
1483 m_aProps
.aTitle
= m_aUri
.getName();
1487 // Required: rArg.Data
1489 if ( !xStream
.is() )
1491 ucbhelper::cancelCommandExecution(
1492 uno::Any( ucb::MissingInputStreamException(
1501 if ( m_aProps
.aTitle
.isEmpty() )
1502 m_aProps
.aTitle
= m_aUri
.getName();
1505 OUString aNewURL
= m_aUri
.getParentUri();
1506 if (1 + aNewURL
.lastIndexOf('/') != aNewURL
.getLength())
1508 aNewURL
+= ::ucb_impl::urihelper::encodeSegment( m_aProps
.aTitle
);
1509 PackageUri
aNewUri( aNewURL
);
1511 // Handle possible name clash...
1512 switch ( nNameClashResolve
)
1515 case ucb::NameClash::ERROR
:
1516 if ( hasData( aNewUri
) )
1518 ucbhelper::cancelCommandExecution(
1519 uno::Any( ucb::NameClashException(
1522 task::InteractionClassification_ERROR
,
1523 m_aProps
.aTitle
) ),
1529 // replace (possibly) existing object.
1530 case ucb::NameClash::OVERWRITE
:
1533 // "invent" a new valid title.
1534 case ucb::NameClash::RENAME
:
1535 if ( hasData( aNewUri
) )
1541 OUString aNew
= aNewUri
.getUri() + "_" + OUString::number( ++nTry
);
1542 aNewUri
.setUri( aNew
);
1544 while ( hasData( aNewUri
) && ( nTry
< 1000 ) );
1548 ucbhelper::cancelCommandExecution(
1550 ucb::UnsupportedNameClashException(
1551 u
"Unable to resolve name clash!"_ustr
,
1553 nNameClashResolve
) ),
1559 m_aProps
.aTitle
+= "_";
1560 m_aProps
.aTitle
+= OUString::number( nTry
);
1565 case ucb::NameClash::KEEP
: // deprecated
1566 case ucb::NameClash::ASK
:
1568 if ( hasData( aNewUri
) )
1570 ucbhelper::cancelCommandExecution(
1572 ucb::UnsupportedNameClashException(
1575 nNameClashResolve
) ),
1582 // Identifier changed?
1583 bool bNewId
= ( m_aUri
.getUri() != aNewUri
.getUri() );
1587 m_xIdentifier
= new ::ucbhelper::ContentIdentifier( aNewURL
);
1588 m_aUri
= std::move(aNewUri
);
1591 if ( !storeData( xStream
) )
1593 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1595 {"Uri", uno::Any(m_xIdentifier
->getContentIdentifier())}
1597 ucbhelper::cancelCommandExecution(
1598 ucb::IOErrorCode_CANT_WRITE
,
1601 u
"Cannot store persistent data!"_ustr
,
1606 m_eState
= PERSISTENT
;
1610 // Take over correct default values from underlying packager...
1611 uno::Reference
< container::XHierarchicalNameAccess
> xXHierarchicalNameAccess
;
1612 loadData( m_pProvider
,
1615 xXHierarchicalNameAccess
);
1623 void Content::destroy(
1624 bool bDeletePhysical
,
1625 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1627 // @@@ take care about bDeletePhysical -> trashcan support
1629 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1631 uno::Reference
< ucb::XContent
> xThis
= this;
1634 if ( m_eState
!= PERSISTENT
)
1636 ucbhelper::cancelCommandExecution(
1637 uno::Any( ucb::UnsupportedCommandException(
1638 u
"Not persistent!"_ustr
,
1651 // Process instantiated children...
1653 ContentRefList aChildren
;
1654 queryChildren( aChildren
);
1656 for ( auto& rChild
: aChildren
)
1658 rChild
->destroy( bDeletePhysical
, xEnv
);
1664 void Content::transfer(
1665 const ucb::TransferInfo
& rInfo
,
1666 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1668 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1671 if ( m_eState
!= PERSISTENT
)
1673 ucbhelper::cancelCommandExecution(
1674 uno::Any( ucb::UnsupportedCommandException(
1675 u
"Not persistent!"_ustr
,
1681 // Is source a package content?
1682 if ( ( rInfo
.SourceURL
.isEmpty() ) ||
1683 ( rInfo
.SourceURL
.compareTo(
1684 m_aUri
.getUri(), PACKAGE_URL_SCHEME_LENGTH
+ 3 ) != 0 ) )
1686 ucbhelper::cancelCommandExecution(
1687 uno::Any( ucb::InteractiveBadTransferURLException(
1694 // Is source not a parent of me / not me?
1695 OUString aId
= m_aUri
.getParentUri() + "/";
1697 if ( rInfo
.SourceURL
.getLength() <= aId
.getLength() )
1699 if ( aId
.startsWith( rInfo
.SourceURL
) )
1701 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1703 {"Uri", uno::Any(rInfo
.SourceURL
)}
1705 ucbhelper::cancelCommandExecution(
1706 ucb::IOErrorCode_RECURSIVE
,
1709 u
"Target is equal to or is a child of source!"_ustr
,
1716 // 0) Obtain content object for source.
1719 uno::Reference
< ucb::XContentIdentifier
> xId
1720 = new ::ucbhelper::ContentIdentifier( rInfo
.SourceURL
);
1722 // Note: The static cast is okay here, because its sure that
1723 // m_xProvider is always the PackageContentProvider.
1724 rtl::Reference
< Content
> xSource
;
1728 xSource
= static_cast< Content
* >(
1729 m_xProvider
->queryContent( xId
).get() );
1731 catch ( ucb::IllegalIdentifierException
const & )
1736 if ( !xSource
.is() )
1738 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1740 {"Uri", uno::Any(xId
->getContentIdentifier())}
1742 ucbhelper::cancelCommandExecution(
1743 ucb::IOErrorCode_CANT_READ
,
1746 u
"Cannot instantiate source object!"_ustr
,
1752 // 1) Create new child content.
1755 ucb::ContentInfo aContentInfo
;
1756 aContentInfo
.Type
= xSource
->isFolder()
1757 ? getContentType( m_aUri
.getScheme(), true )
1758 : getContentType( m_aUri
.getScheme(), false );
1759 aContentInfo
.Attributes
= 0;
1761 // Note: The static cast is okay here, because its sure that
1762 // createNewContent always creates a Content.
1763 rtl::Reference
< Content
> xTarget
1764 = static_cast< Content
* >( createNewContent( aContentInfo
).get() );
1765 if ( !xTarget
.is() )
1767 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1769 {"Folder", uno::Any(aId
)}
1771 ucbhelper::cancelCommandExecution(
1772 ucb::IOErrorCode_CANT_CREATE
,
1775 u
"XContentCreator::createNewContent failed!"_ustr
,
1781 // 2) Copy data from source content to child content.
1784 uno::Sequence
< beans::Property
> aSourceProps
1785 = xSource
->getPropertySetInfo( xEnv
)->getProperties();
1786 sal_Int32 nCount
= aSourceProps
.getLength();
1790 bool bHadTitle
= rInfo
.NewTitle
.isEmpty();
1792 // Get all source values.
1793 uno::Reference
< sdbc::XRow
> xRow
1794 = xSource
->getPropertyValues( aSourceProps
);
1796 uno::Sequence
< beans::PropertyValue
> aValues( nCount
);
1797 beans::PropertyValue
* pValues
= aValues
.getArray();
1799 const beans::Property
* pProps
= aSourceProps
.getConstArray();
1800 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1802 const beans::Property
& rProp
= pProps
[ n
];
1803 beans::PropertyValue
& rValue
= pValues
[ n
];
1805 rValue
.Name
= rProp
.Name
;
1806 rValue
.Handle
= rProp
.Handle
;
1808 if ( !bHadTitle
&& rProp
.Name
== "Title" )
1810 // Set new title instead of original.
1812 rValue
.Value
<<= rInfo
.NewTitle
;
1816 = xRow
->getObject( n
+ 1,
1818 container::XNameAccess
>() );
1820 rValue
.State
= beans::PropertyState_DIRECT_VALUE
;
1822 if ( rProp
.Attributes
& beans::PropertyAttribute::REMOVABLE
)
1824 // Add Additional Core Property.
1827 xTarget
->addProperty( rProp
.Name
,
1831 catch ( beans::PropertyExistException
const & )
1834 catch ( beans::IllegalTypeException
const & )
1837 catch ( lang::IllegalArgumentException
const & )
1843 // Set target values.
1844 xTarget
->setPropertyValues( aValues
, xEnv
);
1848 // 3) Commit (insert) child.
1851 xTarget
->insert( xSource
->getInputStream(), rInfo
.NameClash
, xEnv
);
1854 // 4) Transfer (copy) children of source.
1857 if ( xSource
->isFolder() )
1859 uno::Reference
< container::XEnumeration
> xIter
1860 = xSource
->getIterator();
1863 while ( xIter
->hasMoreElements() )
1867 uno::Reference
< container::XNamed
> xNamed
;
1868 xIter
->nextElement() >>= xNamed
;
1872 OSL_FAIL( "Content::transfer - Got no XNamed!" );
1876 OUString aName
= xNamed
->getName();
1878 if ( aName
.isEmpty() )
1880 OSL_FAIL( "Content::transfer - Empty name!" );
1884 OUString aChildId
= xId
->getContentIdentifier();
1885 if ( ( aChildId
.lastIndexOf( '/' ) + 1 )
1886 != aChildId
.getLength() )
1889 aChildId
+= ::ucb_impl::urihelper::encodeSegment( aName
);
1891 ucb::TransferInfo aInfo
;
1892 aInfo
.MoveData
= false;
1893 aInfo
.NewTitle
.clear();
1894 aInfo
.SourceURL
= aChildId
;
1895 aInfo
.NameClash
= rInfo
.NameClash
;
1897 // Transfer child to target.
1898 xTarget
->transfer( aInfo
, xEnv
);
1900 catch ( container::NoSuchElementException
const & )
1903 catch ( lang::WrappedTargetException
const & )
1911 // 5) Destroy source ( when moving only ) .
1914 if ( !rInfo
.MoveData
)
1917 xSource
->destroy( true, xEnv
);
1919 // Remove all persistent data of source and its children.
1920 if ( !xSource
->removeData() )
1922 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1924 {"Uri", uno::Any(xSource
->m_xIdentifier
->getContentIdentifier())}
1926 ucbhelper::cancelCommandExecution(
1927 ucb::IOErrorCode_CANT_WRITE
,
1930 u
"Cannot remove persistent data of source object!"_ustr
,
1935 // Remove own and all children's Additional Core Properties.
1936 xSource
->removeAdditionalPropertySet();
1940 bool Content::exchangeIdentity(
1941 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
1946 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
1948 uno::Reference
< ucb::XContent
> xThis
= this;
1950 // Already persistent?
1951 if ( m_eState
!= PERSISTENT
)
1953 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
1957 // Exchange own identity.
1959 // Fail, if a content with given id already exists.
1960 PackageUri
aNewUri( xNewId
->getContentIdentifier() );
1961 if ( !hasData( aNewUri
) )
1963 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
1966 if ( exchange( xNewId
) )
1968 m_aUri
= std::move(aNewUri
);
1971 // Process instantiated children...
1973 ContentRefList aChildren
;
1974 queryChildren( aChildren
);
1976 for ( const auto& rChild
: aChildren
)
1978 ContentRef xChild
= rChild
;
1980 // Create new content identifier for the child...
1981 uno::Reference
< ucb::XContentIdentifier
> xOldChildId
1982 = xChild
->getIdentifier();
1983 OUString aOldChildURL
1984 = xOldChildId
->getContentIdentifier();
1985 OUString aNewChildURL
1986 = aOldChildURL
.replaceAt(
1988 aOldURL
.getLength(),
1989 xNewId
->getContentIdentifier() );
1990 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
1991 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
1993 if ( !xChild
->exchangeIdentity( xNewChildId
) )
2001 OSL_FAIL( "Content::exchangeIdentity - Panic! Cannot exchange identity!" );
2006 void Content::queryChildren( ContentRefList
& rChildren
)
2008 // Obtain a list with a snapshot of all currently instantiated contents
2009 // from provider and extract the contents which are direct children
2012 ::ucbhelper::ContentRefList aAllContents
;
2013 m_xProvider
->queryExistingContents( aAllContents
);
2015 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2017 OSL_ENSURE( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ),
2018 "Content::queryChildren - Invalid URL!" );
2022 sal_Int32 nLen
= aURL
.getLength();
2024 for ( const auto& rContent
: aAllContents
)
2026 ::ucbhelper::ContentImplHelperRef xChild
= rContent
;
2028 = xChild
->getIdentifier()->getContentIdentifier();
2030 // Is aURL a prefix of aChildURL?
2031 if ( ( aChildURL
.getLength() > nLen
) &&
2032 ( aChildURL
.startsWith( aURL
) ) )
2034 if ( aChildURL
.indexOf( '/', nLen
) == -1 )
2036 // No further slashes. It's a child!
2037 rChildren
.emplace_back(
2038 static_cast< Content
* >( xChild
.get() ) );
2045 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage(
2046 const PackageUri
& rURI
)
2048 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2050 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2052 if ( !m_xPackage
.is() )
2053 m_xPackage
= m_pProvider
->createPackage( m_aUri
);
2058 return m_pProvider
->createPackage( rURI
);
2062 uno::Reference
< container::XHierarchicalNameAccess
> Content::getPackage()
2064 return getPackage( m_aUri
);
2069 bool Content::hasData(
2070 ContentProvider
* pProvider
,
2071 const PackageUri
& rURI
,
2072 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2074 rxPackage
= pProvider
->createPackage( rURI
);
2075 return rxPackage
->hasByHierarchicalName( rURI
.getPath() );
2079 bool Content::hasData( const PackageUri
& rURI
)
2081 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2083 uno::Reference
< container::XHierarchicalNameAccess
> xPackage
;
2084 if ( rURI
.getPackage() == m_aUri
.getPackage() )
2086 xPackage
= getPackage();
2087 return xPackage
->hasByHierarchicalName( rURI
.getPath() );
2090 return hasData( m_pProvider
, rURI
, xPackage
);
2095 bool Content::loadData(
2096 ContentProvider
* pProvider
,
2097 const PackageUri
& rURI
,
2098 ContentProperties
& rProps
,
2099 uno::Reference
< container::XHierarchicalNameAccess
> & rxPackage
)
2101 rxPackage
= pProvider
->createPackage( rURI
);
2103 if ( rURI
.isRootFolder() )
2105 // Properties available only from package
2106 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2107 rxPackage
, uno::UNO_QUERY
);
2109 OSL_ENSURE( xPackagePropSet
.is(),
2110 "Content::loadData - "
2111 "Got no XPropertySet interface from package!" );
2113 if ( xPackagePropSet
.is() )
2115 // HasEncryptedEntries (only available at root folder)
2118 uno::Any aHasEncryptedEntries
2119 = xPackagePropSet
->getPropertyValue( u
"HasEncryptedEntries"_ustr
);
2120 if ( !( aHasEncryptedEntries
>>= rProps
.bHasEncryptedEntries
) )
2122 OSL_FAIL( "Content::loadData - "
2123 "Got no HasEncryptedEntries value!" );
2127 catch ( beans::UnknownPropertyException
const & )
2129 OSL_FAIL( "Content::loadData - "
2130 "Got no HasEncryptedEntries value!" );
2133 catch ( lang::WrappedTargetException
const & )
2135 OSL_FAIL( "Content::loadData - "
2136 "Got no HasEncryptedEntries value!" );
2142 if ( !rxPackage
->hasByHierarchicalName( rURI
.getPath() ) )
2147 uno::Any aEntry
= rxPackage
->getByHierarchicalName( rURI
.getPath() );
2148 if ( aEntry
.hasValue() )
2150 uno::Reference
< beans::XPropertySet
> xPropSet
;
2151 aEntry
>>= xPropSet
;
2153 if ( !xPropSet
.is() )
2155 OSL_FAIL( "Content::loadData - Got no XPropertySet interface!" );
2160 rProps
.aTitle
= rURI
.getName();
2165 uno::Any aMediaType
= xPropSet
->getPropertyValue(u
"MediaType"_ustr
);
2166 if ( !( aMediaType
>>= rProps
.aMediaType
) )
2168 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2172 catch ( beans::UnknownPropertyException
const & )
2174 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2177 catch ( lang::WrappedTargetException
const & )
2179 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2183 uno::Reference
< container::XEnumerationAccess
> xEnumAccess
;
2184 aEntry
>>= xEnumAccess
;
2186 // ContentType / IsFolder / IsDocument
2187 if ( xEnumAccess
.is() )
2190 rProps
.aContentType
= getContentType( rURI
.getScheme(), true );
2191 rProps
.bIsDocument
= false;
2192 rProps
.bIsFolder
= true;
2197 rProps
.aContentType
= getContentType( rURI
.getScheme(), false );
2198 rProps
.bIsDocument
= true;
2199 rProps
.bIsFolder
= false;
2202 if ( rProps
.bIsDocument
)
2204 // Size ( only available for streams )
2207 uno::Any aSize
= xPropSet
->getPropertyValue(u
"Size"_ustr
);
2208 if ( !( aSize
>>= rProps
.nSize
) )
2210 OSL_FAIL( "Content::loadData - Got no Size value!" );
2214 catch ( beans::UnknownPropertyException
const & )
2216 OSL_FAIL( "Content::loadData - Got no Size value!" );
2219 catch ( lang::WrappedTargetException
const & )
2221 OSL_FAIL( "Content::loadData - Got no Size value!" );
2225 // Compressed ( only available for streams )
2228 uno::Any aCompressed
= xPropSet
->getPropertyValue(u
"Compressed"_ustr
);
2229 if ( !( aCompressed
>>= rProps
.bCompressed
) )
2231 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2235 catch ( beans::UnknownPropertyException
const & )
2237 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2240 catch ( lang::WrappedTargetException
const & )
2242 OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2246 // Encrypted ( only available for streams )
2249 uno::Any aEncrypted
= xPropSet
->getPropertyValue(u
"Encrypted"_ustr
);
2250 if ( !( aEncrypted
>>= rProps
.bEncrypted
) )
2252 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2256 catch ( beans::UnknownPropertyException
const & )
2258 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2261 catch ( lang::WrappedTargetException
const & )
2263 OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2270 catch ( container::NoSuchElementException
const & )
2272 // getByHierarchicalName
2279 void Content::renameData(
2280 const uno::Reference
< ucb::XContentIdentifier
>& xOldId
,
2281 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
2283 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2285 PackageUri
aURI( xOldId
->getContentIdentifier() );
2286 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage(
2289 if ( !xNA
->hasByHierarchicalName( aURI
.getPath() ) )
2294 uno::Any aEntry
= xNA
->getByHierarchicalName( aURI
.getPath() );
2295 uno::Reference
< container::XNamed
> xNamed
;
2300 OSL_FAIL( "Content::renameData - Got no XNamed interface!" );
2304 PackageUri
aNewURI( xNewId
->getContentIdentifier() );
2306 // No success indicator!? No return value / exceptions specified.
2307 xNamed
->setName( aNewURI
.getName() );
2309 catch ( container::NoSuchElementException
const & )
2311 // getByHierarchicalName
2316 bool Content::storeData( const uno::Reference
< io::XInputStream
>& xStream
)
2318 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2320 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2322 uno::Reference
< beans::XPropertySet
> xPackagePropSet(
2323 xNA
, uno::UNO_QUERY
);
2324 OSL_ENSURE( xPackagePropSet
.is(),
2325 "Content::storeData - "
2326 "Got no XPropertySet interface from package!" );
2328 if ( !xPackagePropSet
.is() )
2331 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2333 if ( m_aUri
.isRootFolder() )
2335 // Property available only from package and from streams (see below)
2338 xPackagePropSet
->setPropertyValue(
2339 u
"EncryptionKey"_ustr
,
2340 uno::Any( m_aProps
.aEncryptionKey
) );
2341 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2343 catch ( beans::UnknownPropertyException
const & )
2347 catch ( beans::PropertyVetoException
const & )
2351 catch ( lang::IllegalArgumentException
const & )
2355 catch ( lang::WrappedTargetException
const & )
2362 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2369 // Create new resource...
2370 uno::Reference
< lang::XSingleServiceFactory
> xFac(
2371 xNA
, uno::UNO_QUERY
);
2374 OSL_FAIL( "Content::storeData - "
2375 "Got no XSingleServiceFactory interface!" );
2379 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(isFolder()) };
2381 uno::Reference
< uno::XInterface
> xNew
2382 = xFac
->createInstanceWithArguments( aArgs
);
2386 OSL_FAIL( "Content::storeData - createInstance failed!" );
2390 PackageUri
aParentUri( getParentURL() );
2392 = xNA
->getByHierarchicalName( aParentUri
.getPath() );
2393 uno::Reference
< container::XNameContainer
> xParentContainer
;
2394 aEntry
>>= xParentContainer
;
2396 if ( !xParentContainer
.is() )
2398 OSL_FAIL( "Content::storeData - "
2399 "Got no XNameContainer interface!" );
2403 xParentContainer
->insertByName( m_aProps
.aTitle
,
2406 catch ( lang::IllegalArgumentException
const & )
2409 OSL_FAIL( "Content::storeData - insertByName failed!" );
2412 catch ( uno::RuntimeException
const & )
2416 catch ( container::ElementExistException
const & )
2419 OSL_FAIL( "Content::storeData - insertByName failed!" );
2422 catch ( lang::WrappedTargetException
const & )
2425 OSL_FAIL( "Content::storeData - insertByName failed!" );
2428 catch ( container::NoSuchElementException
const & )
2430 // getByHierarchicalName
2431 OSL_FAIL( "Content::storeData - getByHierarchicalName failed!" );
2434 catch ( uno::Exception
const & )
2436 // createInstanceWithArguments
2437 OSL_FAIL( "Content::storeData - Error!" );
2442 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2447 uno::Reference
< beans::XPropertySet
> xPropSet
;
2448 xNA
->getByHierarchicalName( m_aUri
.getPath() ) >>= xPropSet
;
2450 if ( !xPropSet
.is() )
2452 OSL_FAIL( "Content::storeData - Got no XPropertySet interface!" );
2457 // Store property values...
2460 if ( m_nModifiedProps
& MEDIATYPE_MODIFIED
)
2462 xPropSet
->setPropertyValue(
2464 uno::Any( m_aProps
.aMediaType
) );
2465 m_nModifiedProps
&= ~MEDIATYPE_MODIFIED
;
2468 if ( m_nModifiedProps
& COMPRESSED_MODIFIED
)
2471 xPropSet
->setPropertyValue(
2473 uno::Any( m_aProps
.bCompressed
) );
2475 m_nModifiedProps
&= ~COMPRESSED_MODIFIED
;
2478 if ( m_nModifiedProps
& ENCRYPTED_MODIFIED
)
2481 xPropSet
->setPropertyValue(
2483 uno::Any( m_aProps
.bEncrypted
) );
2485 m_nModifiedProps
&= ~ENCRYPTED_MODIFIED
;
2488 if ( m_nModifiedProps
& ENCRYPTIONKEY_MODIFIED
)
2491 xPropSet
->setPropertyValue(
2492 u
"EncryptionKey"_ustr
,
2493 uno::Any( m_aProps
.aEncryptionKey
) );
2495 m_nModifiedProps
&= ~ENCRYPTIONKEY_MODIFIED
;
2499 // Store data stream...
2502 if ( xStream
.is() && !isFolder() )
2504 uno::Reference
< io::XActiveDataSink
> xSink(
2505 xPropSet
, uno::UNO_QUERY
);
2509 OSL_FAIL( "Content::storeData - "
2510 "Got no XActiveDataSink interface!" );
2514 xSink
->setInputStream( xStream
);
2519 catch ( container::NoSuchElementException
const & )
2521 // getByHierarchicalName
2523 catch ( beans::UnknownPropertyException
const & )
2527 catch ( beans::PropertyVetoException
const & )
2531 catch ( lang::IllegalArgumentException
const & )
2535 catch ( lang::WrappedTargetException
const & )
2540 OSL_FAIL( "Content::storeData - Error!" );
2545 bool Content::removeData()
2547 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2549 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2551 PackageUri
aParentUri( getParentURL() );
2552 if ( !xNA
->hasByHierarchicalName( aParentUri
.getPath() ) )
2557 uno::Any aEntry
= xNA
->getByHierarchicalName( aParentUri
.getPath() );
2558 uno::Reference
< container::XNameContainer
> xContainer
;
2559 aEntry
>>= xContainer
;
2561 if ( !xContainer
.is() )
2563 OSL_FAIL( "Content::removeData - "
2564 "Got no XNameContainer interface!" );
2568 xContainer
->removeByName( m_aUri
.getName() );
2571 catch ( container::NoSuchElementException
const & )
2573 // getByHierarchicalName, removeByName
2575 catch ( lang::WrappedTargetException
const & )
2580 OSL_FAIL( "Content::removeData - Error!" );
2585 bool Content::flushData()
2587 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2589 // Note: XChangesBatch is only implemented by the package itself, not
2590 // by the single entries. Maybe this has to change...
2592 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2594 uno::Reference
< util::XChangesBatch
> xBatch( xNA
, uno::UNO_QUERY
);
2597 OSL_FAIL( "Content::flushData - Got no XChangesBatch interface!" );
2603 xBatch
->commitChanges();
2606 catch ( lang::WrappedTargetException
const & )
2610 OSL_FAIL( "Content::flushData - Error!" );
2615 uno::Reference
< io::XInputStream
> Content::getInputStream()
2617 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2619 uno::Reference
< io::XInputStream
> xStream
;
2620 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2622 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2627 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2628 uno::Reference
< io::XActiveDataSink
> xSink
;
2633 OSL_FAIL( "Content::getInputStream - "
2634 "Got no XActiveDataSink interface!" );
2638 xStream
= xSink
->getInputStream();
2640 OSL_ENSURE( xStream
.is(),
2641 "Content::getInputStream - Got no stream!" );
2643 catch ( container::NoSuchElementException
const & )
2645 // getByHierarchicalName
2652 uno::Reference
< container::XEnumeration
> Content::getIterator()
2654 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2656 uno::Reference
< container::XEnumeration
> xIter
;
2657 uno::Reference
< container::XHierarchicalNameAccess
> xNA
= getPackage();
2659 if ( !xNA
->hasByHierarchicalName( m_aUri
.getPath() ) )
2664 uno::Any aEntry
= xNA
->getByHierarchicalName( m_aUri
.getPath() );
2665 uno::Reference
< container::XEnumerationAccess
> xIterFac
;
2666 aEntry
>>= xIterFac
;
2668 if ( !xIterFac
.is() )
2670 OSL_FAIL( "Content::getIterator - "
2671 "Got no XEnumerationAccess interface!" );
2675 xIter
= xIterFac
->createEnumeration();
2677 OSL_ENSURE( xIter
.is(),
2678 "Content::getIterator - Got no iterator!" );
2680 catch ( container::NoSuchElementException
const & )
2682 // getByHierarchicalName
2688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */