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