LibreOffice Module ucb (master) 1
tdoc_content.cxx
Go to the documentation of this file.
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 *************************************************************************/
26
27#include <sal/config.h>
28
29#include <string_view>
30
31#include <o3tl/string_view.hxx>
32#include <tools/diagnose_ex.h>
33#include <rtl/ustrbuf.hxx>
34#include <com/sun/star/beans/IllegalTypeException.hpp>
35#include <com/sun/star/beans/PropertyAttribute.hpp>
36#include <com/sun/star/beans/XPropertySet.hpp>
37#include <com/sun/star/embed/InvalidStorageException.hpp>
38#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
39#include <com/sun/star/embed/XTransactedObject.hpp>
40#include <com/sun/star/io/BufferSizeExceededException.hpp>
41#include <com/sun/star/io/IOException.hpp>
42#include <com/sun/star/io/NotConnectedException.hpp>
43#include <com/sun/star/io/XActiveDataSink.hpp>
44#include <com/sun/star/io/XActiveDataStreamer.hpp>
45#include <com/sun/star/lang/IllegalAccessException.hpp>
46#include <com/sun/star/packages/WrongPasswordException.hpp>
47#include <com/sun/star/task/DocumentPasswordRequest.hpp>
48#include <com/sun/star/task/XInteractionPassword.hpp>
49#include <com/sun/star/ucb/CommandFailedException.hpp>
50#include <com/sun/star/ucb/ContentAction.hpp>
51#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
52#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
53#include <com/sun/star/ucb/InsertCommandArgument.hpp>
54#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
55#include <com/sun/star/ucb/MissingInputStreamException.hpp>
56#include <com/sun/star/ucb/NameClash.hpp>
57#include <com/sun/star/ucb/NameClashException.hpp>
58#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
59#include <com/sun/star/ucb/OpenMode.hpp>
60#include <com/sun/star/ucb/TransferInfo.hpp>
61#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
62#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
63#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
64#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
65#include <com/sun/star/ucb/XCommandInfo.hpp>
66#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
67
73#include <ucbhelper/macros.hxx>
74
75#include "tdoc_content.hxx"
76#include "tdoc_resultset.hxx"
78
79#include "../inc/urihelper.hxx"
80
81using namespace com::sun::star;
82using namespace tdoc_ucp;
83
84
85static ContentType lcl_getContentType( std::u16string_view rType )
86{
87 if ( rType == TDOC_ROOT_CONTENT_TYPE )
88 return ROOT;
89 else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
90 return DOCUMENT;
91 else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
92 return FOLDER;
93 else if ( rType == TDOC_STREAM_CONTENT_TYPE )
94 return STREAM;
95 else
96 {
97 OSL_FAIL( "Content::Content - unsupported content type string" );
98 return STREAM;
99 }
100}
101
102
103// Content Implementation.
104
105
106// static ( "virtual" ctor )
107rtl::Reference<Content> Content::create(
108 const uno::Reference< uno::XComponentContext >& rxContext,
109 ContentProvider* pProvider,
110 const uno::Reference< ucb::XContentIdentifier >& Identifier )
111{
112 // Fail, if resource does not exist.
113 ContentProperties aProps;
114 if ( !Content::loadData( pProvider,
115 Uri( Identifier->getContentIdentifier() ),
116 aProps ) )
117 return nullptr;
118
119 return new Content( rxContext, pProvider, Identifier, aProps );
120}
121
122
123// static ( "virtual" ctor )
125 const uno::Reference< uno::XComponentContext >& rxContext,
126 ContentProvider* pProvider,
127 const uno::Reference< ucb::XContentIdentifier >& Identifier,
128 const ucb::ContentInfo& Info )
129{
130 if ( Info.Type.isEmpty() )
131 return nullptr;
132
134 {
135 OSL_FAIL( "Content::create - unsupported content type!" );
136 return nullptr;
137 }
138
139 return new Content( rxContext, pProvider, Identifier, Info );
140}
141
142
144 const uno::Reference< uno::XComponentContext > & rxContext,
145 ContentProvider * pProvider,
146 const uno::Reference< ucb::XContentIdentifier > & Identifier,
147 const ContentProperties & rProps )
148: ContentImplHelper( rxContext, pProvider, Identifier ),
149 m_aProps( rProps ),
150 m_eState( PERSISTENT ),
151 m_pProvider( pProvider )
152{
153}
154
155
156// ctor for a content just created via XContentCreator::createNewContent()
157Content::Content(
158 const uno::Reference< uno::XComponentContext >& rxContext,
159 ContentProvider* pProvider,
160 const uno::Reference< ucb::XContentIdentifier >& Identifier,
161 const ucb::ContentInfo& Info )
162 : ContentImplHelper( rxContext, pProvider, Identifier ),
163 m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
164 m_eState( TRANSIENT ),
165 m_pProvider( pProvider )
166{
167}
168
169
170// virtual
171Content::~Content()
172{
173}
174
175
176// XInterface methods.
177
178
179// virtual
180void SAL_CALL Content::acquire()
181 noexcept
182{
183 ContentImplHelper::acquire();
184}
185
186
187// virtual
188void SAL_CALL Content::release()
189 noexcept
190{
191 ContentImplHelper::release();
192}
193
194
195// virtual
196uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
197{
198 uno::Any aRet = ContentImplHelper::queryInterface( rType );
199
200 if ( !aRet.hasValue() )
201 {
203 rType, static_cast< ucb::XContentCreator * >( this ) );
204 if ( aRet.hasValue() )
205 {
206 if ( !m_aProps.isContentCreator() )
207 return uno::Any();
208 }
209 }
210
211 return aRet;
212}
213
214
215// XTypeProvider methods.
216
217
219
220
221// virtual
222uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
223{
225 {
226 static cppu::OTypeCollection s_aFolderTypes(
227 CPPU_TYPE_REF( lang::XTypeProvider ),
228 CPPU_TYPE_REF( lang::XServiceInfo ),
229 CPPU_TYPE_REF( lang::XComponent ),
230 CPPU_TYPE_REF( ucb::XContent ),
231 CPPU_TYPE_REF( ucb::XCommandProcessor ),
232 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
233 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
234 CPPU_TYPE_REF( beans::XPropertyContainer ),
235 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
236 CPPU_TYPE_REF( container::XChild ),
237 CPPU_TYPE_REF( ucb::XContentCreator ) );
238
239 return s_aFolderTypes.getTypes();
240 }
241 else
242 {
243 static cppu::OTypeCollection s_aDocumentTypes(
244 CPPU_TYPE_REF( lang::XTypeProvider ),
245 CPPU_TYPE_REF( lang::XServiceInfo ),
246 CPPU_TYPE_REF( lang::XComponent ),
247 CPPU_TYPE_REF( ucb::XContent ),
248 CPPU_TYPE_REF( ucb::XCommandProcessor ),
249 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
250 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
251 CPPU_TYPE_REF( beans::XPropertyContainer ),
252 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
253 CPPU_TYPE_REF( container::XChild ) );
254
255 return s_aDocumentTypes.getTypes();
256 }
257}
258
259
260// XServiceInfo methods.
261
262
263// virtual
265{
266 return "com.sun.star.comp.ucb.TransientDocumentsContent";
267}
268
269
270// virtual
271uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
272{
273 osl::Guard< osl::Mutex > aGuard( m_aMutex );
274
275 uno::Sequence< OUString > aSNS( 1 );
276
277 if ( m_aProps.getType() == STREAM )
278 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsStreamContent";
279 else if ( m_aProps.getType() == FOLDER )
280 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsFolderContent";
281 else if ( m_aProps.getType() == DOCUMENT )
282 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsDocumentContent";
283 else
284 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsRootContent";
285
286 return aSNS;
287}
288
289
290// XContent methods.
291
292
293// virtual
294OUString SAL_CALL Content::getContentType()
295{
296 osl::Guard< osl::Mutex > aGuard( m_aMutex );
297 return m_aProps.getContentType();
298}
299
300
301// virtual
302uno::Reference< ucb::XContentIdentifier > SAL_CALL
304{
305 {
306 osl::Guard< osl::Mutex > aGuard( m_aMutex );
307
308 // Transient?
309 if ( m_eState == TRANSIENT )
310 {
311 // Transient contents have no identifier.
312 return uno::Reference< ucb::XContentIdentifier >();
313 }
314 }
315 return ContentImplHelper::getIdentifier();
316}
317
318
319// XCommandProcessor methods.
320
321
322// virtual
324 const ucb::Command& aCommand,
325 sal_Int32 /*CommandId*/,
326 const uno::Reference< ucb::XCommandEnvironment >& Environment )
327{
328 uno::Any aRet;
329
330 if ( aCommand.Name == "getPropertyValues" )
331 {
332
333 // getPropertyValues
334
335
336 uno::Sequence< beans::Property > Properties;
337 if ( !( aCommand.Argument >>= Properties ) )
338 {
340 uno::Any( lang::IllegalArgumentException(
341 "Wrong argument type!",
342 static_cast< cppu::OWeakObject * >( this ),
343 -1 ) ),
344 Environment );
345 // Unreachable
346 }
347
348 aRet <<= getPropertyValues( Properties );
349 }
350 else if ( aCommand.Name == "setPropertyValues" )
351 {
352
353 // setPropertyValues
354
355
356 uno::Sequence< beans::PropertyValue > aProperties;
357 if ( !( aCommand.Argument >>= aProperties ) )
358 {
360 uno::Any( lang::IllegalArgumentException(
361 "Wrong argument type!",
362 static_cast< cppu::OWeakObject * >( this ),
363 -1 ) ),
364 Environment );
365 // Unreachable
366 }
367
368 if ( !aProperties.hasElements() )
369 {
371 uno::Any( lang::IllegalArgumentException(
372 "No properties!",
373 static_cast< cppu::OWeakObject * >( this ),
374 -1 ) ),
375 Environment );
376 // Unreachable
377 }
378
379 aRet <<= setPropertyValues( aProperties, Environment );
380 }
381 else if ( aCommand.Name == "getPropertySetInfo" )
382 {
383
384 // getPropertySetInfo
385
386
387 aRet <<= getPropertySetInfo( Environment );
388 }
389 else if ( aCommand.Name == "getCommandInfo" )
390 {
391
392 // getCommandInfo
393
394
395 aRet <<= getCommandInfo( Environment );
396 }
397 else if ( aCommand.Name == "open" )
398 {
399
400 // open
401
402
403 ucb::OpenCommandArgument2 aOpenCommand;
404 if ( !( aCommand.Argument >>= aOpenCommand ) )
405 {
407 uno::Any( lang::IllegalArgumentException(
408 "Wrong argument type!",
409 static_cast< cppu::OWeakObject * >( this ),
410 -1 ) ),
411 Environment );
412 // Unreachable
413 }
414
415 aRet = open( aOpenCommand, Environment );
416 }
417 else if ( aCommand.Name == "insert" )
418 {
419
420 // insert ( Supported by folders and streams only )
421
422
424 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
425 {
427 uno::Any( ucb::UnsupportedCommandException(
428 "insert command only supported by "
429 "folders and streams!",
430 static_cast< cppu::OWeakObject * >( this ) ) ),
431 Environment );
432 // Unreachable
433 }
434
435 if ( eType == STREAM )
436 {
437 Uri aUri( m_xIdentifier->getContentIdentifier() );
438 Uri aParentUri( aUri.getParentUri() );
439 if ( aParentUri.isDocument() )
440 {
442 uno::Any( ucb::UnsupportedCommandException(
443 "insert command not supported by "
444 "streams that are direct children "
445 "of document root!",
446 static_cast< cppu::OWeakObject * >(
447 this ) ) ),
448 Environment );
449 // Unreachable
450 }
451 }
452
453 ucb::InsertCommandArgument aArg;
454 if ( !( aCommand.Argument >>= aArg ) )
455 {
457 uno::Any( lang::IllegalArgumentException(
458 "Wrong argument type!",
459 static_cast< cppu::OWeakObject * >( this ),
460 -1 ) ),
461 Environment );
462 // Unreachable
463 }
464
465 sal_Int32 nNameClash = aArg.ReplaceExisting
466 ? ucb::NameClash::OVERWRITE
467 : ucb::NameClash::ERROR;
468 insert( aArg.Data, nNameClash, Environment );
469 }
470 else if ( aCommand.Name == "delete" )
471 {
472
473 // delete ( Supported by folders and streams only )
474
475
476 {
477 osl::MutexGuard aGuard( m_aMutex );
478
480 if ( ( eType != FOLDER ) && ( eType != STREAM ) )
481 {
483 uno::Any( ucb::UnsupportedCommandException(
484 "delete command only supported by "
485 "folders and streams!",
486 static_cast< cppu::OWeakObject * >(
487 this ) ) ),
488 Environment );
489 // Unreachable
490 }
491 }
492
493 bool bDeletePhysical = false;
494 aCommand.Argument >>= bDeletePhysical;
495 destroy( bDeletePhysical, Environment );
496
497 // Remove own and all children's persistent data.
498 if ( !removeData() )
499 {
500 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
501 {
502 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
503 }));
505 ucb::IOErrorCode_CANT_WRITE,
506 aArgs,
507 Environment,
508 "Cannot remove persistent data!",
509 this );
510 // Unreachable
511 }
512
513 // Remove own and all children's Additional Core Properties.
515 }
516 else if ( aCommand.Name == "transfer" )
517 {
518
519 // transfer ( Supported by document and folders only )
520
521
522 {
523 osl::MutexGuard aGuard( m_aMutex );
524
526 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
527 {
529 uno::Any( ucb::UnsupportedCommandException(
530 "transfer command only supported "
531 "by folders and documents!",
532 static_cast< cppu::OWeakObject * >(
533 this ) ) ),
534 Environment );
535 // Unreachable
536 }
537 }
538
539 ucb::TransferInfo aInfo;
540 if ( !( aCommand.Argument >>= aInfo ) )
541 {
542 OSL_FAIL( "Wrong argument type!" );
544 uno::Any( lang::IllegalArgumentException(
545 "Wrong argument type!",
546 static_cast< cppu::OWeakObject * >( this ),
547 -1 ) ),
548 Environment );
549 // Unreachable
550 }
551
552 transfer( aInfo, Environment );
553 }
554 else if ( aCommand.Name == "createNewContent" )
555 {
556
557 // createNewContent ( Supported by document and folders only )
558
559
560 {
561 osl::MutexGuard aGuard( m_aMutex );
562
564 if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
565 {
567 uno::Any( ucb::UnsupportedCommandException(
568 "createNewContent command only "
569 "supported by folders and "
570 "documents!",
571 static_cast< cppu::OWeakObject * >(
572 this ) ) ),
573 Environment );
574 // Unreachable
575 }
576 }
577
578 ucb::ContentInfo aInfo;
579 if ( !( aCommand.Argument >>= aInfo ) )
580 {
581 OSL_FAIL( "Wrong argument type!" );
583 uno::Any( lang::IllegalArgumentException(
584 "Wrong argument type!",
585 static_cast< cppu::OWeakObject * >( this ),
586 -1 ) ),
587 Environment );
588 // Unreachable
589 }
590
591 aRet <<= createNewContent( aInfo );
592 }
593 else
594 {
595
596 // Unsupported command
597
598
600 uno::Any( ucb::UnsupportedCommandException(
601 OUString(),
602 static_cast< cppu::OWeakObject * >( this ) ) ),
603 Environment );
604 // Unreachable
605 }
606
607 return aRet;
608}
609
610
611// virtual
612void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
613{
614}
615
616
617// XContentCreator methods.
618
619
620// virtual
621uno::Sequence< ucb::ContentInfo > SAL_CALL
623{
625}
626
627
628// virtual
629uno::Reference< ucb::XContent > SAL_CALL
630Content::createNewContent( const ucb::ContentInfo& Info )
631{
633 {
634 osl::Guard< osl::Mutex > aGuard( m_aMutex );
635
636 if ( Info.Type.isEmpty() )
637 return uno::Reference< ucb::XContent >();
638
639 bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
640
641 // streams cannot be created as direct children of document root
642 if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
643 {
644 OSL_FAIL( "Content::createNewContent - streams cannot be "
645 "created as direct children of document root!" );
646 return uno::Reference< ucb::XContent >();
647 }
648 if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
649 {
650 OSL_FAIL( "Content::createNewContent - unsupported type!" );
651 return uno::Reference< ucb::XContent >();
652 }
653
654 OUString aURL = m_xIdentifier->getContentIdentifier();
655
656 OSL_ENSURE( !aURL.isEmpty(),
657 "Content::createNewContent - empty identifier!" );
658
659 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
660 aURL += "/";
661
662 if ( bCreateFolder )
663 aURL += "New_Folder";
664 else
665 aURL += "New_Stream";
666
667 uno::Reference< ucb::XContentIdentifier > xId
668 = new ::ucbhelper::ContentIdentifier( aURL );
669
670 return create( m_xContext, m_pProvider, xId, Info );
671 }
672 else
673 {
674 OSL_FAIL( "createNewContent called on non-contentcreator object!" );
675 return uno::Reference< ucb::XContent >();
676 }
677}
678
679
680// virtual
682{
683 osl::Guard< osl::Mutex > aGuard( m_aMutex );
684 Uri aUri( m_xIdentifier->getContentIdentifier() );
685 return aUri.getParentUri();
686}
687
688
689uno::Reference< ucb::XContentIdentifier >
690Content::makeNewIdentifier( const OUString& rTitle )
691{
692 osl::Guard< osl::Mutex > aGuard( m_aMutex );
693
694 // Assemble new content identifier...
695 Uri aUri( m_xIdentifier->getContentIdentifier() );
696 OUString aNewURL = aUri.getParentUri() + ::ucb_impl::urihelper::encodeSegment( rTitle );
697
698 return
699 uno::Reference< ucb::XContentIdentifier >(
700 new ::ucbhelper::ContentIdentifier( aNewURL ) );
701}
702
703
705{
706 osl::Guard< osl::Mutex > aGuard( m_aMutex );
707
708 // Only folders (root, documents, folders) have children.
709 if ( !m_aProps.getIsFolder() )
710 return;
711
712 // Obtain a list with a snapshot of all currently instantiated contents
713 // from provider and extract the contents which are direct children
714 // of this content.
715
716 ::ucbhelper::ContentRefList aAllContents;
717 m_xProvider->queryExistingContents( aAllContents );
718
719 OUString aURL = m_xIdentifier->getContentIdentifier();
720 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
721
722 if ( nURLPos != ( aURL.getLength() - 1 ) )
723 {
724 // No trailing slash found. Append.
725 aURL += "/";
726 }
727
728 sal_Int32 nLen = aURL.getLength();
729
730 for ( const auto& rContent : aAllContents )
731 {
732 ::ucbhelper::ContentImplHelperRef xChild = rContent;
733 OUString aChildURL
734 = xChild->getIdentifier()->getContentIdentifier();
735
736 // Is aURL a prefix of aChildURL?
737 if ( ( aChildURL.getLength() > nLen ) &&
738 ( aChildURL.startsWith( aURL ) ) )
739 {
740 sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
741
742 if ( ( nPos == -1 ) ||
743 ( nPos == ( aChildURL.getLength() - 1 ) ) )
744 {
745 // No further slashes / only a final slash. It's a child!
746 rChildren.emplace_back(
747 static_cast< Content * >( xChild.get() ) );
748 }
749 }
750 }
751}
752
753
755 const uno::Reference< ucb::XContentIdentifier >& xNewId )
756{
757 if ( !xNewId.is() )
758 return false;
759
760 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
761
762 uno::Reference< ucb::XContent > xThis = this;
763
764 // Already persistent?
765 if ( m_eState != PERSISTENT )
766 {
767 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
768 return false;
769 }
770
771 // Only folders and streams can be renamed -> exchange identity.
773 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
774 {
775 OSL_FAIL( "Content::exchangeIdentity - "
776 "Not supported by root or document!" );
777 return false;
778 }
779
780 // Exchange own identity.
781
782 // Fail, if a content with given id already exists.
783 if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
784 {
785 OUString aOldURL = m_xIdentifier->getContentIdentifier();
786
787 aGuard.clear();
788 if ( exchange( xNewId ) )
789 {
790 if ( eType == FOLDER )
791 {
792 // Process instantiated children...
793
794 ContentRefList aChildren;
795 queryChildren( aChildren );
796
797 for ( const auto& rChild : aChildren )
798 {
799 ContentRef xChild = rChild;
800
801 // Create new content identifier for the child...
802 uno::Reference< ucb::XContentIdentifier > xOldChildId
803 = xChild->getIdentifier();
804 OUString aOldChildURL
805 = xOldChildId->getContentIdentifier();
806 OUString aNewChildURL
807 = aOldChildURL.replaceAt(
808 0,
809 aOldURL.getLength(),
810 xNewId->getContentIdentifier() );
811 uno::Reference< ucb::XContentIdentifier > xNewChildId
812 = new ::ucbhelper::ContentIdentifier( aNewChildURL );
813
814 if ( !xChild->exchangeIdentity( xNewChildId ) )
815 return false;
816 }
817 }
818 return true;
819 }
820 }
821
822 OSL_FAIL( "Content::exchangeIdentity - "
823 "Panic! Cannot exchange identity!" );
824 return false;
825}
826
827
828// static
829uno::Reference< sdbc::XRow > Content::getPropertyValues(
830 const uno::Reference< uno::XComponentContext >& rxContext,
831 const uno::Sequence< beans::Property >& rProperties,
832 ContentProvider* pProvider,
833 const OUString& rContentId )
834{
836 if ( loadData( pProvider, Uri(rContentId), aData ) )
837 {
838 return getPropertyValues(
839 rxContext, rProperties, aData, pProvider, rContentId );
840 }
841 else
842 {
844 = new ::ucbhelper::PropertyValueSet( rxContext );
845
846 for ( const beans::Property& rProp : rProperties )
847 xRow->appendVoid( rProp );
848
849 return xRow;
850 }
851}
852
853
854// static
855uno::Reference< sdbc::XRow > Content::getPropertyValues(
856 const uno::Reference< uno::XComponentContext >& rxContext,
857 const uno::Sequence< beans::Property >& rProperties,
858 const ContentProperties& rData,
859 ContentProvider* pProvider,
860 const OUString& rContentId )
861{
862 // Note: Empty sequence means "get values of all supported properties".
863
865 = new ::ucbhelper::PropertyValueSet( rxContext );
866
867 if ( rProperties.hasElements() )
868 {
869 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
870 bool bTriedToGetAdditionalPropSet = false;
871
872 for ( const beans::Property& rProp : rProperties )
873 {
874 // Process Core properties.
875
876 if ( rProp.Name == "ContentType" )
877 {
878 xRow->appendString ( rProp, rData.getContentType() );
879 }
880 else if ( rProp.Name == "Title" )
881 {
882 xRow->appendString ( rProp, rData.getTitle() );
883 }
884 else if ( rProp.Name == "IsDocument" )
885 {
886 xRow->appendBoolean( rProp, rData.getIsDocument() );
887 }
888 else if ( rProp.Name == "IsFolder" )
889 {
890 xRow->appendBoolean( rProp, rData.getIsFolder() );
891 }
892 else if ( rProp.Name == "CreatableContentsInfo" )
893 {
894 xRow->appendObject(
896 }
897 else if ( rProp.Name == "Storage" )
898 {
899 // Storage is only supported by folders.
901 if ( eType == FOLDER )
902 xRow->appendObject(
903 rProp,
904 uno::Any(
905 pProvider->queryStorageClone( rContentId ) ) );
906 else
907 xRow->appendVoid( rProp );
908 }
909 else if ( rProp.Name == "DocumentModel" )
910 {
911 // DocumentModel is only supported by documents.
913 if ( eType == DOCUMENT )
914 xRow->appendObject(
915 rProp,
916 uno::Any(
917 pProvider->queryDocumentModel( rContentId ) ) );
918 else
919 xRow->appendVoid( rProp );
920 }
921 else
922 {
923 // Not a Core Property! Maybe it's an Additional Core Property?!
924
925 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
926 {
927 xAdditionalPropSet =
928 pProvider->getAdditionalPropertySet( rContentId,
929 false );
930 bTriedToGetAdditionalPropSet = true;
931 }
932
933 if ( xAdditionalPropSet.is() )
934 {
935 if ( !xRow->appendPropertySetValue(
936 xAdditionalPropSet,
937 rProp ) )
938 {
939 // Append empty entry.
940 xRow->appendVoid( rProp );
941 }
942 }
943 else
944 {
945 // Append empty entry.
946 xRow->appendVoid( rProp );
947 }
948 }
949 }
950 }
951 else
952 {
953 // Append all Core Properties.
954 xRow->appendString (
955 beans::Property( "ContentType",
956 -1,
958 beans::PropertyAttribute::BOUND
959 | beans::PropertyAttribute::READONLY ),
961
963
964 xRow->appendString (
965 beans::Property( "Title",
966 -1,
968 // Title is read-only for root and documents.
969 beans::PropertyAttribute::BOUND |
970 ( ( eType == ROOT ) || ( eType == DOCUMENT )
971 ? beans::PropertyAttribute::READONLY
972 : 0 ) ),
973 rData.getTitle() );
974 xRow->appendBoolean(
975 beans::Property( "IsDocument",
976 -1,
978 beans::PropertyAttribute::BOUND
979 | beans::PropertyAttribute::READONLY ),
981 xRow->appendBoolean(
982 beans::Property( "IsFolder",
983 -1,
985 beans::PropertyAttribute::BOUND
986 | beans::PropertyAttribute::READONLY ),
987 rData.getIsFolder() );
988 xRow->appendObject(
989 beans::Property(
990 "CreatableContentsInfo",
991 -1,
992 cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
993 beans::PropertyAttribute::BOUND
994 | beans::PropertyAttribute::READONLY ),
996
997 // Storage is only supported by folders.
998 if ( eType == FOLDER )
999 xRow->appendObject(
1000 beans::Property( "Storage",
1001 -1,
1003 beans::PropertyAttribute::BOUND
1004 | beans::PropertyAttribute::READONLY ),
1005 uno::Any( pProvider->queryStorageClone( rContentId ) ) );
1006
1007 // DocumentModel is only supported by documents.
1008 if ( eType == DOCUMENT )
1009 xRow->appendObject(
1010 beans::Property( "DocumentModel",
1011 -1,
1013 beans::PropertyAttribute::BOUND
1014 | beans::PropertyAttribute::READONLY ),
1015 uno::Any(
1016 pProvider->queryDocumentModel( rContentId ) ) );
1017
1018 // Append all Additional Core Properties.
1019
1020 uno::Reference< beans::XPropertySet > xSet =
1021 pProvider->getAdditionalPropertySet( rContentId, false );
1022 xRow->appendPropertySet( xSet );
1023 }
1024
1025 return xRow;
1026}
1027
1028
1029uno::Reference< sdbc::XRow > Content::getPropertyValues(
1030 const uno::Sequence< beans::Property >& rProperties )
1031{
1032 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1034 rProperties,
1035 m_aProps,
1037 m_xIdentifier->getContentIdentifier() );
1038}
1039
1040
1041uno::Sequence< uno::Any > Content::setPropertyValues(
1042 const uno::Sequence< beans::PropertyValue >& rValues,
1043 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1044{
1045 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1046
1047 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1048 auto aRetRange = asNonConstRange(aRet);
1049 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1050 sal_Int32 nChanged = 0;
1051
1052 beans::PropertyChangeEvent aEvent;
1053 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1054 aEvent.Further = false;
1055 // aEvent.PropertyName =
1056 aEvent.PropertyHandle = -1;
1057 // aEvent.OldValue =
1058 // aEvent.NewValue =
1059
1060 const beans::PropertyValue* pValues = rValues.getConstArray();
1061 sal_Int32 nCount = rValues.getLength();
1062
1063 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1064 bool bTriedToGetAdditionalPropSet = false;
1065
1066 bool bExchange = false;
1067 OUString aOldTitle;
1068 sal_Int32 nTitlePos = -1;
1069
1070 for ( sal_Int32 n = 0; n < nCount; ++n )
1071 {
1072 const beans::PropertyValue& rValue = pValues[ n ];
1073
1074 if ( rValue.Name == "ContentType" )
1075 {
1076 // Read-only property!
1077 aRetRange[ n ] <<= lang::IllegalAccessException(
1078 "Property is read-only!",
1079 static_cast< cppu::OWeakObject * >( this ) );
1080 }
1081 else if ( rValue.Name == "IsDocument" )
1082 {
1083 // Read-only property!
1084 aRetRange[ n ] <<= lang::IllegalAccessException(
1085 "Property is read-only!",
1086 static_cast< cppu::OWeakObject * >( this ) );
1087 }
1088 else if ( rValue.Name == "IsFolder" )
1089 {
1090 // Read-only property!
1091 aRetRange[ n ] <<= lang::IllegalAccessException(
1092 "Property is read-only!",
1093 static_cast< cppu::OWeakObject * >( this ) );
1094 }
1095 else if ( rValue.Name == "CreatableContentsInfo" )
1096 {
1097 // Read-only property!
1098 aRetRange[ n ] <<= lang::IllegalAccessException(
1099 "Property is read-only!",
1100 static_cast< cppu::OWeakObject * >( this ) );
1101 }
1102 else if ( rValue.Name == "Title" )
1103 {
1104 // Title is read-only for root and documents.
1106 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1107 {
1108 aRetRange[ n ] <<= lang::IllegalAccessException(
1109 "Property is read-only!",
1110 static_cast< cppu::OWeakObject * >( this ) );
1111 }
1112 else
1113 {
1114 OUString aNewValue;
1115 if ( rValue.Value >>= aNewValue )
1116 {
1117 // No empty titles!
1118 if ( !aNewValue.isEmpty() )
1119 {
1120 if ( aNewValue != m_aProps.getTitle() )
1121 {
1122 // modified title -> modified URL -> exchange !
1123 if ( m_eState == PERSISTENT )
1124 bExchange = true;
1125
1126 aOldTitle = m_aProps.getTitle();
1127 m_aProps.setTitle( aNewValue );
1128
1129 // property change event will be sent later...
1130
1131 // remember position within sequence of values
1132 // (for error handling).
1133 nTitlePos = n;
1134 }
1135 }
1136 else
1137 {
1138 aRetRange[ n ] <<= lang::IllegalArgumentException(
1139 "Empty Title not allowed!",
1140 static_cast< cppu::OWeakObject * >( this ),
1141 -1 );
1142 }
1143 }
1144 else
1145 {
1146 aRetRange[ n ] <<= beans::IllegalTypeException(
1147 "Title Property value has wrong type!",
1148 static_cast< cppu::OWeakObject * >( this ) );
1149 }
1150 }
1151 }
1152 else if ( rValue.Name == "Storage" )
1153 {
1155 if ( eType == FOLDER )
1156 {
1157 aRetRange[ n ] <<= lang::IllegalAccessException(
1158 "Property is read-only!",
1159 static_cast< cppu::OWeakObject * >( this ) );
1160 }
1161 else
1162 {
1163 // Storage is only supported by folders.
1164 aRetRange[ n ] <<= beans::UnknownPropertyException(
1165 "Storage property only supported by folders",
1166 static_cast< cppu::OWeakObject * >( this ) );
1167 }
1168 }
1169 else if ( rValue.Name == "DocumentModel" )
1170 {
1172 if ( eType == DOCUMENT )
1173 {
1174 aRetRange[ n ] <<= lang::IllegalAccessException(
1175 "Property is read-only!",
1176 static_cast< cppu::OWeakObject * >( this ) );
1177 }
1178 else
1179 {
1180 // Storage is only supported by folders.
1181 aRetRange[ n ] <<= beans::UnknownPropertyException(
1182 "DocumentModel property only supported by documents",
1183 static_cast< cppu::OWeakObject * >( this ) );
1184 }
1185 }
1186 else
1187 {
1188 // Not a Core Property! Maybe it's an Additional Core Property?!
1189
1190 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1191 {
1192 xAdditionalPropSet = getAdditionalPropertySet( false );
1193 bTriedToGetAdditionalPropSet = true;
1194 }
1195
1196 if ( xAdditionalPropSet.is() )
1197 {
1198 try
1199 {
1200 uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1201 rValue.Name );
1202 if ( aOldValue != rValue.Value )
1203 {
1204 xAdditionalPropSet->setPropertyValue(
1205 rValue.Name, rValue.Value );
1206
1207 aEvent.PropertyName = rValue.Name;
1208 aEvent.OldValue = aOldValue;
1209 aEvent.NewValue = rValue.Value;
1210
1211 aChanges.getArray()[ nChanged ] = aEvent;
1212 nChanged++;
1213 }
1214 }
1215 catch ( beans::UnknownPropertyException const & e )
1216 {
1217 aRetRange[ n ] <<= e;
1218 }
1219 catch ( lang::WrappedTargetException const & e )
1220 {
1221 aRetRange[ n ] <<= e;
1222 }
1223 catch ( beans::PropertyVetoException const & e )
1224 {
1225 aRetRange[ n ] <<= e;
1226 }
1227 catch ( lang::IllegalArgumentException const & e )
1228 {
1229 aRetRange[ n ] <<= e;
1230 }
1231 }
1232 else
1233 {
1234 aRetRange[ n ] <<= uno::Exception(
1235 "No property set for storing the value!",
1236 static_cast< cppu::OWeakObject * >( this ) );
1237 }
1238 }
1239 }
1240
1241 if ( bExchange )
1242 {
1243 uno::Reference< ucb::XContentIdentifier > xOldId
1244 = m_xIdentifier;
1245 uno::Reference< ucb::XContentIdentifier > xNewId
1247
1248 aGuard.clear();
1249 if ( exchangeIdentity( xNewId ) )
1250 {
1251 // Adapt persistent data.
1252 renameData( xOldId, xNewId );
1253
1254 // Adapt Additional Core Properties.
1255 renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1256 xNewId->getContentIdentifier() );
1257 }
1258 else
1259 {
1260 // Roll-back.
1261 m_aProps.setTitle( aOldTitle );
1262 aOldTitle.clear();
1263
1264 // Set error .
1265 aRetRange[ nTitlePos ] <<= uno::Exception(
1266 "Exchange failed!",
1267 static_cast< cppu::OWeakObject * >( this ) );
1268 }
1269 }
1270
1271 if ( !aOldTitle.isEmpty() )
1272 {
1273 aEvent.PropertyName = "Title";
1274 aEvent.OldValue <<= aOldTitle;
1275 aEvent.NewValue <<= m_aProps.getTitle();
1276
1277 aChanges.getArray()[ nChanged ] = aEvent;
1278 nChanged++;
1279 }
1280
1281 if ( nChanged > 0 )
1282 {
1283 // Save changes, if content was already made persistent.
1284 if ( !bExchange && ( m_eState == PERSISTENT ) )
1285 {
1286 if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1287 {
1288 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1289 {
1290 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1291 }));
1293 ucb::IOErrorCode_CANT_WRITE,
1294 aArgs,
1295 xEnv,
1296 "Cannot store persistent data!",
1297 this );
1298 // Unreachable
1299 }
1300 }
1301
1302 aChanges.realloc( nChanged );
1303
1304 aGuard.clear();
1305 notifyPropertiesChange( aChanges );
1306 }
1307
1308 return aRet;
1309}
1310
1311
1313 const ucb::OpenCommandArgument2& rArg,
1314 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1315{
1316 if ( rArg.Mode == ucb::OpenMode::ALL ||
1317 rArg.Mode == ucb::OpenMode::FOLDERS ||
1318 rArg.Mode == ucb::OpenMode::DOCUMENTS )
1319 {
1320
1321 // open command for a folder content
1322
1323
1324 uno::Reference< ucb::XDynamicResultSet > xSet
1325 = new DynamicResultSet( m_xContext, this, rArg );
1326 return uno::Any( xSet );
1327 }
1328 else
1329 {
1330
1331 // open command for a document content
1332
1333
1334 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1335 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1336 {
1337 // Currently(?) unsupported.
1339 uno::Any( ucb::UnsupportedOpenModeException(
1340 OUString(),
1341 static_cast< cppu::OWeakObject * >( this ),
1342 sal_Int16( rArg.Mode ) ) ),
1343 xEnv );
1344 // Unreachable
1345 }
1346
1347 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1348
1349 uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1350 rArg.Sink, uno::UNO_QUERY );
1351 if ( xDataStreamer.is() )
1352 {
1353 // May throw CommandFailedException, DocumentPasswordRequest!
1354 uno::Reference< io::XStream > xStream = getStream( xEnv );
1355 if ( !xStream.is() )
1356 {
1357 // No interaction if we are not persistent!
1358 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1359 {
1360 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1361 }));
1363 ucb::IOErrorCode_CANT_READ,
1364 aArgs,
1366 ? xEnv
1367 : uno::Reference< ucb::XCommandEnvironment >(),
1368 "Got no data stream!",
1369 this );
1370 // Unreachable
1371 }
1372
1373 // Done.
1374 xDataStreamer->setStream( xStream );
1375 }
1376 else
1377 {
1378 uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1379 if ( xOut.is() )
1380 {
1381 // PUSH: write data into xOut
1382
1383 // May throw CommandFailedException, DocumentPasswordRequest!
1384 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1385 if ( !xIn.is() )
1386 {
1387 // No interaction if we are not persistent!
1388 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1389 {
1390 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1391 }));
1393 ucb::IOErrorCode_CANT_READ,
1394 aArgs,
1396 ? xEnv
1397 : uno::Reference< ucb::XCommandEnvironment >(),
1398 "Got no data stream!",
1399 this );
1400 // Unreachable
1401 }
1402
1403 try
1404 {
1405 uno::Sequence< sal_Int8 > aBuffer;
1406
1407 while (true)
1408 {
1409 sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1410 if (!nRead)
1411 break;
1412 aBuffer.realloc( nRead );
1413 xOut->writeBytes( aBuffer );
1414 }
1415
1416 xOut->closeOutput();
1417 }
1418 catch ( io::NotConnectedException const & )
1419 {
1420 // closeOutput, readSomeBytes, writeBytes
1421 }
1422 catch ( io::BufferSizeExceededException const & )
1423 {
1424 // closeOutput, readSomeBytes, writeBytes
1425 }
1426 catch ( io::IOException const & )
1427 {
1428 // closeOutput, readSomeBytes, writeBytes
1429 }
1430 }
1431 else
1432 {
1433 uno::Reference< io::XActiveDataSink > xDataSink(
1434 rArg.Sink, uno::UNO_QUERY );
1435 if ( xDataSink.is() )
1436 {
1437 // PULL: wait for client read
1438
1439 // May throw CommandFailedException, DocumentPasswordRequest!
1440 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1441 if ( !xIn.is() )
1442 {
1443 // No interaction if we are not persistent!
1444 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1445 {
1446 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1447 }));
1449 ucb::IOErrorCode_CANT_READ,
1450 aArgs,
1452 ? xEnv
1453 : uno::Reference<
1454 ucb::XCommandEnvironment >(),
1455 "Got no data stream!",
1456 this );
1457 // Unreachable
1458 }
1459
1460 // Done.
1461 xDataSink->setInputStream( xIn );
1462 }
1463 else
1464 {
1466 uno::Any(
1467 ucb::UnsupportedDataSinkException(
1468 OUString(),
1469 static_cast< cppu::OWeakObject * >( this ),
1470 rArg.Sink ) ),
1471 xEnv );
1472 // Unreachable
1473 }
1474 }
1475 }
1476 }
1477
1478 return uno::Any();
1479}
1480
1481
1482void Content::insert( const uno::Reference< io::XInputStream >& xData,
1483 sal_Int32 nNameClashResolve,
1484 const uno::Reference<
1485 ucb::XCommandEnvironment > & xEnv )
1486{
1487 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1488
1490
1491 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1492 "insert command only supported by streams and folders!" );
1493
1494 Uri aUri( m_xIdentifier->getContentIdentifier() );
1495
1496#if OSL_DEBUG_LEVEL > 0
1497 if ( eType == STREAM )
1498 {
1499 Uri aParentUri( aUri.getParentUri() );
1500 OSL_ENSURE( !aParentUri.isDocument(),
1501 "insert command not supported by streams that are direct "
1502 "children of document root!" );
1503 }
1504#endif
1505
1506 // Check, if all required properties were set.
1507 if ( eType == FOLDER )
1508 {
1509 // Required: Title
1510
1511 if ( m_aProps.getTitle().isEmpty() )
1512 m_aProps.setTitle( aUri.getDecodedName() );
1513 }
1514 else // stream
1515 {
1516 // Required: data
1517
1518 if ( !xData.is() )
1519 {
1521 uno::Any( ucb::MissingInputStreamException(
1522 OUString(),
1523 static_cast< cppu::OWeakObject * >( this ) ) ),
1524 xEnv );
1525 // Unreachable
1526 }
1527
1528 // Required: Title
1529
1530 if ( m_aProps.getTitle().isEmpty() )
1531 m_aProps.setTitle( aUri.getDecodedName() );
1532 }
1533
1534 Uri aNewUri( aUri.getParentUri() + m_aProps.getTitle() );
1535
1536 // Handle possible name clash...
1537 switch ( nNameClashResolve )
1538 {
1539 // fail.
1540 case ucb::NameClash::ERROR:
1541 if ( hasData( aNewUri ) )
1542 {
1544 uno::Any( ucb::NameClashException(
1545 OUString(),
1546 static_cast< cppu::OWeakObject * >( this ),
1547 task::InteractionClassification_ERROR,
1548 m_aProps.getTitle() ) ),
1549 xEnv );
1550 // Unreachable
1551 }
1552 break;
1553
1554 // replace (possibly) existing object.
1555 case ucb::NameClash::OVERWRITE:
1556 break;
1557
1558 // "invent" a new valid title.
1559 case ucb::NameClash::RENAME:
1560 if ( hasData( aNewUri ) )
1561 {
1562 sal_Int32 nTry = 0;
1563
1564 do
1565 {
1566 OUStringBuffer aNew(aNewUri.getUri());
1567 aNew.append( "_" );
1568 aNew.append( ++nTry );
1569 aNewUri.setUri( aNew.makeStringAndClear() );
1570 }
1571 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1572
1573 if ( nTry == 1000 )
1574 {
1576 uno::Any(
1577 ucb::UnsupportedNameClashException(
1578 "Unable to resolve name clash!",
1579 static_cast< cppu::OWeakObject * >( this ),
1580 nNameClashResolve ) ),
1581 xEnv );
1582 // Unreachable
1583 }
1584 else
1585 {
1586 OUStringBuffer aNewTitle(m_aProps.getTitle());
1587 aNewTitle.append( "_" );
1588 aNewTitle.append( ++nTry );
1589 m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1590 }
1591 }
1592 break;
1593
1594 case ucb::NameClash::KEEP: // deprecated
1595 case ucb::NameClash::ASK:
1596 default:
1597 if ( hasData( aNewUri ) )
1598 {
1600 uno::Any(
1601 ucb::UnsupportedNameClashException(
1602 OUString(),
1603 static_cast< cppu::OWeakObject * >( this ),
1604 nNameClashResolve ) ),
1605 xEnv );
1606 // Unreachable
1607 }
1608 break;
1609 }
1610
1611 // Identifier changed?
1612 bool bNewId = ( aUri != aNewUri );
1613
1614 if ( bNewId )
1615 {
1617 = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1618 }
1619
1620 if ( !storeData( xData, xEnv ) )
1621 {
1622 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1623 {
1624 {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1625 }));
1627 ucb::IOErrorCode_CANT_WRITE,
1628 aArgs,
1629 xEnv,
1630 "Cannot store persistent data!",
1631 this );
1632 // Unreachable
1633 }
1634
1636
1637 if ( bNewId )
1638 {
1639 //loadData( m_pProvider, m_aUri, m_aProps );
1640
1641 aGuard.clear();
1642 inserted();
1643 }
1644}
1645
1646
1647void Content::destroy( bool bDeletePhysical,
1648 const uno::Reference<
1649 ucb::XCommandEnvironment > & xEnv )
1650{
1651 // @@@ take care about bDeletePhysical -> trashcan support
1652
1653 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1654
1656
1657 OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1658 "delete command only supported by streams and folders!" );
1659
1660 uno::Reference< ucb::XContent > xThis = this;
1661
1662 // Persistent?
1663 if ( m_eState != PERSISTENT )
1664 {
1666 uno::Any( ucb::UnsupportedCommandException(
1667 "Not persistent!",
1668 static_cast< cppu::OWeakObject * >( this ) ) ),
1669 xEnv );
1670 // Unreachable
1671 }
1672
1673 m_eState = DEAD;
1674
1675 aGuard.clear();
1676 deleted();
1677
1678 if ( eType == FOLDER )
1679 {
1680 // Process instantiated children...
1681
1682 ContentRefList aChildren;
1683 queryChildren( aChildren );
1684
1685 for ( auto& rChild : aChildren )
1686 {
1687 rChild->destroy( bDeletePhysical, xEnv );
1688 }
1689 }
1690}
1691
1692
1694{
1695 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1696
1697 m_eState = DEAD;
1698
1699 // @@@ anything else to reset or such?
1700
1701 // callback follows!
1702 aGuard.clear();
1703
1704 // Propagate destruction to content event listeners
1705 // Remove this from provider's content list.
1706 deleted();
1707}
1708
1709
1710uno::Reference< ucb::XContent >
1711Content::queryChildContent( std::u16string_view rRelativeChildUri )
1712{
1713 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1714
1715 const OUString aMyId = getIdentifier()->getContentIdentifier();
1716 OUStringBuffer aBuf( aMyId );
1717 if ( !aMyId.endsWith("/") )
1718 aBuf.append( "/" );
1719 if ( !o3tl::starts_with(rRelativeChildUri, u"/") )
1720 aBuf.append( rRelativeChildUri );
1721 else
1722 aBuf.append( rRelativeChildUri.substr(1) );
1723
1724 uno::Reference< ucb::XContentIdentifier > xChildId
1725 = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1726
1727 uno::Reference< ucb::XContent > xChild;
1728 try
1729 {
1730 xChild = m_pProvider->queryContent( xChildId );
1731 }
1732 catch ( ucb::IllegalIdentifierException const & )
1733 {
1734 // handled below.
1735 }
1736
1737 OSL_ENSURE( xChild.is(),
1738 "Content::queryChildContent - unable to create child content!" );
1739 return xChild;
1740}
1741
1742
1743void Content::notifyChildRemoved( std::u16string_view rRelativeChildUri )
1744{
1745 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1746
1747 // Ugly! Need to create child content object, just to fill event properly.
1748 uno::Reference< ucb::XContent > xChild
1749 = queryChildContent( rRelativeChildUri );
1750
1751 if ( !xChild.is() )
1752 return;
1753
1754 // callback follows!
1755 aGuard.clear();
1756
1757 // Notify "REMOVED" event.
1758 ucb::ContentEvent aEvt(
1759 static_cast< cppu::OWeakObject * >( this ),
1760 ucb::ContentAction::REMOVED,
1761 xChild,
1762 getIdentifier() );
1763 notifyContentEvent( aEvt );
1764}
1765
1766
1767void Content::notifyChildInserted( std::u16string_view rRelativeChildUri )
1768{
1769 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1770
1771 // Ugly! Need to create child content object, just to fill event properly.
1772 uno::Reference< ucb::XContent > xChild
1773 = queryChildContent( rRelativeChildUri );
1774
1775 if ( !xChild.is() )
1776 return;
1777
1778 // callback follows!
1779 aGuard.clear();
1780
1781 // Notify "INSERTED" event.
1782 ucb::ContentEvent aEvt(
1783 static_cast< cppu::OWeakObject * >( this ),
1784 ucb::ContentAction::INSERTED,
1785 xChild,
1786 getIdentifier() );
1787 notifyContentEvent( aEvt );
1788}
1789
1790
1792 const ucb::TransferInfo& rInfo,
1793 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1794{
1795 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1796
1797 // Persistent?
1798 if ( m_eState != PERSISTENT )
1799 {
1801 uno::Any( ucb::UnsupportedCommandException(
1802 "Not persistent!",
1803 static_cast< cppu::OWeakObject * >( this ) ) ),
1804 xEnv );
1805 // Unreachable
1806 }
1807
1808 // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1809
1810 if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1811 {
1812 // Invalid length (to short).
1814 uno::Any( ucb::InteractiveBadTransferURLException(
1815 OUString(),
1816 static_cast< cppu::OWeakObject * >( this ) ) ),
1817 xEnv );
1818 // Unreachable
1819 }
1820
1821 OUString aScheme
1822 = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1823 .toAsciiLowerCase();
1824 if ( aScheme != TDOC_URL_SCHEME ":/" )
1825 {
1826 // Invalid scheme.
1828 uno::Any( ucb::InteractiveBadTransferURLException(
1829 OUString(),
1830 static_cast< cppu::OWeakObject * >( this ) ) ),
1831 xEnv );
1832 // Unreachable
1833 }
1834
1835 // Does source URI describe a tdoc folder or stream?
1836 Uri aSourceUri( rInfo.SourceURL );
1837 if ( !aSourceUri.isValid() )
1838 {
1840 uno::Any( lang::IllegalArgumentException(
1841 "Invalid source URI! Syntax!",
1842 static_cast< cppu::OWeakObject * >( this ),
1843 -1 ) ),
1844 xEnv );
1845 // Unreachable
1846 }
1847
1848 if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1849 {
1851 uno::Any( lang::IllegalArgumentException(
1852 "Invalid source URI! Must describe a folder or stream!",
1853 static_cast< cppu::OWeakObject * >( this ),
1854 -1 ) ),
1855 xEnv );
1856 // Unreachable
1857 }
1858
1859 // Is source not a parent of me / not me?
1860 OUString aId = m_xIdentifier->getContentIdentifier();
1861 sal_Int32 nPos = aId.lastIndexOf( '/' );
1862 if ( nPos != ( aId.getLength() - 1 ) )
1863 {
1864 // No trailing slash found. Append.
1865 aId += "/";
1866 }
1867
1868 if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1869 {
1870 if ( aId.startsWith( rInfo.SourceURL ) )
1871 {
1872 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1873 {
1874 {"Uri", uno::Any(rInfo.SourceURL)}
1875 }));
1877 ucb::IOErrorCode_RECURSIVE,
1878 aArgs,
1879 xEnv,
1880 "Target is equal to or is a child of source!",
1881 this );
1882 // Unreachable
1883 }
1884 }
1885
1886 if ( m_aProps.getType() == DOCUMENT )
1887 {
1888 bool bOK = false;
1889
1890 uno::Reference< embed::XStorage > xStorage
1892 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1893 if ( xStorage.is() )
1894 {
1895 try
1896 {
1897 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1898 {
1900 uno::Any( lang::IllegalArgumentException(
1901 "Invalid source URI! "
1902 "Streams cannot be created as "
1903 "children of document root!",
1904 static_cast< cppu::OWeakObject * >(
1905 this ),
1906 -1 ) ),
1907 xEnv );
1908 // Unreachable
1909 }
1910 bOK = true;
1911 }
1912 catch ( container::NoSuchElementException const & )
1913 {
1914 // handled below.
1915 }
1916 catch ( lang::IllegalArgumentException const & )
1917 {
1918 // handled below.
1919 }
1920 catch ( embed::InvalidStorageException const & )
1921 {
1922 // handled below.
1923 }
1924 }
1925
1926 if ( !bOK )
1927 {
1929 uno::Any( lang::IllegalArgumentException(
1930 "Invalid source URI! Unable to determine source type!",
1931 static_cast< cppu::OWeakObject * >( this ),
1932 -1 ) ),
1933 xEnv );
1934 // Unreachable
1935 }
1936 }
1937
1938
1939 // Copy data.
1940
1941
1942 OUString aNewName( !rInfo.NewTitle.isEmpty()
1943 ? rInfo.NewTitle
1944 : aSourceUri.getDecodedName() );
1945
1946 if ( !copyData( aSourceUri, aNewName ) )
1947 {
1948 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1949 {
1950 {"Uri", uno::Any(rInfo.SourceURL)}
1951 }));
1953 ucb::IOErrorCode_CANT_WRITE,
1954 aArgs,
1955 xEnv,
1956 "Cannot copy data!",
1957 this );
1958 // Unreachable
1959 }
1960
1961
1962 // Copy own and all children's Additional Core Properties.
1963
1964
1965 OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1966 if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1967 aTargetUri += "/";
1968
1969 if ( !rInfo.NewTitle.isEmpty() )
1970 aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1971 else
1972 aTargetUri += aSourceUri.getName();
1973
1974 if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1975 {
1976 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1977 {
1978 {"Uri", uno::Any(rInfo.SourceURL)}
1979 }));
1981 ucb::IOErrorCode_CANT_WRITE,
1982 aArgs,
1983 xEnv,
1984 "Cannot copy additional properties!",
1985 this );
1986 // Unreachable
1987 }
1988
1989
1990 // Propagate new content.
1991
1992
1994 try
1995 {
1996 uno::Reference< ucb::XContentIdentifier > xTargetId
1997 = new ::ucbhelper::ContentIdentifier( aTargetUri );
1998
1999 // Note: The static cast is okay here, because its sure that
2000 // m_xProvider is always the WebDAVContentProvider.
2001 xTarget = static_cast< Content * >(
2002 m_pProvider->queryContent( xTargetId ).get() );
2003
2004 }
2005 catch ( ucb::IllegalIdentifierException const & )
2006 {
2007 // queryContent
2008 }
2009
2010 if ( !xTarget.is() )
2011 {
2012 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2013 {
2014 {"Uri", uno::Any(aTargetUri)}
2015 }));
2017 ucb::IOErrorCode_CANT_READ,
2018 aArgs,
2019 xEnv,
2020 "Cannot instantiate target object!",
2021 this );
2022 // Unreachable
2023 }
2024
2025 // Announce transferred content in its new folder.
2026 xTarget->inserted();
2027
2028
2029 // Remove source, if requested
2030
2031
2032 if ( !rInfo.MoveData )
2033 return;
2034
2036 try
2037 {
2038 uno::Reference< ucb::XContentIdentifier >
2039 xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2040
2041 // Note: The static cast is okay here, because its sure
2042 // that m_xProvider is always the ContentProvider.
2043 xSource = static_cast< Content * >(
2044 m_xProvider->queryContent( xSourceId ).get() );
2045 }
2046 catch ( ucb::IllegalIdentifierException const & )
2047 {
2048 // queryContent
2049 }
2050
2051 if ( !xSource.is() )
2052 {
2053 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2054 {
2055 {"Uri", uno::Any(rInfo.SourceURL)}
2056 }));
2058 ucb::IOErrorCode_CANT_READ,
2059 aArgs,
2060 xEnv,
2061 "Cannot instantiate target object!",
2062 this );
2063 // Unreachable
2064 }
2065
2066 // Propagate destruction (recursively).
2067 xSource->destroy( true, xEnv );
2068
2069 // Remove all persistent data of source and its children.
2070 if ( !xSource->removeData() )
2071 {
2072 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2073 {
2074 {"Uri", uno::Any(rInfo.SourceURL)}
2075 }));
2077 ucb::IOErrorCode_CANT_WRITE,
2078 aArgs,
2079 xEnv,
2080 "Cannot remove persistent data of source object!",
2081 this );
2082 // Unreachable
2083 }
2084
2085 // Remove own and all children's Additional Core Properties.
2086 if ( xSource->removeAdditionalPropertySet() )
2087 return;
2088
2089 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2090 {
2091 {"Uri", uno::Any(rInfo.SourceURL)}
2092 }));
2094 ucb::IOErrorCode_CANT_WRITE,
2095 aArgs,
2096 xEnv,
2097 "Cannot remove additional properties of source object!",
2098 this );
2099 // Unreachable
2100}
2101
2102
2103//static
2104bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2105{
2106 if ( rUri.isRoot() )
2107 {
2108 return true; // root has no storage
2109 }
2110 else if ( rUri.isDocument() )
2111 {
2112 uno::Reference< embed::XStorage > xStorage
2113 = pProvider->queryStorage( rUri.getUri(), READ );
2114 return xStorage.is();
2115 }
2116 else
2117 {
2118 // folder or stream
2119
2120 // Ask parent storage. In case that rUri describes a stream,
2121 // ContentProvider::queryStorage( rUri ) would return null.
2122
2123 uno::Reference< embed::XStorage > xStorage
2124 = pProvider->queryStorage( rUri.getParentUri(), READ );
2125
2126 if ( !xStorage.is() )
2127 return false;
2128
2129 return xStorage->hasByName( rUri.getDecodedName() );
2130 }
2131}
2132
2133
2134//static
2135bool Content::loadData( ContentProvider const * pProvider,
2136 const Uri & rUri,
2137 ContentProperties& rProps )
2138{
2139 if ( rUri.isRoot() ) // root has no storage, but can always be created
2140 {
2141 rProps
2143 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2144 }
2145 else if ( rUri.isDocument() ) // document must have storage
2146 {
2147 uno::Reference< embed::XStorage > xStorage
2148 = pProvider->queryStorage( rUri.getUri(), READ );
2149
2150 if ( !xStorage.is() )
2151 return false;
2152
2153 rProps
2155 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2156 }
2157 else // stream or folder; stream has no storage; folder has storage
2158 {
2159 uno::Reference< embed::XStorage > xStorage
2160 = pProvider->queryStorage( rUri.getParentUri(), READ );
2161
2162 if ( !xStorage.is() )
2163 return false;
2164
2165 // Check whether exists at all, is stream or folder
2166 try
2167 {
2168 // return: true -> folder
2169 // return: false -> stream
2170 // NoSuchElementException -> neither folder nor stream
2171 bool bIsFolder
2172 = xStorage->isStorageElement( rUri.getDecodedName() );
2173
2174 rProps
2176 bIsFolder ? FOLDER : STREAM,
2177 pProvider->queryStorageTitle( rUri.getUri() ) );
2178 }
2179 catch ( container::NoSuchElementException const & )
2180 {
2181 // there is no element with such name
2182 //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2183 return false;
2184 }
2185 catch ( lang::IllegalArgumentException const & )
2186 {
2187 // an illegal argument is provided
2188 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2189 return false;
2190 }
2191 catch ( embed::InvalidStorageException const & )
2192 {
2193 // this storage is in invalid state for any reason
2194 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2195 return false;
2196 }
2197 }
2198 return true;
2199}
2200
2201
2202bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2203 const uno::Reference<
2204 ucb::XCommandEnvironment >& xEnv )
2205{
2206 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2207
2209 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2210 {
2211 OSL_FAIL( "storeData not supported by root and documents!" );
2212 return false;
2213 }
2214
2215 Uri aUri( m_xIdentifier->getContentIdentifier() );
2216
2217 if ( eType == FOLDER )
2218 {
2219 uno::Reference< embed::XStorage > xStorage
2220 = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2221
2222 if ( !xStorage.is() )
2223 return false;
2224
2225 uno::Reference< beans::XPropertySet > xPropSet(
2226 xStorage, uno::UNO_QUERY );
2227 OSL_ENSURE( xPropSet.is(),
2228 "Content::storeData - Got no XPropertySet interface!" );
2229 if ( !xPropSet.is() )
2230 return false;
2231
2232 try
2233 {
2234 // According to MBA, if no mediatype is set, folder and all
2235 // its contents will be lost on save of the document!!!
2236 xPropSet->setPropertyValue(
2237 "MediaType",
2238 uno::Any(
2239 OUString( // @@@ better mediatype
2240 "application/binary" ) ) );
2241 }
2242 catch ( beans::UnknownPropertyException const & )
2243 {
2244 OSL_FAIL( "Property MediaType not supported!" );
2245 return false;
2246 }
2247 catch ( beans::PropertyVetoException const & )
2248 {
2249 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2250 return false;
2251 }
2252 catch ( lang::IllegalArgumentException const & )
2253 {
2254 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2255 return false;
2256 }
2257 catch ( lang::WrappedTargetException const & )
2258 {
2259 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2260 return false;
2261 }
2262
2263 if ( !commitStorage( xStorage ) )
2264 return false;
2265 }
2266 else if ( eType == STREAM )
2267 {
2268 // stream
2269
2270 // Important: Parent storage and output stream must be kept alive until
2271 // changes have been committed!
2272 uno::Reference< embed::XStorage > xStorage
2274 aUri.getParentUri(), READ_WRITE_CREATE );
2275 uno::Reference< io::XOutputStream > xOut;
2276
2277 if ( !xStorage.is() )
2278 return false;
2279
2280 if ( xData.is() )
2281 {
2282 // May throw CommandFailedException, DocumentPasswordRequest!
2283 xOut = getTruncatedOutputStream( xEnv );
2284
2285 OSL_ENSURE( xOut.is(), "No target data stream!" );
2286
2287 try
2288 {
2289 uno::Sequence< sal_Int8 > aBuffer;
2290 while (true)
2291 {
2292 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2293 if (!nRead)
2294 break;
2295 aBuffer.realloc( nRead );
2296 xOut->writeBytes( aBuffer );
2297 }
2298
2299 closeOutputStream( xOut );
2300 }
2301 catch ( io::NotConnectedException const & )
2302 {
2303 // readSomeBytes, writeBytes
2304 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2305 closeOutputStream( xOut );
2306 return false;
2307 }
2308 catch ( io::BufferSizeExceededException const & )
2309 {
2310 // readSomeBytes, writeBytes
2311 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2312 closeOutputStream( xOut );
2313 return false;
2314 }
2315 catch ( io::IOException const & )
2316 {
2317 // readSomeBytes, writeBytes
2318 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2319 closeOutputStream( xOut );
2320 return false;
2321 }
2322 catch ( ... )
2323 {
2324 closeOutputStream( xOut );
2325 throw;
2326 }
2327 }
2328
2329 // Commit changes.
2330 if ( !commitStorage( xStorage ) )
2331 return false;
2332 }
2333 else
2334 {
2335 OSL_FAIL( "Unknown content type!" );
2336 return false;
2337 }
2338 return true;
2339}
2340
2341
2343 const uno::Reference< ucb::XContentIdentifier >& xOldId,
2344 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2345{
2346 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2347
2349 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2350 {
2351 OSL_FAIL( "renameData not supported by root and documents!" );
2352 return;
2353 }
2354
2355 Uri aOldUri( xOldId->getContentIdentifier() );
2356 uno::Reference< embed::XStorage > xStorage
2358 aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2359
2360 if ( !xStorage.is() )
2361 return;
2362
2363 try
2364 {
2365 Uri aNewUri( xNewId->getContentIdentifier() );
2366 xStorage->renameElement(
2367 aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2368 }
2369 catch ( embed::InvalidStorageException const & )
2370 {
2371 // this storage is in invalid state for any reason
2372 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2373 return;
2374 }
2375 catch ( lang::IllegalArgumentException const & )
2376 {
2377 // an illegal argument is provided
2378 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2379 return;
2380 }
2381 catch ( container::NoSuchElementException const & )
2382 {
2383 // there is no element with old name in this storage
2384 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2385 return;
2386 }
2387 catch ( container::ElementExistException const & )
2388 {
2389 // an element with new name already exists in this storage
2390 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2391 return;
2392 }
2393 catch ( io::IOException const & )
2394 {
2395 // in case of io errors during renaming
2396 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2397 return;
2398 }
2399 catch ( embed::StorageWrappedTargetException const & )
2400 {
2401 // wraps other exceptions
2402 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2403 return;
2404 }
2405
2406 commitStorage( xStorage );
2407}
2408
2409
2411{
2412 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2413
2415 if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2416 {
2417 OSL_FAIL( "removeData not supported by root and documents!" );
2418 return false;
2419 }
2420
2421 Uri aUri( m_xIdentifier->getContentIdentifier() );
2422 uno::Reference< embed::XStorage > xStorage
2425
2426 if ( !xStorage.is() )
2427 return false;
2428
2429 try
2430 {
2431 xStorage->removeElement( aUri.getDecodedName() );
2432 }
2433 catch ( embed::InvalidStorageException const & )
2434 {
2435 // this storage is in invalid state for any reason
2436 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2437 return false;
2438 }
2439 catch ( lang::IllegalArgumentException const & )
2440 {
2441 // an illegal argument is provided
2442 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2443 return false;
2444 }
2445 catch ( container::NoSuchElementException const & )
2446 {
2447 // there is no element with this name in this storage
2448 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2449 return false;
2450 }
2451 catch ( io::IOException const & )
2452 {
2453 // in case of io errors during renaming
2454 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2455 return false;
2456 }
2457 catch ( embed::StorageWrappedTargetException const & )
2458 {
2459 // wraps other exceptions
2460 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2461 return false;
2462 }
2463
2464 return commitStorage( xStorage );
2465}
2466
2467
2468bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2469{
2470 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2471
2473 if ( ( eType == ROOT ) || ( eType == STREAM ) )
2474 {
2475 OSL_FAIL( "copyData not supported by root and streams!" );
2476 return false;
2477 }
2478
2479 Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2480 uno::Reference< embed::XStorage > xDestStorage
2482
2483 if ( !xDestStorage.is() )
2484 return false;
2485
2486 uno::Reference< embed::XStorage > xSourceStorage
2487 = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2488
2489 if ( !xSourceStorage.is() )
2490 return false;
2491
2492 try
2493 {
2494 xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2495 xDestStorage,
2496 rNewName );
2497 }
2498 catch ( embed::InvalidStorageException const & )
2499 {
2500 // this storage is in invalid state for any reason
2501 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2502 return false;
2503 }
2504 catch ( lang::IllegalArgumentException const & )
2505 {
2506 // an illegal argument is provided
2507 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2508 return false;
2509 }
2510 catch ( container::NoSuchElementException const & )
2511 {
2512 // there is no element with this name in this storage
2513 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2514 return false;
2515 }
2516 catch ( container::ElementExistException const & )
2517 {
2518 // there is no element with this name in this storage
2519 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2520 return false;
2521 }
2522 catch ( io::IOException const & )
2523 {
2524 // in case of io errors during renaming
2525 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2526 return false;
2527 }
2528 catch ( embed::StorageWrappedTargetException const & )
2529 {
2530 // wraps other exceptions
2531 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2532 return false;
2533 }
2534
2535 return commitStorage( xDestStorage );
2536}
2537
2538
2539// static
2540bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2541{
2542 // Commit changes
2543 uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2544
2545 OSL_ENSURE( xTO.is(),
2546 "Required interface css.embed.XTransactedObject missing!" );
2547 try
2548 {
2549 xTO->commit();
2550 }
2551 catch ( io::IOException const & )
2552 {
2553 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2554 return false;
2555 }
2556 catch ( lang::WrappedTargetException const & )
2557 {
2558 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2559 return false;
2560 }
2561
2562 return true;
2563}
2564
2565
2566// static
2568 const uno::Reference< io::XOutputStream > & xOut )
2569{
2570 if ( xOut.is() )
2571 {
2572 try
2573 {
2574 xOut->closeOutput();
2575 return true;
2576 }
2577 catch ( io::NotConnectedException const & )
2578 {
2579 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2580 }
2581 catch ( io::BufferSizeExceededException const & )
2582 {
2583 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2584 }
2585 catch ( io::IOException const & )
2586 {
2587 TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2588 }
2589 }
2590 return false;
2591}
2592
2595static OUString obtainPassword(
2596 const OUString & rName,
2597 task::PasswordRequestMode eMode,
2598 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2599{
2601 = new DocumentPasswordRequest( eMode, rName );
2602
2603 if ( xEnv.is() )
2604 {
2605 uno::Reference< task::XInteractionHandler > xIH
2606 = xEnv->getInteractionHandler();
2607 if ( xIH.is() )
2608 {
2609 xIH->handle( xRequest );
2610
2612 = xRequest->getSelection();
2613
2614 if ( xSelection.is() )
2615 {
2616 // Handler handled the request.
2617 uno::Reference< task::XInteractionAbort > xAbort(
2618 xSelection.get(), uno::UNO_QUERY );
2619 if ( xAbort.is() )
2620 {
2621 throw ucb::CommandFailedException(
2622 "Abort requested by Interaction Handler.",
2623 uno::Reference< uno::XInterface >(),
2624 xRequest->getRequest() );
2625 }
2626
2627 uno::Reference< task::XInteractionPassword > xPassword(
2628 xSelection.get(), uno::UNO_QUERY );
2629 if ( xPassword.is() )
2630 {
2631 return xPassword->getPassword();
2632 }
2633
2634 // Unknown selection. Should never happen.
2635 throw ucb::CommandFailedException(
2636 "Interaction Handler selected unknown continuation!",
2637 uno::Reference< uno::XInterface >(),
2638 xRequest->getRequest() );
2639 }
2640 }
2641 }
2642
2643 // No IH or IH did not handle exception.
2644 task::DocumentPasswordRequest aRequest;
2645 xRequest->getRequest() >>= aRequest;
2646 throw aRequest;
2647}
2648
2649
2650uno::Reference< io::XInputStream > Content::getInputStream(
2651 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2652{
2653 OUString aUri;
2654 OUString aPassword;
2655 bool bPasswordRequested = false;
2656
2657 {
2658 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2659
2660 OSL_ENSURE( m_aProps.getType() == STREAM,
2661 "Content::getInputStream - content is no stream!" );
2662
2663 aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2664 }
2665
2666 for ( ;; )
2667 {
2668 try
2669 {
2670 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2671 return m_pProvider->queryInputStream( aUri, aPassword );
2672 }
2673 catch ( packages::WrongPasswordException const & )
2674 {
2675 // Obtain (new) password.
2676 aPassword
2677 = obtainPassword( aUri, /* @@@ find better title */
2678 bPasswordRequested
2679 ? task::PasswordRequestMode_PASSWORD_REENTER
2680 : task::PasswordRequestMode_PASSWORD_ENTER,
2681 xEnv );
2682 bPasswordRequested = true;
2683 }
2684 }
2685}
2686
2690static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2691 const OUString & rUri,
2692 ContentProvider const * pProvider,
2693 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2694{
2695 OUString aPassword;
2696 bool bPasswordRequested = false;
2697 for ( ;; )
2698 {
2699 try
2700 {
2701 return pProvider->queryOutputStream(
2702 rUri, aPassword, true /* truncate */ );
2703 }
2704 catch ( packages::WrongPasswordException const & )
2705 {
2706 // Obtain (new) password.
2707 aPassword
2708 = obtainPassword( rUri, /* @@@ find better title */
2709 bPasswordRequested
2710 ? task::PasswordRequestMode_PASSWORD_REENTER
2711 : task::PasswordRequestMode_PASSWORD_ENTER,
2712 xEnv );
2713 bPasswordRequested = true;
2714 }
2715 }
2716}
2717
2718
2719uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2720 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2721{
2722 OSL_ENSURE( m_aProps.getType() == STREAM,
2723 "Content::getTruncatedOutputStream - content is no stream!" );
2724
2726 Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2728 xEnv );
2729}
2730
2731
2732uno::Reference< io::XStream > Content::getStream(
2733 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2734{
2735 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2736
2737 OSL_ENSURE( m_aProps.getType() == STREAM,
2738 "Content::getStream - content is no stream!" );
2739
2740 OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2741 OUString aPassword;
2742 bool bPasswordRequested = false;
2743 for ( ;; )
2744 {
2745 try
2746 {
2747 return m_pProvider->queryStream(
2748 aUri, aPassword, false /* no truncate */ );
2749 }
2750 catch ( packages::WrongPasswordException const & )
2751 {
2752 // Obtain (new) password.
2753 aPassword
2754 = obtainPassword( aUri, /* @@@ find better title */
2755 bPasswordRequested
2756 ? task::PasswordRequestMode_PASSWORD_REENTER
2757 : task::PasswordRequestMode_PASSWORD_ENTER,
2758 xEnv );
2759 bPasswordRequested = true;
2760 }
2761 }
2762}
2763
2764
2765// ContentProperties Implementation.
2766
2767
2768uno::Sequence< ucb::ContentInfo >
2770{
2771 if ( isContentCreator() )
2772 {
2773 uno::Sequence< beans::Property > aProps( 1 );
2774 aProps.getArray()[ 0 ] = beans::Property(
2775 "Title",
2776 -1,
2778 beans::PropertyAttribute::BOUND );
2779
2780 if ( getType() == DOCUMENT )
2781 {
2782 // streams cannot be created as direct children of document root
2783 uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2784
2785 // Folder.
2786 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2787 aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2788 aSeq.getArray()[ 0 ].Properties = aProps;
2789
2790 return aSeq;
2791 }
2792 else
2793 {
2794 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2795
2796 // Folder.
2797 aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2798 aSeq.getArray()[ 0 ].Attributes
2799 = ucb::ContentInfoAttribute::KIND_FOLDER;
2800 aSeq.getArray()[ 0 ].Properties = aProps;
2801
2802 // Stream.
2803 aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2804 aSeq.getArray()[ 1 ].Attributes
2805 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2806 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2807 aSeq.getArray()[ 1 ].Properties = aProps;
2808
2809 return aSeq;
2810 }
2811 }
2812 else
2813 {
2814 OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2815 "object!" );
2816
2817 return uno::Sequence< ucb::ContentInfo >( 0 );
2818 }
2819}
2820
2821
2823{
2824 return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2825}
2826
2827/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const PropertyValue * pValues
PropertiesInfo aProperties
Reference< XInputStream > xStream
AnyEventRef aEvent
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
ContentType getType() const
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
const OUString & getContentType() const
void setTitle(const OUString &rTitle)
const OUString & getTitle() const
OUString queryStorageTitle(const OUString &rUri) const
css::uno::Reference< css::io::XOutputStream > queryOutputStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
css::uno::Reference< css::io::XInputStream > queryInputStream(const OUString &rUri, const OUString &rPassword) const
css::uno::Reference< css::embed::XStorage > queryStorageClone(const OUString &rUri) const
css::uno::Reference< css::frame::XModel > queryDocumentModel(const OUString &rUri) const
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL queryContent(const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier) override
css::uno::Reference< css::io::XStream > queryStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
css::uno::Reference< css::embed::XStorage > queryStorage(const OUString &rUri, StorageAccessMode eMode) const
static bool hasData(ContentProvider const *pProvider, const Uri &rUri)
static bool commitStorage(const css::uno::Reference< css::embed::XStorage > &xStorage)
css::uno::Reference< css::io::XOutputStream > getTruncatedOutputStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier() override
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
void renameData(const css::uno::Reference< css::ucb::XContentIdentifier > &xOldId, const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
bool copyData(const Uri &rSourceUri, const OUString &rNewName)
virtual css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL queryCreatableContentsInfo() override
ContentProvider * m_pProvider
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
ContentState m_eState
void insert(const css::uno::Reference< css::io::XInputStream > &xData, sal_Int32 nNameClashResolve, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
std::vector< ContentRef > ContentRefList
css::uno::Any open(const css::ucb::OpenCommandArgument2 &rArg, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void destroy(bool bDeletePhysical, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createNewContent(const css::ucb::ContentInfo &Info) override
rtl::Reference< Content > ContentRef
static rtl::Reference< Content > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties)
void notifyChildInserted(std::u16string_view rRelativeChildUri)
css::uno::Reference< css::io::XStream > getStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::io::XInputStream > getInputStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void notifyChildRemoved(std::u16string_view rRelativeChildUri)
virtual OUString SAL_CALL getImplementationName() override
void transfer(const css::ucb::TransferInfo &rInfo, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual void SAL_CALL acquire() noexcept override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
css::uno::Reference< css::ucb::XContentIdentifier > makeNewIdentifier(const OUString &rTitle)
virtual void SAL_CALL release() noexcept override
static bool closeOutputStream(const css::uno::Reference< css::io::XOutputStream > &xOut)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
bool storeData(const css::uno::Reference< css::io::XInputStream > &xData, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void queryChildren(ContentRefList &rChildren)
virtual OUString SAL_CALL getContentType() override
virtual void SAL_CALL abort(sal_Int32 CommandId) override
virtual OUString getParentURL() override
ContentProperties m_aProps
static bool loadData(ContentProvider const *pProvider, const Uri &rUri, ContentProperties &rProps)
Content(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier, const ContentProperties &rProps)
css::uno::Reference< css::ucb::XContent > queryChildContent(std::u16string_view rRelativeChildUri)
bool isRoot() const
Definition: tdoc_uri.hxx:92
const OUString & getDecodedName() const
Definition: tdoc_uri.hxx:73
const OUString & getParentUri() const
Definition: tdoc_uri.hxx:64
const OUString & getUri() const
Definition: tdoc_uri.hxx:59
bool isDocument() const
Definition: tdoc_uri.hxx:98
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(bool bCreate)
css::uno::Reference< css::ucb::XCommandInfo > getCommandInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
bool renameAdditionalPropertySet(const OUString &rOldKey, const OUString &rNewKey)
rtl::Reference< ContentProviderImplHelper > m_xProvider
void notifyContentEvent(const css::ucb::ContentEvent &evt) const
bool copyAdditionalPropertySet(const OUString &rSourceKey, const OUString &rTargetKey)
bool exchange(const css::uno::Reference< css::ucb::XContentIdentifier > &rNewId)
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
css::uno::Reference< css::ucb::XContentIdentifier > m_xIdentifier
css::uno::Reference< css::uno::XComponentContext > m_xContext
void notifyPropertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent > &evt) const
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
int nCount
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
float u
Reference< XInterface > xTarget
DocumentType eType
Mode eMode
sal_Int64 n
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define CPPU_TYPE_REF(T)
aBuf
Reference< XRow > xRow
Reference< XContentIdentifier > xId
OUString aId
const ContentProperties & rData
constexpr OUStringLiteral aData
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Type
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
Info
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
constexpr OUStringLiteral TDOC_ROOT_CONTENT_TYPE
constexpr OUStringLiteral TDOC_STREAM_CONTENT_TYPE
constexpr OUStringLiteral TDOC_DOCUMENT_CONTENT_TYPE
@ READ_WRITE_NOCREATE
@ READ_WRITE_CREATE
constexpr OUStringLiteral TDOC_FOLDER_CONTENT_TYPE
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:29
std::vector< ContentImplHelperRef > ContentRefList
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
uno::Sequence< beans::Property > m_aProps
bool hasValue()
static OUString obtainPassword(const OUString &rName, task::PasswordRequestMode eMode, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
static ContentType lcl_getContentType(std::u16string_view rType)
XTYPEPROVIDER_COMMON_IMPL(Content)
static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(const OUString &rUri, ContentProvider const *pProvider, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
#define TDOC_URL_SCHEME_LENGTH
Definition: tdoc_uri.hxx:28
#define TDOC_URL_SCHEME
Definition: tdoc_uri.hxx:27
OUString aCommand
std::unique_ptr< char[]> aBuffer