1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 /**************************************************************************
22                                 TODO
23  **************************************************************************
24  *************************************************************************/
25 #include <osl/diagnose.h>
26 
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"
70 
71 #include "../inc/urihelper.hxx"
72 
73 using namespace com::sun::star;
74 using namespace package_ucp;
75 
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 )
81 
82 
83 // ContentProperties Implementation.
84 
85 
ContentProperties(const OUString & rContentType)86 ContentProperties::ContentProperties( const OUString& rContentType )
87 : aContentType( rContentType ),
88   nSize( 0 ),
89   bCompressed( true ),
90   bEncrypted( false ),
91   bHasEncryptedEntries( false )
92 {
93     bIsFolder = rContentType == PACKAGE_FOLDER_CONTENT_TYPE || rContentType == PACKAGE_ZIP_FOLDER_CONTENT_TYPE;
94     bIsDocument = !bIsFolder;
95 
96     OSL_ENSURE( bIsFolder || rContentType == PACKAGE_STREAM_CONTENT_TYPE || rContentType == PACKAGE_ZIP_STREAM_CONTENT_TYPE,
97                 "ContentProperties::ContentProperties - Unknown type!" );
98 }
99 
100 
101 uno::Sequence< ucb::ContentInfo >
getCreatableContentsInfo(PackageUri const & rUri) const102 ContentProperties::getCreatableContentsInfo( PackageUri const & rUri ) const
103 {
104     if ( bIsFolder )
105     {
106         uno::Sequence< beans::Property > aProps( 1 );
107         aProps.getArray()[ 0 ] = beans::Property(
108                     "Title",
109                     -1,
110                     cppu::UnoType<OUString>::get(),
111                     beans::PropertyAttribute::BOUND );
112 
113         uno::Sequence< ucb::ContentInfo > aSeq( 2 );
114 
115         // Folder.
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;
121 
122         // Stream.
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;
129 
130         return aSeq;
131     }
132     else
133     {
134         return uno::Sequence< ucb::ContentInfo >( 0 );
135     }
136 }
137 
138 
139 // Content Implementation.
140 
141 
142 // static ( "virtual" ctor )
create(const uno::Reference<uno::XComponentContext> & rxContext,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier)143 rtl::Reference<Content> Content::create(
144             const uno::Reference< uno::XComponentContext >& rxContext,
145             ContentProvider* pProvider,
146             const uno::Reference< ucb::XContentIdentifier >& Identifier )
147 {
148     OUString aURL = Identifier->getContentIdentifier();
149     PackageUri aURI( aURL );
150     ContentProperties aProps;
151     uno::Reference< container::XHierarchicalNameAccess > xPackage;
152 
153     if ( loadData( pProvider, aURI, aProps, xPackage ) )
154     {
155         // resource exists
156 
157         sal_Int32 nLastSlash = aURL.lastIndexOf( '/' );
158         if ( ( nLastSlash + 1 ) == aURL.getLength() )
159         {
160             // Client explicitly requested a folder!
161             if ( !aProps.bIsFolder )
162                 return nullptr;
163         }
164 
165         uno::Reference< ucb::XContentIdentifier > xId
166             = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
167         return new Content( rxContext, pProvider, xId, xPackage, aURI, aProps );
168     }
169     else
170     {
171         // resource doesn't exist
172 
173         bool bFolder = false;
174 
175         // Guess type according to URI.
176         sal_Int32 nLastSlash = aURL.lastIndexOf( '/' );
177         if ( ( nLastSlash + 1 ) == aURL.getLength() )
178             bFolder = true;
179 
180         uno::Reference< ucb::XContentIdentifier > xId
181             = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
182 
183         ucb::ContentInfo aInfo;
184         if ( bFolder || aURI.isRootFolder() )
185             aInfo.Type = getContentType( aURI.getScheme(), true );
186         else
187             aInfo.Type = getContentType( aURI.getScheme(), false );
188 
189         return new Content( rxContext, pProvider, xId, xPackage, aURI, aInfo );
190     }
191 }
192 
193 
194 // static ( "virtual" ctor )
create(const uno::Reference<uno::XComponentContext> & rxContext,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier,const ucb::ContentInfo & Info)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 )
200 {
201     if ( Info.Type.isEmpty() )
202         return nullptr;
203 
204     PackageUri aURI( Identifier->getContentIdentifier() );
205 
206     if ( !Info.Type.equalsIgnoreAsciiCase(
207                 getContentType( aURI.getScheme(), true ) ) &&
208          !Info.Type.equalsIgnoreAsciiCase(
209                 getContentType( aURI.getScheme(), false ) ) )
210         return nullptr;
211 
212     uno::Reference< container::XHierarchicalNameAccess > xPackage = pProvider->createPackage( aURI );
213 
214     uno::Reference< ucb::XContentIdentifier > xId
215         = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
216     return new Content( rxContext, pProvider, xId, xPackage, aURI, Info );
217 }
218 
219 
220 // static
getContentType(std::u16string_view aScheme,bool bFolder)221 OUString Content::getContentType(
222     std::u16string_view aScheme, bool bFolder )
223 {
224     return ( OUString::Concat("application/")
225              + aScheme
226              + ( bFolder
227                  ? OUStringLiteral(u"-folder")
228                  : OUStringLiteral(u"-stream") ) );
229 }
230 
231 
Content(const uno::Reference<uno::XComponentContext> & rxContext,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier,const uno::Reference<container::XHierarchicalNameAccess> & Package,const PackageUri & rUri,const ContentProperties & rProps)232 Content::Content(
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 ),
240   m_aUri( rUri ),
241   m_aProps( rProps ),
242   m_eState( PERSISTENT ),
243   m_xPackage( Package ),
244   m_pProvider( pProvider ),
245   m_nModifiedProps( NONE_MODIFIED )
246 {
247 }
248 
249 
Content(const uno::Reference<uno::XComponentContext> & rxContext,ContentProvider * pProvider,const uno::Reference<ucb::XContentIdentifier> & Identifier,const uno::Reference<container::XHierarchicalNameAccess> & Package,const PackageUri & rUri,const ucb::ContentInfo & Info)250 Content::Content(
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 ),
258   m_aUri( rUri ),
259   m_aProps( Info.Type ),
260   m_eState( TRANSIENT ),
261   m_xPackage( Package ),
262   m_pProvider( pProvider ),
263   m_nModifiedProps( NONE_MODIFIED )
264 {
265 }
266 
267 
268 // virtual
~Content()269 Content::~Content()
270 {
271 }
272 
273 
274 // XInterface methods.
275 
276 
277 // virtual
acquire()278 void SAL_CALL Content::acquire()
279     noexcept
280 {
281     ContentImplHelper::acquire();
282 }
283 
284 
285 // virtual
release()286 void SAL_CALL Content::release()
287     noexcept
288 {
289     ContentImplHelper::release();
290 }
291 
292 
293 // virtual
queryInterface(const uno::Type & rType)294 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
295 {
296     uno::Any aRet;
297 
298     if ( isFolder() )
299         aRet = cppu::queryInterface(
300                 rType, static_cast< ucb::XContentCreator * >( this ) );
301 
302     return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
303 }
304 
305 
306 // XTypeProvider methods.
307 
308 
309 XTYPEPROVIDER_COMMON_IMPL( Content );
310 
311 
312 // virtual
getTypes()313 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
314 {
315     if ( isFolder() )
316     {
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 ) );
329 
330         return s_aFolderTypes.getTypes();
331 
332     }
333     else
334     {
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 ) );
346 
347         return s_aDocumentTypes.getTypes();
348     }
349 }
350 
351 
352 // XServiceInfo methods.
353 
354 
355 // virtual
getImplementationName()356 OUString SAL_CALL Content::getImplementationName()
357 {
358     return "com.sun.star.comp.ucb.PackageContent";
359 }
360 
361 
362 // virtual
getSupportedServiceNames()363 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
364 {
365     return { isFolder()? OUString("com.sun.star.ucb.PackageFolderContent"):OUString("com.sun.star.ucb.PackageStreamContent") } ;
366 }
367 
368 
369 // XContent methods.
370 
371 
372 // virtual
getContentType()373 OUString SAL_CALL Content::getContentType()
374 {
375     return m_aProps.aContentType;
376 }
377 
378 
379 // XCommandProcessor methods.
380 
381 
382 // virtual
execute(const ucb::Command & aCommand,sal_Int32,const uno::Reference<ucb::XCommandEnvironment> & Environment)383 uno::Any SAL_CALL Content::execute(
384         const ucb::Command& aCommand,
385         sal_Int32 /*CommandId*/,
386         const uno::Reference< ucb::XCommandEnvironment >& Environment )
387 {
388     uno::Any aRet;
389 
390     if ( aCommand.Name == "getPropertyValues" )
391     {
392 
393         // getPropertyValues
394 
395 
396         uno::Sequence< beans::Property > Properties;
397         if ( !( aCommand.Argument >>= Properties ) )
398         {
399             ucbhelper::cancelCommandExecution(
400                 uno::makeAny( lang::IllegalArgumentException(
401                                     "Wrong argument type!",
402                                     static_cast< cppu::OWeakObject * >( this ),
403                                     -1 ) ),
404                 Environment );
405             // Unreachable
406         }
407 
408         aRet <<= getPropertyValues( Properties );
409     }
410     else if ( aCommand.Name == "setPropertyValues" )
411     {
412 
413         // setPropertyValues
414 
415 
416         uno::Sequence< beans::PropertyValue > aProperties;
417         if ( !( aCommand.Argument >>= aProperties ) )
418         {
419             ucbhelper::cancelCommandExecution(
420                 uno::makeAny( lang::IllegalArgumentException(
421                                     "Wrong argument type!",
422                                     static_cast< cppu::OWeakObject * >( this ),
423                                     -1 ) ),
424                 Environment );
425             // Unreachable
426         }
427 
428         if ( !aProperties.hasElements() )
429         {
430             ucbhelper::cancelCommandExecution(
431                 uno::makeAny( lang::IllegalArgumentException(
432                                     "No properties!",
433                                     static_cast< cppu::OWeakObject * >( this ),
434                                     -1 ) ),
435                 Environment );
436             // Unreachable
437         }
438 
439         aRet <<= setPropertyValues( aProperties, Environment );
440     }
441     else if ( aCommand.Name == "getPropertySetInfo" )
442     {
443 
444         // getPropertySetInfo
445 
446 
447         // Note: Implemented by base class.
448         aRet <<= getPropertySetInfo( Environment );
449     }
450     else if ( aCommand.Name == "getCommandInfo" )
451     {
452 
453         // getCommandInfo
454 
455 
456         // Note: Implemented by base class.
457         aRet <<= getCommandInfo( Environment );
458     }
459     else if ( aCommand.Name == "open" )
460     {
461 
462         // open
463 
464 
465         ucb::OpenCommandArgument2 aOpenCommand;
466         if ( !( aCommand.Argument >>= aOpenCommand ) )
467         {
468             ucbhelper::cancelCommandExecution(
469                 uno::makeAny( lang::IllegalArgumentException(
470                                     "Wrong argument type!",
471                                     static_cast< cppu::OWeakObject * >( this ),
472                                     -1 ) ),
473                 Environment );
474             // Unreachable
475         }
476 
477         aRet = open( aOpenCommand, Environment );
478     }
479     else if ( !m_aUri.isRootFolder() && aCommand.Name == "insert" )
480     {
481 
482         // insert
483 
484 
485         ucb::InsertCommandArgument aArg;
486         if ( !( aCommand.Argument >>= aArg ) )
487         {
488             ucbhelper::cancelCommandExecution(
489                 uno::makeAny( lang::IllegalArgumentException(
490                                     "Wrong argument type!",
491                                     static_cast< cppu::OWeakObject * >( this ),
492                                     -1 ) ),
493                 Environment );
494             // Unreachable
495         }
496 
497         sal_Int32 nNameClash = aArg.ReplaceExisting
498                              ? ucb::NameClash::OVERWRITE
499                              : ucb::NameClash::ERROR;
500         insert( aArg.Data, nNameClash, Environment );
501     }
502     else if ( !m_aUri.isRootFolder() && aCommand.Name == "delete" )
503     {
504 
505         // delete
506 
507 
508         bool bDeletePhysical = false;
509         aCommand.Argument >>= bDeletePhysical;
510         destroy( bDeletePhysical, Environment );
511 
512         // Remove own and all children's persistent data.
513         if ( !removeData() )
514         {
515             uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
516             {
517                 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
518             }));
519             ucbhelper::cancelCommandExecution(
520                 ucb::IOErrorCode_CANT_WRITE,
521                 aArgs,
522                 Environment,
523                 "Cannot remove persistent data!",
524                 this );
525             // Unreachable
526         }
527 
528         // Remove own and all children's Additional Core Properties.
529         removeAdditionalPropertySet();
530     }
531     else if ( aCommand.Name == "transfer" )
532     {
533 
534         // transfer
535         //      ( Not available at stream objects )
536 
537 
538         ucb::TransferInfo aInfo;
539         if ( !( aCommand.Argument >>= aInfo ) )
540         {
541             ucbhelper::cancelCommandExecution(
542                 uno::makeAny( lang::IllegalArgumentException(
543                                     "Wrong argument type!",
544                                     static_cast< cppu::OWeakObject * >( this ),
545                                     -1 ) ),
546                 Environment );
547             // Unreachable
548         }
549 
550         transfer( aInfo, Environment );
551     }
552     else if ( aCommand.Name == "createNewContent" && isFolder() )
553     {
554 
555         // createNewContent
556         //      ( Not available at stream objects )
557 
558 
559         ucb::ContentInfo aInfo;
560         if ( !( aCommand.Argument >>= aInfo ) )
561         {
562             OSL_FAIL( "Wrong argument type!" );
563             ucbhelper::cancelCommandExecution(
564                 uno::makeAny( lang::IllegalArgumentException(
565                                     "Wrong argument type!",
566                                     static_cast< cppu::OWeakObject * >( this ),
567                                     -1 ) ),
568                 Environment );
569             // Unreachable
570         }
571 
572         aRet <<= createNewContent( aInfo );
573     }
574     else if ( aCommand.Name == "flush" )
575     {
576 
577         // flush
578         //      ( Not available at stream objects )
579 
580 
581         if( !flushData() )
582         {
583             uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
584             {
585                 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
586             }));
587             ucbhelper::cancelCommandExecution(
588                 ucb::IOErrorCode_CANT_WRITE,
589                 aArgs,
590                 Environment,
591                 "Cannot write file to disk!",
592                 this );
593             // Unreachable
594         }
595     }
596     else
597     {
598 
599         // Unsupported command
600 
601 
602         ucbhelper::cancelCommandExecution(
603             uno::makeAny( ucb::UnsupportedCommandException(
604                                 OUString(),
605                                 static_cast< cppu::OWeakObject * >( this ) ) ),
606             Environment );
607         // Unreachable
608     }
609 
610     return aRet;
611 }
612 
613 
614 // virtual
abort(sal_Int32)615 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
616 {
617     // @@@ Implement logic to abort running commands, if this makes
618     //     sense for your content.
619 }
620 
621 
622 // XContentCreator methods.
623 
624 
625 // virtual
626 uno::Sequence< ucb::ContentInfo > SAL_CALL
queryCreatableContentsInfo()627 Content::queryCreatableContentsInfo()
628 {
629     return m_aProps.getCreatableContentsInfo( m_aUri );
630 }
631 
632 
633 // virtual
634 uno::Reference< ucb::XContent > SAL_CALL
createNewContent(const ucb::ContentInfo & Info)635 Content::createNewContent( const ucb::ContentInfo& Info )
636 {
637     if ( isFolder() )
638     {
639         osl::Guard< osl::Mutex > aGuard( m_aMutex );
640 
641         if ( Info.Type.isEmpty() )
642             return uno::Reference< ucb::XContent >();
643 
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 >();
649 
650         OUString aURL = m_aUri.getUri() + "/";
651 
652         if ( Info.Type.equalsIgnoreAsciiCase(
653                 getContentType( m_aUri.getScheme(), true ) ) )
654             aURL += "New_Folder";
655         else
656             aURL += "New_Stream";
657 
658         uno::Reference< ucb::XContentIdentifier > xId(
659             new ::ucbhelper::ContentIdentifier( aURL ) );
660 
661         return create( m_xContext, m_pProvider, xId, Info );
662     }
663     else
664     {
665         OSL_FAIL( "createNewContent called on non-folder object!" );
666         return uno::Reference< ucb::XContent >();
667     }
668 }
669 
670 
671 // Non-interface methods.
672 
673 
674 // virtual
getParentURL()675 OUString Content::getParentURL()
676 {
677     return m_aUri.getParentUri();
678 }
679 
680 
681 // static
getPropertyValues(const uno::Reference<uno::XComponentContext> & rxContext,const uno::Sequence<beans::Property> & rProperties,ContentProvider * pProvider,const OUString & rContentId)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 )
687 {
688     ContentProperties aData;
689     uno::Reference< container::XHierarchicalNameAccess > xPackage;
690     if ( loadData( pProvider, PackageUri( rContentId ), aData, xPackage ) )
691     {
692         return getPropertyValues( rxContext,
693                                   rProperties,
694                                   aData,
695                                   rtl::Reference<
696                                     ::ucbhelper::ContentProviderImplHelper >(
697                                         pProvider ),
698                                   rContentId );
699     }
700     else
701     {
702         rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
703             = new ::ucbhelper::PropertyValueSet( rxContext );
704 
705         for ( const beans::Property& rProp : rProperties )
706             xRow->appendVoid( rProp );
707 
708         return xRow;
709     }
710 }
711 
712 
713 // static
getPropertyValues(const uno::Reference<uno::XComponentContext> & rxContext,const uno::Sequence<beans::Property> & rProperties,const ContentProperties & rData,const rtl::Reference<::ucbhelper::ContentProviderImplHelper> & rProvider,const OUString & rContentId)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 >&
719             rProvider,
720         const OUString& rContentId )
721 {
722     // Note: Empty sequence means "get values of all supported properties".
723 
724     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
725         = new ::ucbhelper::PropertyValueSet( rxContext );
726 
727     if ( rProperties.hasElements() )
728     {
729         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
730         bool bTriedToGetAdditionalPropSet = false;
731 
732         for ( const beans::Property& rProp : rProperties )
733         {
734             // Process Core properties.
735 
736             if ( rProp.Name == "ContentType" )
737             {
738                 xRow->appendString ( rProp, rData.aContentType );
739             }
740             else if ( rProp.Name == "Title" )
741             {
742                 xRow->appendString ( rProp, rData.aTitle );
743             }
744             else if ( rProp.Name == "IsDocument" )
745             {
746                 xRow->appendBoolean( rProp, rData.bIsDocument );
747             }
748             else if ( rProp.Name == "IsFolder" )
749             {
750                 xRow->appendBoolean( rProp, rData.bIsFolder );
751             }
752             else if ( rProp.Name == "CreatableContentsInfo" )
753             {
754                 xRow->appendObject(
755                     rProp, uno::makeAny(
756                         rData.getCreatableContentsInfo(
757                             PackageUri( rContentId ) ) ) );
758             }
759             else if ( rProp.Name == "MediaType" )
760             {
761                 xRow->appendString ( rProp, rData.aMediaType );
762             }
763             else if ( rProp.Name == "Size" )
764             {
765                 // Property only available for streams.
766                 if ( rData.bIsDocument )
767                     xRow->appendLong( rProp, rData.nSize );
768                 else
769                     xRow->appendVoid( rProp );
770             }
771             else if ( rProp.Name == "Compressed" )
772             {
773                 // Property only available for streams.
774                 if ( rData.bIsDocument )
775                     xRow->appendBoolean( rProp, rData.bCompressed );
776                 else
777                     xRow->appendVoid( rProp );
778             }
779             else if ( rProp.Name == "Encrypted" )
780             {
781                 // Property only available for streams.
782                 if ( rData.bIsDocument )
783                     xRow->appendBoolean( rProp, rData.bEncrypted );
784                 else
785                     xRow->appendVoid( rProp );
786             }
787             else if ( rProp.Name == "HasEncryptedEntries" )
788             {
789                 // Property only available for root folder.
790                 PackageUri aURI( rContentId );
791                 if ( aURI.isRootFolder() )
792                     xRow->appendBoolean( rProp, rData.bHasEncryptedEntries );
793                 else
794                     xRow->appendVoid( rProp );
795             }
796             else
797             {
798                 // Not a Core Property! Maybe it's an Additional Core Property?!
799 
800                 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
801                 {
802                     xAdditionalPropSet =
803                             rProvider->getAdditionalPropertySet( rContentId,
804                                                                  false );
805                     bTriedToGetAdditionalPropSet = true;
806                 }
807 
808                 if ( xAdditionalPropSet.is() )
809                 {
810                     if ( !xRow->appendPropertySetValue(
811                                                 xAdditionalPropSet,
812                                                 rProp ) )
813                     {
814                         // Append empty entry.
815                         xRow->appendVoid( rProp );
816                     }
817                 }
818                 else
819                 {
820                     // Append empty entry.
821                     xRow->appendVoid( rProp );
822                 }
823             }
824         }
825     }
826     else
827     {
828         // Append all Core Properties.
829         xRow->appendString (
830             beans::Property(
831                 "ContentType",
832                 -1,
833                 cppu::UnoType<OUString>::get(),
834                 beans::PropertyAttribute::BOUND
835                     | beans::PropertyAttribute::READONLY ),
836             rData.aContentType );
837         xRow->appendString(
838             beans::Property(
839                 "Title",
840                 -1,
841                 cppu::UnoType<OUString>::get(),
842                 beans::PropertyAttribute::BOUND ),
843             rData.aTitle );
844         xRow->appendBoolean(
845             beans::Property(
846                 "IsDocument",
847                 -1,
848                 cppu::UnoType<bool>::get(),
849                 beans::PropertyAttribute::BOUND
850                     | beans::PropertyAttribute::READONLY ),
851             rData.bIsDocument );
852         xRow->appendBoolean(
853             beans::Property(
854                 "IsFolder",
855                 -1,
856                 cppu::UnoType<bool>::get(),
857                 beans::PropertyAttribute::BOUND
858                     | beans::PropertyAttribute::READONLY ),
859             rData.bIsFolder );
860         xRow->appendObject(
861             beans::Property(
862                 "CreatableContentsInfo",
863                 -1,
864                 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
865                 beans::PropertyAttribute::BOUND
866                 | beans::PropertyAttribute::READONLY ),
867             uno::makeAny(
868                 rData.getCreatableContentsInfo( PackageUri( rContentId ) ) ) );
869         xRow->appendString(
870             beans::Property(
871                 "MediaType",
872                 -1,
873                 cppu::UnoType<OUString>::get(),
874                 beans::PropertyAttribute::BOUND ),
875             rData.aMediaType );
876 
877         // Properties only available for streams.
878         if ( rData.bIsDocument )
879         {
880             xRow->appendLong(
881                 beans::Property(
882                     "Size",
883                     -1,
884                     cppu::UnoType<sal_Int64>::get(),
885                     beans::PropertyAttribute::BOUND
886                         | beans::PropertyAttribute::READONLY ),
887                 rData.nSize );
888 
889             xRow->appendBoolean(
890                 beans::Property(
891                     "Compressed",
892                     -1,
893                     cppu::UnoType<bool>::get(),
894                     beans::PropertyAttribute::BOUND ),
895                 rData.bCompressed );
896 
897             xRow->appendBoolean(
898                 beans::Property(
899                     "Encrypted",
900                     -1,
901                     cppu::UnoType<bool>::get(),
902                     beans::PropertyAttribute::BOUND ),
903                 rData.bEncrypted );
904         }
905 
906         // Properties only available for root folder.
907         PackageUri aURI( rContentId );
908         if ( aURI.isRootFolder() )
909         {
910             xRow->appendBoolean(
911                 beans::Property(
912                     "HasEncryptedEntries",
913                     -1,
914                     cppu::UnoType<bool>::get(),
915                     beans::PropertyAttribute::BOUND
916                         | beans::PropertyAttribute::READONLY ),
917                 rData.bHasEncryptedEntries );
918         }
919 
920         // Append all Additional Core Properties.
921 
922         uno::Reference< beans::XPropertySet > xSet =
923             rProvider->getAdditionalPropertySet( rContentId, false );
924         xRow->appendPropertySet( xSet );
925     }
926 
927     return xRow;
928 }
929 
930 
getPropertyValues(const uno::Sequence<beans::Property> & rProperties)931 uno::Reference< sdbc::XRow > Content::getPropertyValues(
932                         const uno::Sequence< beans::Property >& rProperties )
933 {
934     osl::Guard< osl::Mutex > aGuard( m_aMutex );
935     return getPropertyValues( m_xContext,
936                               rProperties,
937                               m_aProps,
938                               m_xProvider,
939                               m_xIdentifier->getContentIdentifier() );
940 }
941 
942 
setPropertyValues(const uno::Sequence<beans::PropertyValue> & rValues,const uno::Reference<ucb::XCommandEnvironment> & xEnv)943 uno::Sequence< uno::Any > Content::setPropertyValues(
944         const uno::Sequence< beans::PropertyValue >& rValues,
945         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
946 {
947     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
948 
949     uno::Sequence< uno::Any > aRet( rValues.getLength() );
950     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
951     sal_Int32 nChanged = 0;
952 
953     beans::PropertyChangeEvent aEvent;
954     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
955     aEvent.Further        = false;
956 //    aEvent.PropertyName   =
957     aEvent.PropertyHandle = -1;
958 //    aEvent.OldValue       =
959 //    aEvent.NewValue       =
960 
961     const beans::PropertyValue* pValues = rValues.getConstArray();
962     sal_Int32 nCount = rValues.getLength();
963 
964     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
965     bool bTriedToGetAdditionalPropSet = false;
966     bool bExchange = false;
967     bool bStore    = false;
968     OUString aNewTitle;
969     sal_Int32 nTitlePos = -1;
970 
971     for ( sal_Int32 n = 0; n < nCount; ++n )
972     {
973         const beans::PropertyValue& rValue = pValues[ n ];
974 
975         if ( rValue.Name == "ContentType" )
976         {
977             // Read-only property!
978             aRet[ n ] <<= lang::IllegalAccessException(
979                             "Property is read-only!",
980                             static_cast< cppu::OWeakObject * >( this ) );
981         }
982         else if ( rValue.Name == "IsDocument" )
983         {
984             // Read-only property!
985             aRet[ n ] <<= lang::IllegalAccessException(
986                             "Property is read-only!",
987                             static_cast< cppu::OWeakObject * >( this ) );
988         }
989         else if ( rValue.Name == "IsFolder" )
990         {
991             // Read-only property!
992             aRet[ n ] <<= lang::IllegalAccessException(
993                             "Property is read-only!",
994                             static_cast< cppu::OWeakObject * >( this ) );
995         }
996         else if ( rValue.Name == "CreatableContentsInfo" )
997         {
998             // Read-only property!
999             aRet[ n ] <<= lang::IllegalAccessException(
1000                             "Property is read-only!",
1001                             static_cast< cppu::OWeakObject * >( this ) );
1002         }
1003         else if ( rValue.Name == "Title" )
1004         {
1005             if ( m_aUri.isRootFolder() )
1006             {
1007                 // Read-only property!
1008                 aRet[ n ] <<= lang::IllegalAccessException(
1009                                 "Property is read-only!",
1010                                 static_cast< cppu::OWeakObject * >( this ) );
1011             }
1012             else
1013             {
1014                 OUString aNewValue;
1015                 if ( rValue.Value >>= aNewValue )
1016                 {
1017                     // No empty titles!
1018                     if ( !aNewValue.isEmpty() )
1019                     {
1020                         if ( aNewValue != m_aProps.aTitle )
1021                         {
1022                             // modified title -> modified URL -> exchange !
1023                             if ( m_eState == PERSISTENT )
1024                                 bExchange = true;
1025 
1026                             // new value will be set later...
1027                             aNewTitle = aNewValue;
1028 
1029                             // remember position within sequence of values
1030                             // (for error handling).
1031                             nTitlePos = n;
1032                         }
1033                     }
1034                     else
1035                     {
1036                         aRet[ n ] <<=
1037                             lang::IllegalArgumentException(
1038                                 "Empty title not allowed!",
1039                                 static_cast< cppu::OWeakObject * >( this ),
1040                                 -1 );
1041                     }
1042                 }
1043                 else
1044                 {
1045                     aRet[ n ] <<=
1046                         beans::IllegalTypeException(
1047                             "Property value has wrong type!",
1048                             static_cast< cppu::OWeakObject * >( this ) );
1049                 }
1050             }
1051         }
1052         else if ( rValue.Name == "MediaType" )
1053         {
1054             OUString aNewValue;
1055             if ( rValue.Value >>= aNewValue )
1056             {
1057                 if ( aNewValue != m_aProps.aMediaType )
1058                 {
1059                     aEvent.PropertyName = rValue.Name;
1060                     aEvent.OldValue     <<= m_aProps.aMediaType;
1061                     aEvent.NewValue     <<= aNewValue;
1062 
1063                     m_aProps.aMediaType = aNewValue;
1064                     nChanged++;
1065                     bStore = true;
1066                     m_nModifiedProps |= MEDIATYPE_MODIFIED;
1067                 }
1068             }
1069             else
1070             {
1071                 aRet[ n ] <<= beans::IllegalTypeException(
1072                                 "Property value has wrong type!",
1073                                 static_cast< cppu::OWeakObject * >( this ) );
1074             }
1075         }
1076         else if ( rValue.Name == "Size" )
1077         {
1078             // Read-only property!
1079             aRet[ n ] <<= lang::IllegalAccessException(
1080                             "Property is read-only!",
1081                             static_cast< cppu::OWeakObject * >( this ) );
1082         }
1083         else if ( rValue.Name == "Compressed" )
1084         {
1085             // Property only available for streams.
1086             if ( m_aProps.bIsDocument )
1087             {
1088                 bool bNewValue;
1089                 if ( rValue.Value >>= bNewValue )
1090                 {
1091                     if ( bNewValue != m_aProps.bCompressed )
1092                     {
1093                         aEvent.PropertyName = rValue.Name;
1094                         aEvent.OldValue <<= m_aProps.bCompressed;
1095                         aEvent.NewValue <<= bNewValue;
1096 
1097                         m_aProps.bCompressed = bNewValue;
1098                         nChanged++;
1099                         bStore = true;
1100                         m_nModifiedProps |= COMPRESSED_MODIFIED;
1101                     }
1102                 }
1103                 else
1104                 {
1105                     aRet[ n ] <<= beans::IllegalTypeException(
1106                                 "Property value has wrong type!",
1107                                 static_cast< cppu::OWeakObject * >( this ) );
1108                 }
1109             }
1110             else
1111             {
1112                 aRet[ n ] <<= beans::UnknownPropertyException(
1113                                 "Compressed only supported by streams!",
1114                                 static_cast< cppu::OWeakObject * >( this ) );
1115             }
1116         }
1117         else if ( rValue.Name == "Encrypted" )
1118         {
1119             // Property only available for streams.
1120             if ( m_aProps.bIsDocument )
1121             {
1122                 bool bNewValue;
1123                 if ( rValue.Value >>= bNewValue )
1124                 {
1125                     if ( bNewValue != m_aProps.bEncrypted )
1126                     {
1127                         aEvent.PropertyName = rValue.Name;
1128                         aEvent.OldValue <<= m_aProps.bEncrypted;
1129                         aEvent.NewValue <<= bNewValue;
1130 
1131                         m_aProps.bEncrypted = bNewValue;
1132                         nChanged++;
1133                         bStore = true;
1134                         m_nModifiedProps |= ENCRYPTED_MODIFIED;
1135                     }
1136                 }
1137                 else
1138                 {
1139                     aRet[ n ] <<= beans::IllegalTypeException(
1140                                 "Property value has wrong type!",
1141                                 static_cast< cppu::OWeakObject * >( this ) );
1142                 }
1143             }
1144             else
1145             {
1146                 aRet[ n ] <<= beans::UnknownPropertyException(
1147                                 "Encrypted only supported by streams!",
1148                                 static_cast< cppu::OWeakObject * >( this ) );
1149             }
1150         }
1151         else if ( rValue.Name == "HasEncryptedEntries" )
1152         {
1153             // Read-only property!
1154             aRet[ n ] <<= lang::IllegalAccessException(
1155                             "Property is read-only!",
1156                             static_cast< cppu::OWeakObject * >( this ) );
1157         }
1158         else if ( rValue.Name == "EncryptionKey" )
1159         {
1160             // @@@ This is a temporary solution. In the future submitting
1161             //     the key should be done using an interaction handler!
1162 
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 )
1166             {
1167                 uno::Sequence < sal_Int8 > aNewValue;
1168                 if ( rValue.Value >>= aNewValue )
1169                 {
1170                     if ( aNewValue != m_aProps.aEncryptionKey )
1171                     {
1172                         aEvent.PropertyName = rValue.Name;
1173                         aEvent.OldValue     <<= m_aProps.aEncryptionKey;
1174                         aEvent.NewValue     <<= aNewValue;
1175 
1176                         m_aProps.aEncryptionKey = aNewValue;
1177                         nChanged++;
1178                         bStore = true;
1179                         m_nModifiedProps |= ENCRYPTIONKEY_MODIFIED;
1180                     }
1181                 }
1182                 else
1183                 {
1184                     aRet[ n ] <<= beans::IllegalTypeException(
1185                                 "Property value has wrong type!",
1186                                 static_cast< cppu::OWeakObject * >( this ) );
1187                 }
1188             }
1189             else
1190             {
1191                 aRet[ n ] <<= beans::UnknownPropertyException(
1192                         "EncryptionKey not supported by non-root folder!",
1193                         static_cast< cppu::OWeakObject * >( this ) );
1194             }
1195         }
1196         else
1197         {
1198             // Not a Core Property! Maybe it's an Additional Core Property?!
1199 
1200             if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1201             {
1202                 xAdditionalPropSet = getAdditionalPropertySet( false );
1203                 bTriedToGetAdditionalPropSet = true;
1204             }
1205 
1206             if ( xAdditionalPropSet.is() )
1207             {
1208                 try
1209                 {
1210                     uno::Any aOldValue
1211                         = xAdditionalPropSet->getPropertyValue( rValue.Name );
1212                     if ( aOldValue != rValue.Value )
1213                     {
1214                         xAdditionalPropSet->setPropertyValue(
1215                                                 rValue.Name, rValue.Value );
1216 
1217                         aEvent.PropertyName = rValue.Name;
1218                         aEvent.OldValue     = aOldValue;
1219                         aEvent.NewValue     = rValue.Value;
1220 
1221                         aChanges.getArray()[ nChanged ] = aEvent;
1222                         nChanged++;
1223                     }
1224                 }
1225                 catch ( beans::UnknownPropertyException const & e )
1226                 {
1227                     aRet[ n ] <<= e;
1228                 }
1229                 catch ( lang::WrappedTargetException const & e )
1230                 {
1231                     aRet[ n ] <<= e;
1232                 }
1233                 catch ( beans::PropertyVetoException const & e )
1234                 {
1235                     aRet[ n ] <<= e;
1236                 }
1237                 catch ( lang::IllegalArgumentException const & e )
1238                 {
1239                     aRet[ n ] <<= e;
1240                 }
1241             }
1242             else
1243             {
1244                 aRet[ n ] <<= uno::Exception(
1245                                 "No property set for storing the value!",
1246                                 static_cast< cppu::OWeakObject * >( this ) );
1247             }
1248         }
1249     }
1250 
1251     if ( bExchange )
1252     {
1253         uno::Reference< ucb::XContentIdentifier > xOldId = m_xIdentifier;
1254 
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 );
1260 
1261         aGuard.clear();
1262         if ( exchangeIdentity( xNewId ) )
1263         {
1264             // Adapt persistent data.
1265             renameData( xOldId, xNewId );
1266 
1267             // Adapt Additional Core Properties.
1268             renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1269                                          xNewId->getContentIdentifier() );
1270         }
1271         else
1272         {
1273             // Do not set new title!
1274             aNewTitle.clear();
1275 
1276             // Set error .
1277             aRet[ nTitlePos ] <<= uno::Exception(
1278                     "Exchange failed!",
1279                     static_cast< cppu::OWeakObject * >( this ) );
1280         }
1281     }
1282 
1283     if ( !aNewTitle.isEmpty() )
1284     {
1285         aEvent.PropertyName = "Title";
1286         aEvent.OldValue     <<= m_aProps.aTitle;
1287         aEvent.NewValue     <<= aNewTitle;
1288 
1289         m_aProps.aTitle = aNewTitle;
1290 
1291         aChanges.getArray()[ nChanged ] = aEvent;
1292         nChanged++;
1293     }
1294 
1295     if ( nChanged > 0 )
1296     {
1297         // Save changes, if content was already made persistent.
1298         if ( ( m_nModifiedProps & ENCRYPTIONKEY_MODIFIED ) ||
1299              ( bStore && ( m_eState == PERSISTENT ) ) )
1300         {
1301             if ( !storeData( uno::Reference< io::XInputStream >() ) )
1302             {
1303                 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1304                 {
1305                     {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1306                 }));
1307                 ucbhelper::cancelCommandExecution(
1308                     ucb::IOErrorCode_CANT_WRITE,
1309                     aArgs,
1310                     xEnv,
1311                     "Cannot store persistent data!",
1312                     this );
1313                 // Unreachable
1314             }
1315         }
1316 
1317         aGuard.clear();
1318         aChanges.realloc( nChanged );
1319         notifyPropertiesChange( aChanges );
1320     }
1321 
1322     return aRet;
1323 }
1324 
1325 
open(const ucb::OpenCommandArgument2 & rArg,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1326 uno::Any Content::open(
1327                 const ucb::OpenCommandArgument2& rArg,
1328                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1329 {
1330     if ( rArg.Mode == ucb::OpenMode::ALL ||
1331          rArg.Mode == ucb::OpenMode::FOLDERS ||
1332          rArg.Mode == ucb::OpenMode::DOCUMENTS )
1333     {
1334 
1335         // open command for a folder content
1336 
1337 
1338         uno::Reference< ucb::XDynamicResultSet > xSet
1339             = new DynamicResultSet( m_xContext, this, rArg, xEnv );
1340         return uno::makeAny( xSet );
1341     }
1342     else
1343     {
1344 
1345         // open command for a document content
1346 
1347 
1348         if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1349              ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1350         {
1351             // Currently(?) unsupported.
1352             ucbhelper::cancelCommandExecution(
1353                 uno::makeAny( ucb::UnsupportedOpenModeException(
1354                                     OUString(),
1355                                     static_cast< cppu::OWeakObject * >( this ),
1356                                     sal_Int16( rArg.Mode ) ) ),
1357                 xEnv );
1358             // Unreachable
1359         }
1360 
1361         uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1362         if ( xOut.is() )
1363         {
1364             // PUSH: write data into xOut
1365 
1366             uno::Reference< io::XInputStream > xIn = getInputStream();
1367             if ( !xIn.is() )
1368             {
1369                 // No interaction if we are not persistent!
1370                 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1371                 {
1372                     {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1373                 }));
1374                 ucbhelper::cancelCommandExecution(
1375                     ucb::IOErrorCode_CANT_READ,
1376                     aArgs,
1377                     m_eState == PERSISTENT
1378                         ? xEnv
1379                         : uno::Reference< ucb::XCommandEnvironment >(),
1380                     "Got no data stream!",
1381                     this );
1382                 // Unreachable
1383             }
1384 
1385             try
1386             {
1387                 uno::Sequence< sal_Int8 > aBuffer;
1388                 while (true)
1389                 {
1390                     sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1391                     if (!nRead)
1392                         break;
1393                     aBuffer.realloc( nRead );
1394                     xOut->writeBytes( aBuffer );
1395                 }
1396 
1397                 xOut->closeOutput();
1398             }
1399             catch ( io::NotConnectedException const & )
1400             {
1401                 // closeOutput, readSomeBytes, writeBytes
1402             }
1403             catch ( io::BufferSizeExceededException const & )
1404             {
1405                 // closeOutput, readSomeBytes, writeBytes
1406             }
1407             catch ( io::IOException const & )
1408             {
1409                 // closeOutput, readSomeBytes, writeBytes
1410             }
1411         }
1412         else
1413         {
1414             uno::Reference< io::XActiveDataSink > xDataSink(
1415                                             rArg.Sink, uno::UNO_QUERY );
1416             if ( xDataSink.is() )
1417             {
1418                 // PULL: wait for client read
1419 
1420                 uno::Reference< io::XInputStream > xIn = getInputStream();
1421                 if ( !xIn.is() )
1422                 {
1423                     // No interaction if we are not persistent!
1424                     uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1425                     {
1426                         {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1427                     }));
1428                     ucbhelper::cancelCommandExecution(
1429                         ucb::IOErrorCode_CANT_READ,
1430                         aArgs,
1431                         m_eState == PERSISTENT
1432                             ? xEnv
1433                             : uno::Reference<
1434                                   ucb::XCommandEnvironment >(),
1435                         "Got no data stream!",
1436                         this );
1437                     // Unreachable
1438                 }
1439 
1440                 // Done.
1441                 xDataSink->setInputStream( xIn );
1442             }
1443             else
1444             {
1445                 // Note: aOpenCommand.Sink may contain an XStream
1446                 //       implementation. Support for this type of
1447                 //       sink is optional...
1448                 ucbhelper::cancelCommandExecution(
1449                     uno::makeAny(
1450                         ucb::UnsupportedDataSinkException(
1451                                 OUString(),
1452                                 static_cast< cppu::OWeakObject * >( this ),
1453                                 rArg.Sink ) ),
1454                     xEnv );
1455                 // Unreachable
1456             }
1457         }
1458     }
1459 
1460     return uno::Any();
1461 }
1462 
1463 
insert(const uno::Reference<io::XInputStream> & xStream,sal_Int32 nNameClashResolve,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1464 void Content::insert(
1465             const uno::Reference< io::XInputStream >& xStream,
1466             sal_Int32 nNameClashResolve,
1467             const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1468 {
1469     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1470 
1471     // Check, if all required properties were set.
1472     if ( isFolder() )
1473     {
1474         // Required: Title
1475 
1476         if ( m_aProps.aTitle.isEmpty() )
1477             m_aProps.aTitle = m_aUri.getName();
1478     }
1479     else
1480     {
1481         // Required: rArg.Data
1482 
1483         if ( !xStream.is() )
1484         {
1485             ucbhelper::cancelCommandExecution(
1486                 uno::makeAny( ucb::MissingInputStreamException(
1487                                 OUString(),
1488                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1489                 xEnv );
1490             // Unreachable
1491         }
1492 
1493         // Required: Title
1494 
1495         if ( m_aProps.aTitle.isEmpty() )
1496             m_aProps.aTitle = m_aUri.getName();
1497     }
1498 
1499     OUString aNewURL = m_aUri.getParentUri();
1500     if (1 + aNewURL.lastIndexOf('/') != aNewURL.getLength())
1501         aNewURL += "/";
1502     aNewURL += ::ucb_impl::urihelper::encodeSegment( m_aProps.aTitle );
1503     PackageUri aNewUri( aNewURL );
1504 
1505     // Handle possible name clash...
1506     switch ( nNameClashResolve )
1507     {
1508         // fail.
1509         case ucb::NameClash::ERROR:
1510             if ( hasData( aNewUri ) )
1511             {
1512                 ucbhelper::cancelCommandExecution(
1513                     uno::makeAny( ucb::NameClashException(
1514                                     OUString(),
1515                                     static_cast< cppu::OWeakObject * >( this ),
1516                                     task::InteractionClassification_ERROR,
1517                                     m_aProps.aTitle ) ),
1518                     xEnv );
1519                 // Unreachable
1520             }
1521             break;
1522 
1523         // replace (possibly) existing object.
1524         case ucb::NameClash::OVERWRITE:
1525             break;
1526 
1527         // "invent" a new valid title.
1528         case ucb::NameClash::RENAME:
1529             if ( hasData( aNewUri ) )
1530             {
1531                 sal_Int32 nTry = 0;
1532 
1533                 do
1534                 {
1535                     OUString aNew = aNewUri.getUri() + "_";
1536                     aNew += OUString::number( ++nTry );
1537                     aNewUri.setUri( aNew );
1538                 }
1539                 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1540 
1541                 if ( nTry == 1000 )
1542                 {
1543                     ucbhelper::cancelCommandExecution(
1544                         uno::makeAny(
1545                             ucb::UnsupportedNameClashException(
1546                                 "Unable to resolve name clash!",
1547                                 static_cast< cppu::OWeakObject * >( this ),
1548                                 nNameClashResolve ) ),
1549                     xEnv );
1550                     // Unreachable
1551                 }
1552                 else
1553                 {
1554                     m_aProps.aTitle += "_";
1555                     m_aProps.aTitle += OUString::number( nTry );
1556                 }
1557             }
1558             break;
1559 
1560         case ucb::NameClash::KEEP: // deprecated
1561         case ucb::NameClash::ASK:
1562         default:
1563             if ( hasData( aNewUri ) )
1564             {
1565                 ucbhelper::cancelCommandExecution(
1566                     uno::makeAny(
1567                         ucb::UnsupportedNameClashException(
1568                             OUString(),
1569                             static_cast< cppu::OWeakObject * >( this ),
1570                             nNameClashResolve ) ),
1571                     xEnv );
1572                 // Unreachable
1573             }
1574             break;
1575     }
1576 
1577     // Identifier changed?
1578     bool bNewId = ( m_aUri.getUri() != aNewUri.getUri() );
1579 
1580     if ( bNewId )
1581     {
1582         m_xIdentifier = new ::ucbhelper::ContentIdentifier( aNewURL );
1583         m_aUri = aNewUri;
1584     }
1585 
1586     if ( !storeData( xStream ) )
1587     {
1588         uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1589         {
1590             {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1591         }));
1592         ucbhelper::cancelCommandExecution(
1593             ucb::IOErrorCode_CANT_WRITE,
1594             aArgs,
1595             xEnv,
1596             "Cannot store persistent data!",
1597             this );
1598         // Unreachable
1599     }
1600 
1601     m_eState = PERSISTENT;
1602 
1603     if ( bNewId )
1604     {
1605         // Take over correct default values from underlying packager...
1606         uno::Reference< container::XHierarchicalNameAccess > xXHierarchicalNameAccess;
1607         loadData( m_pProvider,
1608                   m_aUri,
1609                   m_aProps,
1610                   xXHierarchicalNameAccess );
1611 
1612         aGuard.clear();
1613         inserted();
1614     }
1615 }
1616 
1617 
destroy(bool bDeletePhysical,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1618 void Content::destroy(
1619                 bool bDeletePhysical,
1620                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1621 {
1622     // @@@ take care about bDeletePhysical -> trashcan support
1623 
1624     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1625 
1626     uno::Reference< ucb::XContent > xThis = this;
1627 
1628     // Persistent?
1629     if ( m_eState != PERSISTENT )
1630     {
1631         ucbhelper::cancelCommandExecution(
1632             uno::makeAny( ucb::UnsupportedCommandException(
1633                                 "Not persistent!",
1634                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1635             xEnv );
1636         // Unreachable
1637     }
1638 
1639     m_eState = DEAD;
1640 
1641     aGuard.clear();
1642     deleted();
1643 
1644     if ( isFolder() )
1645     {
1646         // Process instantiated children...
1647 
1648         ContentRefList aChildren;
1649         queryChildren( aChildren );
1650 
1651         for ( auto& rChild : aChildren )
1652         {
1653             rChild->destroy( bDeletePhysical, xEnv );
1654         }
1655     }
1656 }
1657 
1658 
transfer(const ucb::TransferInfo & rInfo,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1659 void Content::transfer(
1660             const ucb::TransferInfo& rInfo,
1661             const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1662 {
1663     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1664 
1665     // Persistent?
1666     if ( m_eState != PERSISTENT )
1667     {
1668         ucbhelper::cancelCommandExecution(
1669             uno::makeAny( ucb::UnsupportedCommandException(
1670                                 "Not persistent!",
1671                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1672             xEnv );
1673         // Unreachable
1674     }
1675 
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 ) )
1680     {
1681         ucbhelper::cancelCommandExecution(
1682             uno::makeAny( ucb::InteractiveBadTransferURLException(
1683                                 OUString(),
1684                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1685             xEnv );
1686         // Unreachable
1687     }
1688 
1689     // Is source not a parent of me / not me?
1690     OUString aId = m_aUri.getParentUri() + "/";
1691 
1692     if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1693     {
1694         if ( aId.startsWith( rInfo.SourceURL ) )
1695         {
1696             uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1697             {
1698                 {"Uri", uno::Any(rInfo.SourceURL)}
1699             }));
1700             ucbhelper::cancelCommandExecution(
1701                 ucb::IOErrorCode_RECURSIVE,
1702                 aArgs,
1703                 xEnv,
1704                 "Target is equal to or is a child of source!",
1705                 this );
1706             // Unreachable
1707         }
1708     }
1709 
1710 
1711     // 0) Obtain content object for source.
1712 
1713 
1714     uno::Reference< ucb::XContentIdentifier > xId
1715         = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1716 
1717     // Note: The static cast is okay here, because its sure that
1718     //       m_xProvider is always the PackageContentProvider.
1719     rtl::Reference< Content > xSource;
1720 
1721     try
1722     {
1723         xSource = static_cast< Content * >(
1724                         m_xProvider->queryContent( xId ).get() );
1725     }
1726     catch ( ucb::IllegalIdentifierException const & )
1727     {
1728         // queryContent
1729     }
1730 
1731     if ( !xSource.is() )
1732     {
1733         uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1734         {
1735             {"Uri", uno::Any(xId->getContentIdentifier())}
1736         }));
1737         ucbhelper::cancelCommandExecution(
1738             ucb::IOErrorCode_CANT_READ,
1739             aArgs,
1740             xEnv,
1741             "Cannot instantiate source object!",
1742             this );
1743         // Unreachable
1744     }
1745 
1746 
1747     // 1) Create new child content.
1748 
1749 
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;
1756 
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() )
1762     {
1763         uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1764         {
1765             {"Folder", uno::Any(aId)}
1766         }));
1767         ucbhelper::cancelCommandExecution(
1768             ucb::IOErrorCode_CANT_CREATE,
1769             aArgs,
1770             xEnv,
1771             "XContentCreator::createNewContent failed!",
1772             this );
1773         // Unreachable
1774     }
1775 
1776 
1777     // 2) Copy data from source content to child content.
1778 
1779 
1780     uno::Sequence< beans::Property > aSourceProps
1781                     = xSource->getPropertySetInfo( xEnv )->getProperties();
1782     sal_Int32 nCount = aSourceProps.getLength();
1783 
1784     if ( nCount )
1785     {
1786         bool bHadTitle = rInfo.NewTitle.isEmpty();
1787 
1788         // Get all source values.
1789         uno::Reference< sdbc::XRow > xRow
1790             = xSource->getPropertyValues( aSourceProps );
1791 
1792         uno::Sequence< beans::PropertyValue > aValues( nCount );
1793         beans::PropertyValue* pValues = aValues.getArray();
1794 
1795         const beans::Property* pProps = aSourceProps.getConstArray();
1796         for ( sal_Int32 n = 0; n < nCount; ++n )
1797         {
1798             const beans::Property& rProp  = pProps[ n ];
1799             beans::PropertyValue&  rValue = pValues[ n ];
1800 
1801             rValue.Name   = rProp.Name;
1802             rValue.Handle = rProp.Handle;
1803 
1804             if ( !bHadTitle && rProp.Name == "Title" )
1805             {
1806                 // Set new title instead of original.
1807                 bHadTitle = true;
1808                 rValue.Value <<= rInfo.NewTitle;
1809             }
1810             else
1811                 rValue.Value
1812                     = xRow->getObject( n + 1,
1813                                        uno::Reference<
1814                                             container::XNameAccess >() );
1815 
1816             rValue.State = beans::PropertyState_DIRECT_VALUE;
1817 
1818             if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1819             {
1820                 // Add Additional Core Property.
1821                 try
1822                 {
1823                     xTarget->addProperty( rProp.Name,
1824                                           rProp.Attributes,
1825                                           rValue.Value );
1826                 }
1827                 catch ( beans::PropertyExistException const & )
1828                 {
1829                 }
1830                 catch ( beans::IllegalTypeException const & )
1831                 {
1832                 }
1833                 catch ( lang::IllegalArgumentException const & )
1834                 {
1835                 }
1836             }
1837         }
1838 
1839         // Set target values.
1840         xTarget->setPropertyValues( aValues, xEnv );
1841     }
1842 
1843 
1844     // 3) Commit (insert) child.
1845 
1846 
1847     xTarget->insert( xSource->getInputStream(), rInfo.NameClash, xEnv );
1848 
1849 
1850     // 4) Transfer (copy) children of source.
1851 
1852 
1853     if ( xSource->isFolder() )
1854     {
1855         uno::Reference< container::XEnumeration > xIter
1856             = xSource->getIterator();
1857         if ( xIter.is() )
1858         {
1859             while ( xIter->hasMoreElements() )
1860             {
1861                 try
1862                 {
1863                     uno::Reference< container::XNamed > xNamed;
1864                     xIter->nextElement() >>= xNamed;
1865 
1866                     if ( !xNamed.is() )
1867                     {
1868                         OSL_FAIL( "Content::transfer - Got no XNamed!" );
1869                         break;
1870                     }
1871 
1872                     OUString aName = xNamed->getName();
1873 
1874                     if ( aName.isEmpty() )
1875                     {
1876                         OSL_FAIL( "Content::transfer - Empty name!" );
1877                         break;
1878                     }
1879 
1880                     OUString aChildId = xId->getContentIdentifier();
1881                     if ( ( aChildId.lastIndexOf( '/' ) + 1 )
1882                                                 != aChildId.getLength() )
1883                         aChildId += "/";
1884 
1885                     aChildId += ::ucb_impl::urihelper::encodeSegment( aName );
1886 
1887                     ucb::TransferInfo aInfo;
1888                     aInfo.MoveData  = false;
1889                     aInfo.NewTitle.clear();
1890                     aInfo.SourceURL = aChildId;
1891                     aInfo.NameClash = rInfo.NameClash;
1892 
1893                     // Transfer child to target.
1894                     xTarget->transfer( aInfo, xEnv );
1895                 }
1896                 catch ( container::NoSuchElementException const & )
1897                 {
1898                 }
1899                 catch ( lang::WrappedTargetException const & )
1900                 {
1901                 }
1902             }
1903         }
1904     }
1905 
1906 
1907     // 5) Destroy source ( when moving only ) .
1908 
1909 
1910     if ( !rInfo.MoveData )
1911         return;
1912 
1913     xSource->destroy( true, xEnv );
1914 
1915     // Remove all persistent data of source and its children.
1916     if ( !xSource->removeData() )
1917     {
1918         uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1919         {
1920             {"Uri", uno::Any(xSource->m_xIdentifier->getContentIdentifier())}
1921         }));
1922         ucbhelper::cancelCommandExecution(
1923             ucb::IOErrorCode_CANT_WRITE,
1924             aArgs,
1925             xEnv,
1926             "Cannot remove persistent data of source object!",
1927             this );
1928         // Unreachable
1929     }
1930 
1931     // Remove own and all children's Additional Core Properties.
1932     xSource->removeAdditionalPropertySet();
1933 }
1934 
1935 
exchangeIdentity(const uno::Reference<ucb::XContentIdentifier> & xNewId)1936 bool Content::exchangeIdentity(
1937             const uno::Reference< ucb::XContentIdentifier >& xNewId )
1938 {
1939     if ( !xNewId.is() )
1940         return false;
1941 
1942     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1943 
1944     uno::Reference< ucb::XContent > xThis = this;
1945 
1946     // Already persistent?
1947     if ( m_eState != PERSISTENT )
1948     {
1949         OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
1950         return false;
1951     }
1952 
1953     // Exchange own identity.
1954 
1955     // Fail, if a content with given id already exists.
1956     PackageUri aNewUri( xNewId->getContentIdentifier() );
1957     if ( !hasData( aNewUri ) )
1958     {
1959         OUString aOldURL = m_xIdentifier->getContentIdentifier();
1960 
1961         aGuard.clear();
1962         if ( exchange( xNewId ) )
1963         {
1964             m_aUri = aNewUri;
1965             if ( isFolder() )
1966             {
1967                 // Process instantiated children...
1968 
1969                 ContentRefList aChildren;
1970                 queryChildren( aChildren );
1971 
1972                 for ( const auto& rChild : aChildren )
1973                 {
1974                     ContentRef xChild = rChild;
1975 
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(
1983                                         0,
1984                                         aOldURL.getLength(),
1985                                         xNewId->getContentIdentifier() );
1986                     uno::Reference< ucb::XContentIdentifier > xNewChildId
1987                         = new ::ucbhelper::ContentIdentifier( aNewChildURL );
1988 
1989                     if ( !xChild->exchangeIdentity( xNewChildId ) )
1990                         return false;
1991                 }
1992             }
1993             return true;
1994         }
1995     }
1996 
1997     OSL_FAIL( "Content::exchangeIdentity - Panic! Cannot exchange identity!" );
1998     return false;
1999 }
2000 
2001 
queryChildren(ContentRefList & rChildren)2002 void Content::queryChildren( ContentRefList& rChildren )
2003 {
2004     // Obtain a list with a snapshot of all currently instantiated contents
2005     // from provider and extract the contents which are direct children
2006     // of this content.
2007 
2008     ::ucbhelper::ContentRefList aAllContents;
2009     m_xProvider->queryExistingContents( aAllContents );
2010 
2011     OUString aURL = m_xIdentifier->getContentIdentifier();
2012 
2013     OSL_ENSURE( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ),
2014                 "Content::queryChildren - Invalid URL!" );
2015 
2016     aURL += "/";
2017 
2018     sal_Int32 nLen = aURL.getLength();
2019 
2020     for ( const auto& rContent : aAllContents )
2021     {
2022         ::ucbhelper::ContentImplHelperRef xChild = rContent;
2023         OUString aChildURL
2024             = xChild->getIdentifier()->getContentIdentifier();
2025 
2026         // Is aURL a prefix of aChildURL?
2027         if ( ( aChildURL.getLength() > nLen ) &&
2028              ( aChildURL.startsWith( aURL ) ) )
2029         {
2030             if ( aChildURL.indexOf( '/', nLen ) == -1 )
2031             {
2032                 // No further slashes. It's a child!
2033                 rChildren.emplace_back(
2034                         static_cast< Content * >( xChild.get() ) );
2035             }
2036         }
2037     }
2038 }
2039 
2040 
getPackage(const PackageUri & rURI)2041 uno::Reference< container::XHierarchicalNameAccess > Content::getPackage(
2042                                                 const PackageUri& rURI )
2043 {
2044     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2045 
2046     if ( rURI.getPackage() == m_aUri.getPackage() )
2047     {
2048         if ( !m_xPackage.is() )
2049             m_xPackage = m_pProvider->createPackage( m_aUri );
2050 
2051         return m_xPackage;
2052     }
2053 
2054     return m_pProvider->createPackage( rURI );
2055 }
2056 
2057 
getPackage()2058 uno::Reference< container::XHierarchicalNameAccess > Content::getPackage()
2059 {
2060     return getPackage( m_aUri );
2061 }
2062 
2063 
2064 // static
hasData(ContentProvider * pProvider,const PackageUri & rURI,uno::Reference<container::XHierarchicalNameAccess> & rxPackage)2065 bool Content::hasData(
2066             ContentProvider* pProvider,
2067             const PackageUri& rURI,
2068             uno::Reference< container::XHierarchicalNameAccess > & rxPackage )
2069 {
2070     rxPackage = pProvider->createPackage( rURI );
2071     return rxPackage->hasByHierarchicalName( rURI.getPath() );
2072 }
2073 
2074 
hasData(const PackageUri & rURI)2075 bool Content::hasData( const PackageUri& rURI )
2076 {
2077     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2078 
2079     uno::Reference< container::XHierarchicalNameAccess > xPackage;
2080     if ( rURI.getPackage() == m_aUri.getPackage() )
2081     {
2082         xPackage = getPackage();
2083         return xPackage->hasByHierarchicalName( rURI.getPath() );
2084     }
2085 
2086     return hasData( m_pProvider, rURI, xPackage );
2087 }
2088 
2089 
2090 //static
loadData(ContentProvider * pProvider,const PackageUri & rURI,ContentProperties & rProps,uno::Reference<container::XHierarchicalNameAccess> & rxPackage)2091 bool Content::loadData(
2092             ContentProvider* pProvider,
2093             const PackageUri& rURI,
2094             ContentProperties& rProps,
2095             uno::Reference< container::XHierarchicalNameAccess > & rxPackage )
2096 {
2097     rxPackage = pProvider->createPackage( rURI );
2098 
2099     if ( rURI.isRootFolder() )
2100     {
2101         // Properties available only from package
2102         uno::Reference< beans::XPropertySet > xPackagePropSet(
2103                                                 rxPackage, uno::UNO_QUERY );
2104 
2105         OSL_ENSURE( xPackagePropSet.is(),
2106                     "Content::loadData - "
2107                     "Got no XPropertySet interface from package!" );
2108 
2109         if ( xPackagePropSet.is() )
2110         {
2111             // HasEncryptedEntries (only available at root folder)
2112             try
2113             {
2114                 uno::Any aHasEncryptedEntries
2115                     = xPackagePropSet->getPropertyValue( "HasEncryptedEntries" );
2116                 if ( !( aHasEncryptedEntries >>= rProps.bHasEncryptedEntries ) )
2117                 {
2118                     OSL_FAIL( "Content::loadData - "
2119                                 "Got no HasEncryptedEntries value!" );
2120                     return false;
2121                 }
2122             }
2123             catch ( beans::UnknownPropertyException const & )
2124             {
2125                 OSL_FAIL( "Content::loadData - "
2126                             "Got no HasEncryptedEntries value!" );
2127                 return false;
2128             }
2129             catch ( lang::WrappedTargetException const & )
2130             {
2131                 OSL_FAIL( "Content::loadData - "
2132                             "Got no HasEncryptedEntries value!" );
2133                 return false;
2134             }
2135         }
2136     }
2137 
2138     if ( !rxPackage->hasByHierarchicalName( rURI.getPath() ) )
2139         return false;
2140 
2141     try
2142     {
2143         uno::Any aEntry = rxPackage->getByHierarchicalName( rURI.getPath() );
2144         if ( aEntry.hasValue() )
2145         {
2146             uno::Reference< beans::XPropertySet > xPropSet;
2147             aEntry >>= xPropSet;
2148 
2149             if ( !xPropSet.is() )
2150             {
2151                 OSL_FAIL( "Content::loadData - Got no XPropertySet interface!" );
2152                 return false;
2153             }
2154 
2155             // Title
2156             rProps.aTitle = rURI.getName();
2157 
2158             // MediaType
2159             try
2160             {
2161                 uno::Any aMediaType = xPropSet->getPropertyValue("MediaType");
2162                 if ( !( aMediaType >>= rProps.aMediaType ) )
2163                 {
2164                     OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2165                     return false;
2166                 }
2167             }
2168             catch ( beans::UnknownPropertyException const & )
2169             {
2170                 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2171                 return false;
2172             }
2173             catch ( lang::WrappedTargetException const & )
2174             {
2175                 OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2176                 return false;
2177             }
2178 
2179             uno::Reference< container::XEnumerationAccess > xEnumAccess;
2180             aEntry >>= xEnumAccess;
2181 
2182             // ContentType / IsFolder / IsDocument
2183             if ( xEnumAccess.is() )
2184             {
2185                 // folder
2186                 rProps.aContentType = getContentType( rURI.getScheme(), true );
2187                 rProps.bIsDocument = false;
2188                 rProps.bIsFolder = true;
2189             }
2190             else
2191             {
2192                 // stream
2193                 rProps.aContentType = getContentType( rURI.getScheme(), false );
2194                 rProps.bIsDocument = true;
2195                 rProps.bIsFolder = false;
2196             }
2197 
2198             if ( rProps.bIsDocument )
2199             {
2200                 // Size ( only available for streams )
2201                 try
2202                 {
2203                     uno::Any aSize = xPropSet->getPropertyValue("Size");
2204                     if ( !( aSize >>= rProps.nSize ) )
2205                     {
2206                         OSL_FAIL( "Content::loadData - Got no Size value!" );
2207                         return false;
2208                     }
2209                 }
2210                 catch ( beans::UnknownPropertyException const & )
2211                 {
2212                     OSL_FAIL( "Content::loadData - Got no Size value!" );
2213                     return false;
2214                 }
2215                 catch ( lang::WrappedTargetException const & )
2216                 {
2217                     OSL_FAIL( "Content::loadData - Got no Size value!" );
2218                     return false;
2219                 }
2220 
2221                 // Compressed ( only available for streams )
2222                 try
2223                 {
2224                     uno::Any aCompressed = xPropSet->getPropertyValue("Compressed");
2225                     if ( !( aCompressed >>= rProps.bCompressed ) )
2226                     {
2227                         OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2228                         return false;
2229                     }
2230                 }
2231                 catch ( beans::UnknownPropertyException const & )
2232                 {
2233                     OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2234                     return false;
2235                 }
2236                 catch ( lang::WrappedTargetException const & )
2237                 {
2238                     OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2239                     return false;
2240                 }
2241 
2242                 // Encrypted ( only available for streams )
2243                 try
2244                 {
2245                     uno::Any aEncrypted = xPropSet->getPropertyValue("Encrypted");
2246                     if ( !( aEncrypted >>= rProps.bEncrypted ) )
2247                     {
2248                         OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2249                         return false;
2250                     }
2251                 }
2252                 catch ( beans::UnknownPropertyException const & )
2253                 {
2254                     OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2255                     return false;
2256                 }
2257                 catch ( lang::WrappedTargetException const & )
2258                 {
2259                     OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2260                     return false;
2261                 }
2262             }
2263             return true;
2264         }
2265     }
2266     catch ( container::NoSuchElementException const & )
2267     {
2268         // getByHierarchicalName
2269     }
2270 
2271     return false;
2272 }
2273 
2274 
renameData(const uno::Reference<ucb::XContentIdentifier> & xOldId,const uno::Reference<ucb::XContentIdentifier> & xNewId)2275 void Content::renameData(
2276             const uno::Reference< ucb::XContentIdentifier >& xOldId,
2277             const uno::Reference< ucb::XContentIdentifier >& xNewId )
2278 {
2279     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2280 
2281     PackageUri aURI( xOldId->getContentIdentifier() );
2282     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage(
2283                                                                         aURI );
2284 
2285     if ( !xNA->hasByHierarchicalName( aURI.getPath() ) )
2286         return;
2287 
2288     try
2289     {
2290         uno::Any aEntry = xNA->getByHierarchicalName( aURI.getPath() );
2291         uno::Reference< container::XNamed > xNamed;
2292         aEntry >>= xNamed;
2293 
2294         if ( !xNamed.is() )
2295         {
2296             OSL_FAIL( "Content::renameData - Got no XNamed interface!" );
2297             return;
2298         }
2299 
2300         PackageUri aNewURI( xNewId->getContentIdentifier() );
2301 
2302         // No success indicator!? No return value / exceptions specified.
2303         xNamed->setName( aNewURI.getName() );
2304     }
2305     catch ( container::NoSuchElementException const & )
2306     {
2307         // getByHierarchicalName
2308     }
2309 }
2310 
2311 
storeData(const uno::Reference<io::XInputStream> & xStream)2312 bool Content::storeData( const uno::Reference< io::XInputStream >& xStream )
2313 {
2314     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2315 
2316     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2317 
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!" );
2323 
2324     if ( !xPackagePropSet.is() )
2325         return false;
2326 
2327     if ( m_nModifiedProps & ENCRYPTIONKEY_MODIFIED )
2328     {
2329         if ( m_aUri.isRootFolder() )
2330         {
2331             // Property available only from package and from streams (see below)
2332             try
2333             {
2334                 xPackagePropSet->setPropertyValue(
2335                         "EncryptionKey",
2336                         uno::makeAny( m_aProps.aEncryptionKey ) );
2337                 m_nModifiedProps &= ~ENCRYPTIONKEY_MODIFIED;
2338             }
2339             catch ( beans::UnknownPropertyException const & )
2340             {
2341                 // setPropertyValue
2342             }
2343             catch ( beans::PropertyVetoException const & )
2344             {
2345                 // setPropertyValue
2346             }
2347             catch ( lang::IllegalArgumentException const & )
2348             {
2349                 // setPropertyValue
2350             }
2351             catch ( lang::WrappedTargetException const & )
2352             {
2353                 // setPropertyValue
2354             }
2355         }
2356     }
2357 
2358     if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2359     {
2360 //        if ( !bCreate )
2361 //            return sal_True;
2362 
2363         try
2364         {
2365             // Create new resource...
2366             uno::Reference< lang::XSingleServiceFactory > xFac(
2367                                                     xNA, uno::UNO_QUERY );
2368             if ( !xFac.is() )
2369             {
2370                 OSL_FAIL( "Content::storeData - "
2371                             "Got no XSingleServiceFactory interface!" );
2372                 return false;
2373             }
2374 
2375             uno::Sequence< uno::Any > aArgs( 1 );
2376             aArgs[ 0 ] <<= isFolder();
2377 
2378             uno::Reference< uno::XInterface > xNew
2379                 = xFac->createInstanceWithArguments( aArgs );
2380 
2381             if ( !xNew.is() )
2382             {
2383                 OSL_FAIL( "Content::storeData - createInstance failed!" );
2384                 return false;
2385             }
2386 
2387             PackageUri aParentUri( getParentURL() );
2388             uno::Any aEntry
2389                 = xNA->getByHierarchicalName( aParentUri.getPath() );
2390             uno::Reference< container::XNameContainer > xParentContainer;
2391             aEntry >>= xParentContainer;
2392 
2393             if ( !xParentContainer.is() )
2394             {
2395                 OSL_FAIL( "Content::storeData - "
2396                             "Got no XNameContainer interface!" );
2397                 return false;
2398             }
2399 
2400             xParentContainer->insertByName( m_aProps.aTitle,
2401                                             uno::makeAny( xNew ) );
2402         }
2403         catch ( lang::IllegalArgumentException const & )
2404         {
2405             // insertByName
2406             OSL_FAIL( "Content::storeData - insertByName failed!" );
2407             return false;
2408         }
2409         catch ( uno::RuntimeException const & )
2410         {
2411             throw;
2412         }
2413         catch ( container::ElementExistException const & )
2414         {
2415             // insertByName
2416             OSL_FAIL( "Content::storeData - insertByName failed!" );
2417             return false;
2418         }
2419         catch ( lang::WrappedTargetException const & )
2420         {
2421             // insertByName
2422             OSL_FAIL( "Content::storeData - insertByName failed!" );
2423             return false;
2424         }
2425         catch ( container::NoSuchElementException const & )
2426         {
2427             // getByHierarchicalName
2428             OSL_FAIL( "Content::storeData - getByHierarchicalName failed!" );
2429             return false;
2430         }
2431         catch ( uno::Exception const & )
2432         {
2433             // createInstanceWithArguments
2434             OSL_FAIL( "Content::storeData - Error!" );
2435             return false;
2436         }
2437     }
2438 
2439     if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2440         return false;
2441 
2442     try
2443     {
2444         uno::Reference< beans::XPropertySet > xPropSet;
2445         xNA->getByHierarchicalName( m_aUri.getPath() ) >>= xPropSet;
2446 
2447         if ( !xPropSet.is() )
2448         {
2449             OSL_FAIL( "Content::storeData - Got no XPropertySet interface!" );
2450             return false;
2451         }
2452 
2453 
2454         // Store property values...
2455 
2456 
2457         if ( m_nModifiedProps & MEDIATYPE_MODIFIED )
2458         {
2459             xPropSet->setPropertyValue(
2460                                 "MediaType",
2461                                 uno::makeAny( m_aProps.aMediaType ) );
2462             m_nModifiedProps &= ~MEDIATYPE_MODIFIED;
2463         }
2464 
2465         if ( m_nModifiedProps & COMPRESSED_MODIFIED )
2466         {
2467             if ( !isFolder() )
2468                 xPropSet->setPropertyValue(
2469                                 "Compressed",
2470                                 uno::makeAny( m_aProps.bCompressed ) );
2471 
2472             m_nModifiedProps &= ~COMPRESSED_MODIFIED;
2473         }
2474 
2475         if ( m_nModifiedProps & ENCRYPTED_MODIFIED )
2476         {
2477             if ( !isFolder() )
2478                 xPropSet->setPropertyValue(
2479                                 "Encrypted",
2480                                 uno::makeAny( m_aProps.bEncrypted ) );
2481 
2482             m_nModifiedProps &= ~ENCRYPTED_MODIFIED;
2483         }
2484 
2485         if ( m_nModifiedProps & ENCRYPTIONKEY_MODIFIED )
2486         {
2487             if ( !isFolder() )
2488                 xPropSet->setPropertyValue(
2489                             "EncryptionKey",
2490                             uno::makeAny( m_aProps.aEncryptionKey ) );
2491 
2492             m_nModifiedProps &= ~ENCRYPTIONKEY_MODIFIED;
2493         }
2494 
2495 
2496         // Store data stream...
2497 
2498 
2499         if ( xStream.is() && !isFolder() )
2500         {
2501             uno::Reference< io::XActiveDataSink > xSink(
2502                                                 xPropSet, uno::UNO_QUERY );
2503 
2504             if ( !xSink.is() )
2505             {
2506                 OSL_FAIL( "Content::storeData - "
2507                             "Got no XActiveDataSink interface!" );
2508                 return false;
2509             }
2510 
2511             xSink->setInputStream( xStream );
2512         }
2513 
2514         return true;
2515     }
2516     catch ( container::NoSuchElementException const & )
2517     {
2518         // getByHierarchicalName
2519     }
2520     catch ( beans::UnknownPropertyException const & )
2521     {
2522         // setPropertyValue
2523     }
2524     catch ( beans::PropertyVetoException const & )
2525     {
2526         // setPropertyValue
2527     }
2528     catch ( lang::IllegalArgumentException const & )
2529     {
2530         // setPropertyValue
2531     }
2532     catch ( lang::WrappedTargetException const & )
2533     {
2534         // setPropertyValue
2535     }
2536 
2537     OSL_FAIL( "Content::storeData - Error!" );
2538     return false;
2539 }
2540 
2541 
removeData()2542 bool Content::removeData()
2543 {
2544     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2545 
2546     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2547 
2548     PackageUri aParentUri( getParentURL() );
2549     if ( !xNA->hasByHierarchicalName( aParentUri.getPath() ) )
2550         return false;
2551 
2552     try
2553     {
2554         uno::Any aEntry = xNA->getByHierarchicalName( aParentUri.getPath() );
2555         uno::Reference< container::XNameContainer > xContainer;
2556         aEntry >>= xContainer;
2557 
2558         if ( !xContainer.is() )
2559         {
2560             OSL_FAIL( "Content::removeData - "
2561                         "Got no XNameContainer interface!" );
2562             return false;
2563         }
2564 
2565         xContainer->removeByName( m_aUri.getName() );
2566         return true;
2567     }
2568     catch ( container::NoSuchElementException const & )
2569     {
2570         // getByHierarchicalName, removeByName
2571     }
2572     catch ( lang::WrappedTargetException const & )
2573     {
2574         // removeByName
2575     }
2576 
2577     OSL_FAIL( "Content::removeData - Error!" );
2578     return false;
2579 }
2580 
2581 
flushData()2582 bool Content::flushData()
2583 {
2584     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2585 
2586     // Note: XChangesBatch is only implemented by the package itself, not
2587     //       by the single entries. Maybe this has to change...
2588 
2589     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2590 
2591     uno::Reference< util::XChangesBatch > xBatch( xNA, uno::UNO_QUERY );
2592     if ( !xBatch.is() )
2593     {
2594         OSL_FAIL( "Content::flushData - Got no XChangesBatch interface!" );
2595         return false;
2596     }
2597 
2598     try
2599     {
2600         xBatch->commitChanges();
2601         return true;
2602     }
2603     catch ( lang::WrappedTargetException const & )
2604     {
2605     }
2606 
2607     OSL_FAIL( "Content::flushData - Error!" );
2608     return false;
2609 }
2610 
2611 
getInputStream()2612 uno::Reference< io::XInputStream > Content::getInputStream()
2613 {
2614     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2615 
2616     uno::Reference< io::XInputStream > xStream;
2617     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2618 
2619     if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2620         return xStream;
2621 
2622     try
2623     {
2624         uno::Any aEntry = xNA->getByHierarchicalName( m_aUri.getPath() );
2625         uno::Reference< io::XActiveDataSink > xSink;
2626         aEntry >>= xSink;
2627 
2628         if ( !xSink.is() )
2629         {
2630             OSL_FAIL( "Content::getInputStream - "
2631                         "Got no XActiveDataSink interface!" );
2632             return xStream;
2633         }
2634 
2635         xStream = xSink->getInputStream();
2636 
2637         OSL_ENSURE( xStream.is(),
2638                     "Content::getInputStream - Got no stream!" );
2639     }
2640     catch ( container::NoSuchElementException const & )
2641     {
2642         // getByHierarchicalName
2643     }
2644 
2645     return xStream;
2646 }
2647 
2648 
getIterator()2649 uno::Reference< container::XEnumeration > Content::getIterator()
2650 {
2651     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2652 
2653     uno::Reference< container::XEnumeration > xIter;
2654     uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2655 
2656     if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2657         return xIter;
2658 
2659     try
2660     {
2661         uno::Any aEntry = xNA->getByHierarchicalName( m_aUri.getPath() );
2662         uno::Reference< container::XEnumerationAccess > xIterFac;
2663         aEntry >>= xIterFac;
2664 
2665         if ( !xIterFac.is() )
2666         {
2667             OSL_FAIL( "Content::getIterator - "
2668                         "Got no XEnumerationAccess interface!" );
2669             return xIter;
2670         }
2671 
2672         xIter = xIterFac->createEnumeration();
2673 
2674         OSL_ENSURE( xIter.is(),
2675                     "Content::getIterator - Got no iterator!" );
2676     }
2677     catch ( container::NoSuchElementException const & )
2678     {
2679         // getByHierarchicalName
2680     }
2681 
2682     return xIter;
2683 }
2684 
2685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2686