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"
77 #include "tdoc_passwordrequest.hxx"
78 
79 #include "../inc/urihelper.hxx"
80 
81 using namespace com::sun::star;
82 using namespace tdoc_ucp;
83 
84 
85 static 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 )
107 rtl::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 )
124 rtl::Reference<Content> Content::create(
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 
133  if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
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 
143 Content::Content(
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()
157 Content::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
171 Content::~Content()
172 {
173 }
174 
175 
176 // XInterface methods.
177 
178 
179 // virtual
180 void SAL_CALL Content::acquire()
181  noexcept
182 {
183  ContentImplHelper::acquire();
184 }
185 
186 
187 // virtual
188 void SAL_CALL Content::release()
189  noexcept
190 {
191  ContentImplHelper::release();
192 }
193 
194 
195 // virtual
196 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
197 {
198  uno::Any aRet = ContentImplHelper::queryInterface( rType );
199 
200  if ( !aRet.hasValue() )
201  {
202  aRet = cppu::queryInterface(
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
222 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
223 {
224  if ( m_aProps.isContentCreator() )
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
271 uno::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
294 OUString SAL_CALL Content::getContentType()
295 {
296  osl::Guard< osl::Mutex > aGuard( m_aMutex );
297  return m_aProps.getContentType();
298 }
299 
300 
301 // virtual
302 uno::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
323 uno::Any SAL_CALL Content::execute(
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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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 
479  ContentType eType = m_aProps.getType();
480  if ( ( eType != FOLDER ) && ( eType != STREAM ) )
481  {
483  uno::makeAny( 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 
525  ContentType eType = m_aProps.getType();
526  if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
527  {
529  uno::makeAny( 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::makeAny( 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 
563  ContentType eType = m_aProps.getType();
564  if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
565  {
567  uno::makeAny( 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::makeAny( 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::makeAny( ucb::UnsupportedCommandException(
601  OUString(),
602  static_cast< cppu::OWeakObject * >( this ) ) ),
603  Environment );
604  // Unreachable
605  }
606 
607  return aRet;
608 }
609 
610 
611 // virtual
612 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
613 {
614 }
615 
616 
617 // XContentCreator methods.
618 
619 
620 // virtual
621 uno::Sequence< ucb::ContentInfo > SAL_CALL
623 {
625 }
626 
627 
628 // virtual
629 uno::Reference< ucb::XContent > SAL_CALL
630 Content::createNewContent( const ucb::ContentInfo& Info )
631 {
632  if ( m_aProps.isContentCreator() )
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 
689 uno::Reference< ucb::XContentIdentifier >
690 Content::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.
772  ContentType eType = m_aProps.getType();
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
829 uno::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
855 uno::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(
895  rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
896  }
897  else if ( rProp.Name == "Storage" )
898  {
899  // Storage is only supported by folders.
900  ContentType eType = rData.getType();
901  if ( eType == FOLDER )
902  xRow->appendObject(
903  rProp,
904  uno::makeAny(
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.
912  ContentType eType = rData.getType();
913  if ( eType == DOCUMENT )
914  xRow->appendObject(
915  rProp,
916  uno::makeAny(
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 ),
960  rData.getContentType() );
961 
962  ContentType eType = rData.getType();
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 ),
980  rData.getIsDocument() );
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 ),
995  uno::makeAny( rData.getCreatableContentsInfo() ) );
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::makeAny( 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::makeAny(
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 
1029 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1030  const uno::Sequence< beans::Property >& rProperties )
1031 {
1032  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1033  return getPropertyValues( m_xContext,
1034  rProperties,
1035  m_aProps,
1036  m_pProvider,
1037  m_xIdentifier->getContentIdentifier() );
1038 }
1039 
1040 
1041 uno::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  uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1049  sal_Int32 nChanged = 0;
1050 
1051  beans::PropertyChangeEvent aEvent;
1052  aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1053  aEvent.Further = false;
1054  // aEvent.PropertyName =
1055  aEvent.PropertyHandle = -1;
1056  // aEvent.OldValue =
1057  // aEvent.NewValue =
1058 
1059  const beans::PropertyValue* pValues = rValues.getConstArray();
1060  sal_Int32 nCount = rValues.getLength();
1061 
1062  uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1063  bool bTriedToGetAdditionalPropSet = false;
1064 
1065  bool bExchange = false;
1066  OUString aOldTitle;
1067  sal_Int32 nTitlePos = -1;
1068 
1069  for ( sal_Int32 n = 0; n < nCount; ++n )
1070  {
1071  const beans::PropertyValue& rValue = pValues[ n ];
1072 
1073  if ( rValue.Name == "ContentType" )
1074  {
1075  // Read-only property!
1076  aRet[ n ] <<= lang::IllegalAccessException(
1077  "Property is read-only!",
1078  static_cast< cppu::OWeakObject * >( this ) );
1079  }
1080  else if ( rValue.Name == "IsDocument" )
1081  {
1082  // Read-only property!
1083  aRet[ n ] <<= lang::IllegalAccessException(
1084  "Property is read-only!",
1085  static_cast< cppu::OWeakObject * >( this ) );
1086  }
1087  else if ( rValue.Name == "IsFolder" )
1088  {
1089  // Read-only property!
1090  aRet[ n ] <<= lang::IllegalAccessException(
1091  "Property is read-only!",
1092  static_cast< cppu::OWeakObject * >( this ) );
1093  }
1094  else if ( rValue.Name == "CreatableContentsInfo" )
1095  {
1096  // Read-only property!
1097  aRet[ n ] <<= lang::IllegalAccessException(
1098  "Property is read-only!",
1099  static_cast< cppu::OWeakObject * >( this ) );
1100  }
1101  else if ( rValue.Name == "Title" )
1102  {
1103  // Title is read-only for root and documents.
1104  ContentType eType = m_aProps.getType();
1105  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1106  {
1107  aRet[ n ] <<= lang::IllegalAccessException(
1108  "Property is read-only!",
1109  static_cast< cppu::OWeakObject * >( this ) );
1110  }
1111  else
1112  {
1113  OUString aNewValue;
1114  if ( rValue.Value >>= aNewValue )
1115  {
1116  // No empty titles!
1117  if ( !aNewValue.isEmpty() )
1118  {
1119  if ( aNewValue != m_aProps.getTitle() )
1120  {
1121  // modified title -> modified URL -> exchange !
1122  if ( m_eState == PERSISTENT )
1123  bExchange = true;
1124 
1125  aOldTitle = m_aProps.getTitle();
1126  m_aProps.setTitle( aNewValue );
1127 
1128  // property change event will be sent later...
1129 
1130  // remember position within sequence of values
1131  // (for error handling).
1132  nTitlePos = n;
1133  }
1134  }
1135  else
1136  {
1137  aRet[ n ] <<= lang::IllegalArgumentException(
1138  "Empty Title not allowed!",
1139  static_cast< cppu::OWeakObject * >( this ),
1140  -1 );
1141  }
1142  }
1143  else
1144  {
1145  aRet[ n ] <<= beans::IllegalTypeException(
1146  "Title Property value has wrong type!",
1147  static_cast< cppu::OWeakObject * >( this ) );
1148  }
1149  }
1150  }
1151  else if ( rValue.Name == "Storage" )
1152  {
1153  ContentType eType = m_aProps.getType();
1154  if ( eType == FOLDER )
1155  {
1156  aRet[ n ] <<= lang::IllegalAccessException(
1157  "Property is read-only!",
1158  static_cast< cppu::OWeakObject * >( this ) );
1159  }
1160  else
1161  {
1162  // Storage is only supported by folders.
1163  aRet[ n ] <<= beans::UnknownPropertyException(
1164  "Storage property only supported by folders",
1165  static_cast< cppu::OWeakObject * >( this ) );
1166  }
1167  }
1168  else if ( rValue.Name == "DocumentModel" )
1169  {
1170  ContentType eType = m_aProps.getType();
1171  if ( eType == DOCUMENT )
1172  {
1173  aRet[ n ] <<= lang::IllegalAccessException(
1174  "Property is read-only!",
1175  static_cast< cppu::OWeakObject * >( this ) );
1176  }
1177  else
1178  {
1179  // Storage is only supported by folders.
1180  aRet[ n ] <<= beans::UnknownPropertyException(
1181  "DocumentModel property only supported by documents",
1182  static_cast< cppu::OWeakObject * >( this ) );
1183  }
1184  }
1185  else
1186  {
1187  // Not a Core Property! Maybe it's an Additional Core Property?!
1188 
1189  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1190  {
1191  xAdditionalPropSet = getAdditionalPropertySet( false );
1192  bTriedToGetAdditionalPropSet = true;
1193  }
1194 
1195  if ( xAdditionalPropSet.is() )
1196  {
1197  try
1198  {
1199  uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1200  rValue.Name );
1201  if ( aOldValue != rValue.Value )
1202  {
1203  xAdditionalPropSet->setPropertyValue(
1204  rValue.Name, rValue.Value );
1205 
1206  aEvent.PropertyName = rValue.Name;
1207  aEvent.OldValue = aOldValue;
1208  aEvent.NewValue = rValue.Value;
1209 
1210  aChanges.getArray()[ nChanged ] = aEvent;
1211  nChanged++;
1212  }
1213  }
1214  catch ( beans::UnknownPropertyException const & e )
1215  {
1216  aRet[ n ] <<= e;
1217  }
1218  catch ( lang::WrappedTargetException const & e )
1219  {
1220  aRet[ n ] <<= e;
1221  }
1222  catch ( beans::PropertyVetoException const & e )
1223  {
1224  aRet[ n ] <<= e;
1225  }
1226  catch ( lang::IllegalArgumentException const & e )
1227  {
1228  aRet[ n ] <<= e;
1229  }
1230  }
1231  else
1232  {
1233  aRet[ n ] <<= uno::Exception(
1234  "No property set for storing the value!",
1235  static_cast< cppu::OWeakObject * >( this ) );
1236  }
1237  }
1238  }
1239 
1240  if ( bExchange )
1241  {
1242  uno::Reference< ucb::XContentIdentifier > xOldId
1243  = m_xIdentifier;
1244  uno::Reference< ucb::XContentIdentifier > xNewId
1246 
1247  aGuard.clear();
1248  if ( exchangeIdentity( xNewId ) )
1249  {
1250  // Adapt persistent data.
1251  renameData( xOldId, xNewId );
1252 
1253  // Adapt Additional Core Properties.
1254  renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1255  xNewId->getContentIdentifier() );
1256  }
1257  else
1258  {
1259  // Roll-back.
1260  m_aProps.setTitle( aOldTitle );
1261  aOldTitle.clear();
1262 
1263  // Set error .
1264  aRet[ nTitlePos ] <<= uno::Exception(
1265  "Exchange failed!",
1266  static_cast< cppu::OWeakObject * >( this ) );
1267  }
1268  }
1269 
1270  if ( !aOldTitle.isEmpty() )
1271  {
1272  aEvent.PropertyName = "Title";
1273  aEvent.OldValue <<= aOldTitle;
1274  aEvent.NewValue <<= m_aProps.getTitle();
1275 
1276  aChanges.getArray()[ nChanged ] = aEvent;
1277  nChanged++;
1278  }
1279 
1280  if ( nChanged > 0 )
1281  {
1282  // Save changes, if content was already made persistent.
1283  if ( !bExchange && ( m_eState == PERSISTENT ) )
1284  {
1285  if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1286  {
1287  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1288  {
1289  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1290  }));
1292  ucb::IOErrorCode_CANT_WRITE,
1293  aArgs,
1294  xEnv,
1295  "Cannot store persistent data!",
1296  this );
1297  // Unreachable
1298  }
1299  }
1300 
1301  aChanges.realloc( nChanged );
1302 
1303  aGuard.clear();
1304  notifyPropertiesChange( aChanges );
1305  }
1306 
1307  return aRet;
1308 }
1309 
1310 
1312  const ucb::OpenCommandArgument2& rArg,
1313  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1314 {
1315  if ( rArg.Mode == ucb::OpenMode::ALL ||
1316  rArg.Mode == ucb::OpenMode::FOLDERS ||
1317  rArg.Mode == ucb::OpenMode::DOCUMENTS )
1318  {
1319 
1320  // open command for a folder content
1321 
1322 
1323  uno::Reference< ucb::XDynamicResultSet > xSet
1324  = new DynamicResultSet( m_xContext, this, rArg );
1325  return uno::makeAny( xSet );
1326  }
1327  else
1328  {
1329 
1330  // open command for a document content
1331 
1332 
1333  if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1334  ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1335  {
1336  // Currently(?) unsupported.
1338  uno::makeAny( ucb::UnsupportedOpenModeException(
1339  OUString(),
1340  static_cast< cppu::OWeakObject * >( this ),
1341  sal_Int16( rArg.Mode ) ) ),
1342  xEnv );
1343  // Unreachable
1344  }
1345 
1346  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1347 
1348  uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1349  rArg.Sink, uno::UNO_QUERY );
1350  if ( xDataStreamer.is() )
1351  {
1352  // May throw CommandFailedException, DocumentPasswordRequest!
1353  uno::Reference< io::XStream > xStream = getStream( xEnv );
1354  if ( !xStream.is() )
1355  {
1356  // No interaction if we are not persistent!
1357  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1358  {
1359  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1360  }));
1362  ucb::IOErrorCode_CANT_READ,
1363  aArgs,
1364  m_eState == PERSISTENT
1365  ? xEnv
1366  : uno::Reference< ucb::XCommandEnvironment >(),
1367  "Got no data stream!",
1368  this );
1369  // Unreachable
1370  }
1371 
1372  // Done.
1373  xDataStreamer->setStream( xStream );
1374  }
1375  else
1376  {
1377  uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1378  if ( xOut.is() )
1379  {
1380  // PUSH: write data into xOut
1381 
1382  // May throw CommandFailedException, DocumentPasswordRequest!
1383  uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1384  if ( !xIn.is() )
1385  {
1386  // No interaction if we are not persistent!
1387  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1388  {
1389  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1390  }));
1392  ucb::IOErrorCode_CANT_READ,
1393  aArgs,
1394  m_eState == PERSISTENT
1395  ? xEnv
1396  : uno::Reference< ucb::XCommandEnvironment >(),
1397  "Got no data stream!",
1398  this );
1399  // Unreachable
1400  }
1401 
1402  try
1403  {
1404  uno::Sequence< sal_Int8 > aBuffer;
1405 
1406  while (true)
1407  {
1408  sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1409  if (!nRead)
1410  break;
1411  aBuffer.realloc( nRead );
1412  xOut->writeBytes( aBuffer );
1413  }
1414 
1415  xOut->closeOutput();
1416  }
1417  catch ( io::NotConnectedException const & )
1418  {
1419  // closeOutput, readSomeBytes, writeBytes
1420  }
1421  catch ( io::BufferSizeExceededException const & )
1422  {
1423  // closeOutput, readSomeBytes, writeBytes
1424  }
1425  catch ( io::IOException const & )
1426  {
1427  // closeOutput, readSomeBytes, writeBytes
1428  }
1429  }
1430  else
1431  {
1432  uno::Reference< io::XActiveDataSink > xDataSink(
1433  rArg.Sink, uno::UNO_QUERY );
1434  if ( xDataSink.is() )
1435  {
1436  // PULL: wait for client read
1437 
1438  // May throw CommandFailedException, DocumentPasswordRequest!
1439  uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1440  if ( !xIn.is() )
1441  {
1442  // No interaction if we are not persistent!
1443  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1444  {
1445  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1446  }));
1448  ucb::IOErrorCode_CANT_READ,
1449  aArgs,
1450  m_eState == PERSISTENT
1451  ? xEnv
1452  : uno::Reference<
1453  ucb::XCommandEnvironment >(),
1454  "Got no data stream!",
1455  this );
1456  // Unreachable
1457  }
1458 
1459  // Done.
1460  xDataSink->setInputStream( xIn );
1461  }
1462  else
1463  {
1465  uno::makeAny(
1466  ucb::UnsupportedDataSinkException(
1467  OUString(),
1468  static_cast< cppu::OWeakObject * >( this ),
1469  rArg.Sink ) ),
1470  xEnv );
1471  // Unreachable
1472  }
1473  }
1474  }
1475  }
1476 
1477  return uno::Any();
1478 }
1479 
1480 
1481 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1482  sal_Int32 nNameClashResolve,
1483  const uno::Reference<
1484  ucb::XCommandEnvironment > & xEnv )
1485 {
1486  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1487 
1488  ContentType eType = m_aProps.getType();
1489 
1490  OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1491  "insert command only supported by streams and folders!" );
1492 
1493  Uri aUri( m_xIdentifier->getContentIdentifier() );
1494 
1495 #if OSL_DEBUG_LEVEL > 0
1496  if ( eType == STREAM )
1497  {
1498  Uri aParentUri( aUri.getParentUri() );
1499  OSL_ENSURE( !aParentUri.isDocument(),
1500  "insert command not supported by streams that are direct "
1501  "children of document root!" );
1502  }
1503 #endif
1504 
1505  // Check, if all required properties were set.
1506  if ( eType == FOLDER )
1507  {
1508  // Required: Title
1509 
1510  if ( m_aProps.getTitle().isEmpty() )
1511  m_aProps.setTitle( aUri.getDecodedName() );
1512  }
1513  else // stream
1514  {
1515  // Required: data
1516 
1517  if ( !xData.is() )
1518  {
1520  uno::makeAny( ucb::MissingInputStreamException(
1521  OUString(),
1522  static_cast< cppu::OWeakObject * >( this ) ) ),
1523  xEnv );
1524  // Unreachable
1525  }
1526 
1527  // Required: Title
1528 
1529  if ( m_aProps.getTitle().isEmpty() )
1530  m_aProps.setTitle( aUri.getDecodedName() );
1531  }
1532 
1533  Uri aNewUri( aUri.getParentUri() + m_aProps.getTitle() );
1534 
1535  // Handle possible name clash...
1536  switch ( nNameClashResolve )
1537  {
1538  // fail.
1539  case ucb::NameClash::ERROR:
1540  if ( hasData( aNewUri ) )
1541  {
1543  uno::makeAny( ucb::NameClashException(
1544  OUString(),
1545  static_cast< cppu::OWeakObject * >( this ),
1546  task::InteractionClassification_ERROR,
1547  m_aProps.getTitle() ) ),
1548  xEnv );
1549  // Unreachable
1550  }
1551  break;
1552 
1553  // replace (possibly) existing object.
1554  case ucb::NameClash::OVERWRITE:
1555  break;
1556 
1557  // "invent" a new valid title.
1558  case ucb::NameClash::RENAME:
1559  if ( hasData( aNewUri ) )
1560  {
1561  sal_Int32 nTry = 0;
1562 
1563  do
1564  {
1565  OUStringBuffer aNew(aNewUri.getUri());
1566  aNew.append( "_" );
1567  aNew.append( ++nTry );
1568  aNewUri.setUri( aNew.makeStringAndClear() );
1569  }
1570  while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1571 
1572  if ( nTry == 1000 )
1573  {
1575  uno::makeAny(
1576  ucb::UnsupportedNameClashException(
1577  "Unable to resolve name clash!",
1578  static_cast< cppu::OWeakObject * >( this ),
1579  nNameClashResolve ) ),
1580  xEnv );
1581  // Unreachable
1582  }
1583  else
1584  {
1585  OUStringBuffer aNewTitle(m_aProps.getTitle());
1586  aNewTitle.append( "_" );
1587  aNewTitle.append( ++nTry );
1588  m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1589  }
1590  }
1591  break;
1592 
1593  case ucb::NameClash::KEEP: // deprecated
1594  case ucb::NameClash::ASK:
1595  default:
1596  if ( hasData( aNewUri ) )
1597  {
1599  uno::makeAny(
1600  ucb::UnsupportedNameClashException(
1601  OUString(),
1602  static_cast< cppu::OWeakObject * >( this ),
1603  nNameClashResolve ) ),
1604  xEnv );
1605  // Unreachable
1606  }
1607  break;
1608  }
1609 
1610  // Identifier changed?
1611  bool bNewId = ( aUri != aNewUri );
1612 
1613  if ( bNewId )
1614  {
1616  = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1617  }
1618 
1619  if ( !storeData( xData, xEnv ) )
1620  {
1621  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1622  {
1623  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1624  }));
1626  ucb::IOErrorCode_CANT_WRITE,
1627  aArgs,
1628  xEnv,
1629  "Cannot store persistent data!",
1630  this );
1631  // Unreachable
1632  }
1633 
1634  m_eState = PERSISTENT;
1635 
1636  if ( bNewId )
1637  {
1638  //loadData( m_pProvider, m_aUri, m_aProps );
1639 
1640  aGuard.clear();
1641  inserted();
1642  }
1643 }
1644 
1645 
1646 void Content::destroy( bool bDeletePhysical,
1647  const uno::Reference<
1648  ucb::XCommandEnvironment > & xEnv )
1649 {
1650  // @@@ take care about bDeletePhysical -> trashcan support
1651 
1652  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1653 
1654  ContentType eType = m_aProps.getType();
1655 
1656  OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1657  "delete command only supported by streams and folders!" );
1658 
1659  uno::Reference< ucb::XContent > xThis = this;
1660 
1661  // Persistent?
1662  if ( m_eState != PERSISTENT )
1663  {
1665  uno::makeAny( ucb::UnsupportedCommandException(
1666  "Not persistent!",
1667  static_cast< cppu::OWeakObject * >( this ) ) ),
1668  xEnv );
1669  // Unreachable
1670  }
1671 
1672  m_eState = DEAD;
1673 
1674  aGuard.clear();
1675  deleted();
1676 
1677  if ( eType == FOLDER )
1678  {
1679  // Process instantiated children...
1680 
1681  ContentRefList aChildren;
1682  queryChildren( aChildren );
1683 
1684  for ( auto& rChild : aChildren )
1685  {
1686  rChild->destroy( bDeletePhysical, xEnv );
1687  }
1688  }
1689 }
1690 
1691 
1693 {
1694  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1695 
1696  m_eState = DEAD;
1697 
1698  // @@@ anything else to reset or such?
1699 
1700  // callback follows!
1701  aGuard.clear();
1702 
1703  // Propagate destruction to content event listeners
1704  // Remove this from provider's content list.
1705  deleted();
1706 }
1707 
1708 
1709 uno::Reference< ucb::XContent >
1710 Content::queryChildContent( std::u16string_view rRelativeChildUri )
1711 {
1712  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1713 
1714  const OUString aMyId = getIdentifier()->getContentIdentifier();
1715  OUStringBuffer aBuf( aMyId );
1716  if ( !aMyId.endsWith("/") )
1717  aBuf.append( "/" );
1718  if ( !o3tl::starts_with(rRelativeChildUri, u"/") )
1719  aBuf.append( rRelativeChildUri );
1720  else
1721  aBuf.append( rRelativeChildUri.substr(1) );
1722 
1723  uno::Reference< ucb::XContentIdentifier > xChildId
1724  = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1725 
1726  uno::Reference< ucb::XContent > xChild;
1727  try
1728  {
1729  xChild = m_pProvider->queryContent( xChildId );
1730  }
1731  catch ( ucb::IllegalIdentifierException const & )
1732  {
1733  // handled below.
1734  }
1735 
1736  OSL_ENSURE( xChild.is(),
1737  "Content::queryChildContent - unable to create child content!" );
1738  return xChild;
1739 }
1740 
1741 
1742 void Content::notifyChildRemoved( std::u16string_view rRelativeChildUri )
1743 {
1744  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1745 
1746  // Ugly! Need to create child content object, just to fill event properly.
1747  uno::Reference< ucb::XContent > xChild
1748  = queryChildContent( rRelativeChildUri );
1749 
1750  if ( !xChild.is() )
1751  return;
1752 
1753  // callback follows!
1754  aGuard.clear();
1755 
1756  // Notify "REMOVED" event.
1757  ucb::ContentEvent aEvt(
1758  static_cast< cppu::OWeakObject * >( this ),
1759  ucb::ContentAction::REMOVED,
1760  xChild,
1761  getIdentifier() );
1762  notifyContentEvent( aEvt );
1763 }
1764 
1765 
1766 void Content::notifyChildInserted( std::u16string_view rRelativeChildUri )
1767 {
1768  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1769 
1770  // Ugly! Need to create child content object, just to fill event properly.
1771  uno::Reference< ucb::XContent > xChild
1772  = queryChildContent( rRelativeChildUri );
1773 
1774  if ( !xChild.is() )
1775  return;
1776 
1777  // callback follows!
1778  aGuard.clear();
1779 
1780  // Notify "INSERTED" event.
1781  ucb::ContentEvent aEvt(
1782  static_cast< cppu::OWeakObject * >( this ),
1783  ucb::ContentAction::INSERTED,
1784  xChild,
1785  getIdentifier() );
1786  notifyContentEvent( aEvt );
1787 }
1788 
1789 
1790 void Content::transfer(
1791  const ucb::TransferInfo& rInfo,
1792  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1793 {
1794  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1795 
1796  // Persistent?
1797  if ( m_eState != PERSISTENT )
1798  {
1800  uno::makeAny( ucb::UnsupportedCommandException(
1801  "Not persistent!",
1802  static_cast< cppu::OWeakObject * >( this ) ) ),
1803  xEnv );
1804  // Unreachable
1805  }
1806 
1807  // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1808 
1809  if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1810  {
1811  // Invalid length (to short).
1813  uno::makeAny( ucb::InteractiveBadTransferURLException(
1814  OUString(),
1815  static_cast< cppu::OWeakObject * >( this ) ) ),
1816  xEnv );
1817  // Unreachable
1818  }
1819 
1820  OUString aScheme
1821  = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1822  .toAsciiLowerCase();
1823  if ( aScheme != TDOC_URL_SCHEME ":/" )
1824  {
1825  // Invalid scheme.
1827  uno::makeAny( ucb::InteractiveBadTransferURLException(
1828  OUString(),
1829  static_cast< cppu::OWeakObject * >( this ) ) ),
1830  xEnv );
1831  // Unreachable
1832  }
1833 
1834  // Does source URI describe a tdoc folder or stream?
1835  Uri aSourceUri( rInfo.SourceURL );
1836  if ( !aSourceUri.isValid() )
1837  {
1839  uno::makeAny( lang::IllegalArgumentException(
1840  "Invalid source URI! Syntax!",
1841  static_cast< cppu::OWeakObject * >( this ),
1842  -1 ) ),
1843  xEnv );
1844  // Unreachable
1845  }
1846 
1847  if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1848  {
1850  uno::makeAny( lang::IllegalArgumentException(
1851  "Invalid source URI! Must describe a folder or stream!",
1852  static_cast< cppu::OWeakObject * >( this ),
1853  -1 ) ),
1854  xEnv );
1855  // Unreachable
1856  }
1857 
1858  // Is source not a parent of me / not me?
1859  OUString aId = m_xIdentifier->getContentIdentifier();
1860  sal_Int32 nPos = aId.lastIndexOf( '/' );
1861  if ( nPos != ( aId.getLength() - 1 ) )
1862  {
1863  // No trailing slash found. Append.
1864  aId += "/";
1865  }
1866 
1867  if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1868  {
1869  if ( aId.startsWith( rInfo.SourceURL ) )
1870  {
1871  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1872  {
1873  {"Uri", uno::Any(rInfo.SourceURL)}
1874  }));
1876  ucb::IOErrorCode_RECURSIVE,
1877  aArgs,
1878  xEnv,
1879  "Target is equal to or is a child of source!",
1880  this );
1881  // Unreachable
1882  }
1883  }
1884 
1885  if ( m_aProps.getType() == DOCUMENT )
1886  {
1887  bool bOK = false;
1888 
1889  uno::Reference< embed::XStorage > xStorage
1891  aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1892  if ( xStorage.is() )
1893  {
1894  try
1895  {
1896  if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1897  {
1899  uno::makeAny( lang::IllegalArgumentException(
1900  "Invalid source URI! "
1901  "Streams cannot be created as "
1902  "children of document root!",
1903  static_cast< cppu::OWeakObject * >(
1904  this ),
1905  -1 ) ),
1906  xEnv );
1907  // Unreachable
1908  }
1909  bOK = true;
1910  }
1911  catch ( container::NoSuchElementException const & )
1912  {
1913  // handled below.
1914  }
1915  catch ( lang::IllegalArgumentException const & )
1916  {
1917  // handled below.
1918  }
1919  catch ( embed::InvalidStorageException const & )
1920  {
1921  // handled below.
1922  }
1923  }
1924 
1925  if ( !bOK )
1926  {
1928  uno::makeAny( lang::IllegalArgumentException(
1929  "Invalid source URI! Unable to determine source type!",
1930  static_cast< cppu::OWeakObject * >( this ),
1931  -1 ) ),
1932  xEnv );
1933  // Unreachable
1934  }
1935  }
1936 
1937 
1938  // Copy data.
1939 
1940 
1941  OUString aNewName( !rInfo.NewTitle.isEmpty()
1942  ? rInfo.NewTitle
1943  : aSourceUri.getDecodedName() );
1944 
1945  if ( !copyData( aSourceUri, aNewName ) )
1946  {
1947  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1948  {
1949  {"Uri", uno::Any(rInfo.SourceURL)}
1950  }));
1952  ucb::IOErrorCode_CANT_WRITE,
1953  aArgs,
1954  xEnv,
1955  "Cannot copy data!",
1956  this );
1957  // Unreachable
1958  }
1959 
1960 
1961  // Copy own and all children's Additional Core Properties.
1962 
1963 
1964  OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1965  if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1966  aTargetUri += "/";
1967 
1968  if ( !rInfo.NewTitle.isEmpty() )
1969  aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1970  else
1971  aTargetUri += aSourceUri.getName();
1972 
1973  if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1974  {
1975  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1976  {
1977  {"Uri", uno::Any(rInfo.SourceURL)}
1978  }));
1980  ucb::IOErrorCode_CANT_WRITE,
1981  aArgs,
1982  xEnv,
1983  "Cannot copy additional properties!",
1984  this );
1985  // Unreachable
1986  }
1987 
1988 
1989  // Propagate new content.
1990 
1991 
1993  try
1994  {
1995  uno::Reference< ucb::XContentIdentifier > xTargetId
1996  = new ::ucbhelper::ContentIdentifier( aTargetUri );
1997 
1998  // Note: The static cast is okay here, because its sure that
1999  // m_xProvider is always the WebDAVContentProvider.
2000  xTarget = static_cast< Content * >(
2001  m_pProvider->queryContent( xTargetId ).get() );
2002 
2003  }
2004  catch ( ucb::IllegalIdentifierException const & )
2005  {
2006  // queryContent
2007  }
2008 
2009  if ( !xTarget.is() )
2010  {
2011  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2012  {
2013  {"Uri", uno::Any(aTargetUri)}
2014  }));
2016  ucb::IOErrorCode_CANT_READ,
2017  aArgs,
2018  xEnv,
2019  "Cannot instantiate target object!",
2020  this );
2021  // Unreachable
2022  }
2023 
2024  // Announce transferred content in its new folder.
2025  xTarget->inserted();
2026 
2027 
2028  // Remove source, if requested
2029 
2030 
2031  if ( !rInfo.MoveData )
2032  return;
2033 
2034  rtl::Reference< Content > xSource;
2035  try
2036  {
2037  uno::Reference< ucb::XContentIdentifier >
2038  xSourceId = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
2039 
2040  // Note: The static cast is okay here, because its sure
2041  // that m_xProvider is always the ContentProvider.
2042  xSource = static_cast< Content * >(
2043  m_xProvider->queryContent( xSourceId ).get() );
2044  }
2045  catch ( ucb::IllegalIdentifierException const & )
2046  {
2047  // queryContent
2048  }
2049 
2050  if ( !xSource.is() )
2051  {
2052  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2053  {
2054  {"Uri", uno::Any(rInfo.SourceURL)}
2055  }));
2057  ucb::IOErrorCode_CANT_READ,
2058  aArgs,
2059  xEnv,
2060  "Cannot instantiate target object!",
2061  this );
2062  // Unreachable
2063  }
2064 
2065  // Propagate destruction (recursively).
2066  xSource->destroy( true, xEnv );
2067 
2068  // Remove all persistent data of source and its children.
2069  if ( !xSource->removeData() )
2070  {
2071  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2072  {
2073  {"Uri", uno::Any(rInfo.SourceURL)}
2074  }));
2076  ucb::IOErrorCode_CANT_WRITE,
2077  aArgs,
2078  xEnv,
2079  "Cannot remove persistent data of source object!",
2080  this );
2081  // Unreachable
2082  }
2083 
2084  // Remove own and all children's Additional Core Properties.
2085  if ( xSource->removeAdditionalPropertySet() )
2086  return;
2087 
2088  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2089  {
2090  {"Uri", uno::Any(rInfo.SourceURL)}
2091  }));
2093  ucb::IOErrorCode_CANT_WRITE,
2094  aArgs,
2095  xEnv,
2096  "Cannot remove additional properties of source object!",
2097  this );
2098  // Unreachable
2099 }
2100 
2101 
2102 //static
2103 bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2104 {
2105  if ( rUri.isRoot() )
2106  {
2107  return true; // root has no storage
2108  }
2109  else if ( rUri.isDocument() )
2110  {
2111  uno::Reference< embed::XStorage > xStorage
2112  = pProvider->queryStorage( rUri.getUri(), READ );
2113  return xStorage.is();
2114  }
2115  else
2116  {
2117  // folder or stream
2118 
2119  // Ask parent storage. In case that rUri describes a stream,
2120  // ContentProvider::queryStorage( rUri ) would return null.
2121 
2122  uno::Reference< embed::XStorage > xStorage
2123  = pProvider->queryStorage( rUri.getParentUri(), READ );
2124 
2125  if ( !xStorage.is() )
2126  return false;
2127 
2128  return xStorage->hasByName( rUri.getDecodedName() );
2129  }
2130 }
2131 
2132 
2133 //static
2134 bool Content::loadData( ContentProvider const * pProvider,
2135  const Uri & rUri,
2136  ContentProperties& rProps )
2137 {
2138  if ( rUri.isRoot() ) // root has no storage, but can always be created
2139  {
2140  rProps
2142  ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2143  }
2144  else if ( rUri.isDocument() ) // document must have storage
2145  {
2146  uno::Reference< embed::XStorage > xStorage
2147  = pProvider->queryStorage( rUri.getUri(), READ );
2148 
2149  if ( !xStorage.is() )
2150  return false;
2151 
2152  rProps
2154  DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2155  }
2156  else // stream or folder; stream has no storage; folder has storage
2157  {
2158  uno::Reference< embed::XStorage > xStorage
2159  = pProvider->queryStorage( rUri.getParentUri(), READ );
2160 
2161  if ( !xStorage.is() )
2162  return false;
2163 
2164  // Check whether exists at all, is stream or folder
2165  try
2166  {
2167  // return: true -> folder
2168  // return: false -> stream
2169  // NoSuchElementException -> neither folder nor stream
2170  bool bIsFolder
2171  = xStorage->isStorageElement( rUri.getDecodedName() );
2172 
2173  rProps
2175  bIsFolder ? FOLDER : STREAM,
2176  pProvider->queryStorageTitle( rUri.getUri() ) );
2177  }
2178  catch ( container::NoSuchElementException const & )
2179  {
2180  // there is no element with such name
2181  //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2182  return false;
2183  }
2184  catch ( lang::IllegalArgumentException const & )
2185  {
2186  // an illegal argument is provided
2187  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2188  return false;
2189  }
2190  catch ( embed::InvalidStorageException const & )
2191  {
2192  // this storage is in invalid state for any reason
2193  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2194  return false;
2195  }
2196  }
2197  return true;
2198 }
2199 
2200 
2201 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2202  const uno::Reference<
2203  ucb::XCommandEnvironment >& xEnv )
2204 {
2205  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2206 
2207  ContentType eType = m_aProps.getType();
2208  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2209  {
2210  OSL_FAIL( "storeData not supported by root and documents!" );
2211  return false;
2212  }
2213 
2214  Uri aUri( m_xIdentifier->getContentIdentifier() );
2215 
2216  if ( eType == FOLDER )
2217  {
2218  uno::Reference< embed::XStorage > xStorage
2219  = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2220 
2221  if ( !xStorage.is() )
2222  return false;
2223 
2224  uno::Reference< beans::XPropertySet > xPropSet(
2225  xStorage, uno::UNO_QUERY );
2226  OSL_ENSURE( xPropSet.is(),
2227  "Content::storeData - Got no XPropertySet interface!" );
2228  if ( !xPropSet.is() )
2229  return false;
2230 
2231  try
2232  {
2233  // According to MBA, if no mediatype is set, folder and all
2234  // its contents will be lost on save of the document!!!
2235  xPropSet->setPropertyValue(
2236  "MediaType",
2237  uno::makeAny(
2238  OUString( // @@@ better mediatype
2239  "application/binary" ) ) );
2240  }
2241  catch ( beans::UnknownPropertyException const & )
2242  {
2243  OSL_FAIL( "Property MediaType not supported!" );
2244  return false;
2245  }
2246  catch ( beans::PropertyVetoException const & )
2247  {
2248  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2249  return false;
2250  }
2251  catch ( lang::IllegalArgumentException const & )
2252  {
2253  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2254  return false;
2255  }
2256  catch ( lang::WrappedTargetException const & )
2257  {
2258  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2259  return false;
2260  }
2261 
2262  if ( !commitStorage( xStorage ) )
2263  return false;
2264  }
2265  else if ( eType == STREAM )
2266  {
2267  // stream
2268 
2269  // Important: Parent storage and output stream must be kept alive until
2270  // changes have been committed!
2271  uno::Reference< embed::XStorage > xStorage
2273  aUri.getParentUri(), READ_WRITE_CREATE );
2274  uno::Reference< io::XOutputStream > xOut;
2275 
2276  if ( !xStorage.is() )
2277  return false;
2278 
2279  if ( xData.is() )
2280  {
2281  // May throw CommandFailedException, DocumentPasswordRequest!
2282  xOut = getTruncatedOutputStream( xEnv );
2283 
2284  OSL_ENSURE( xOut.is(), "No target data stream!" );
2285 
2286  try
2287  {
2288  uno::Sequence< sal_Int8 > aBuffer;
2289  while (true)
2290  {
2291  sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2292  if (!nRead)
2293  break;
2294  aBuffer.realloc( nRead );
2295  xOut->writeBytes( aBuffer );
2296  }
2297 
2298  closeOutputStream( xOut );
2299  }
2300  catch ( io::NotConnectedException const & )
2301  {
2302  // readSomeBytes, writeBytes
2303  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2304  closeOutputStream( xOut );
2305  return false;
2306  }
2307  catch ( io::BufferSizeExceededException const & )
2308  {
2309  // readSomeBytes, writeBytes
2310  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2311  closeOutputStream( xOut );
2312  return false;
2313  }
2314  catch ( io::IOException const & )
2315  {
2316  // readSomeBytes, writeBytes
2317  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2318  closeOutputStream( xOut );
2319  return false;
2320  }
2321  catch ( ... )
2322  {
2323  closeOutputStream( xOut );
2324  throw;
2325  }
2326  }
2327 
2328  // Commit changes.
2329  if ( !commitStorage( xStorage ) )
2330  return false;
2331  }
2332  else
2333  {
2334  OSL_FAIL( "Unknown content type!" );
2335  return false;
2336  }
2337  return true;
2338 }
2339 
2340 
2341 void Content::renameData(
2342  const uno::Reference< ucb::XContentIdentifier >& xOldId,
2343  const uno::Reference< ucb::XContentIdentifier >& xNewId )
2344 {
2345  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2346 
2347  ContentType eType = m_aProps.getType();
2348  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2349  {
2350  OSL_FAIL( "renameData not supported by root and documents!" );
2351  return;
2352  }
2353 
2354  Uri aOldUri( xOldId->getContentIdentifier() );
2355  uno::Reference< embed::XStorage > xStorage
2357  aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2358 
2359  if ( !xStorage.is() )
2360  return;
2361 
2362  try
2363  {
2364  Uri aNewUri( xNewId->getContentIdentifier() );
2365  xStorage->renameElement(
2366  aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2367  }
2368  catch ( embed::InvalidStorageException const & )
2369  {
2370  // this storage is in invalid state for any reason
2371  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2372  return;
2373  }
2374  catch ( lang::IllegalArgumentException const & )
2375  {
2376  // an illegal argument is provided
2377  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2378  return;
2379  }
2380  catch ( container::NoSuchElementException const & )
2381  {
2382  // there is no element with old name in this storage
2383  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2384  return;
2385  }
2386  catch ( container::ElementExistException const & )
2387  {
2388  // an element with new name already exists in this storage
2389  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2390  return;
2391  }
2392  catch ( io::IOException const & )
2393  {
2394  // in case of io errors during renaming
2395  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2396  return;
2397  }
2398  catch ( embed::StorageWrappedTargetException const & )
2399  {
2400  // wraps other exceptions
2401  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2402  return;
2403  }
2404 
2405  commitStorage( xStorage );
2406 }
2407 
2408 
2410 {
2411  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2412 
2413  ContentType eType = m_aProps.getType();
2414  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2415  {
2416  OSL_FAIL( "removeData not supported by root and documents!" );
2417  return false;
2418  }
2419 
2420  Uri aUri( m_xIdentifier->getContentIdentifier() );
2421  uno::Reference< embed::XStorage > xStorage
2423  aUri.getParentUri(), READ_WRITE_NOCREATE );
2424 
2425  if ( !xStorage.is() )
2426  return false;
2427 
2428  try
2429  {
2430  xStorage->removeElement( aUri.getDecodedName() );
2431  }
2432  catch ( embed::InvalidStorageException const & )
2433  {
2434  // this storage is in invalid state for any reason
2435  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2436  return false;
2437  }
2438  catch ( lang::IllegalArgumentException const & )
2439  {
2440  // an illegal argument is provided
2441  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2442  return false;
2443  }
2444  catch ( container::NoSuchElementException const & )
2445  {
2446  // there is no element with this name in this storage
2447  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2448  return false;
2449  }
2450  catch ( io::IOException const & )
2451  {
2452  // in case of io errors during renaming
2453  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2454  return false;
2455  }
2456  catch ( embed::StorageWrappedTargetException const & )
2457  {
2458  // wraps other exceptions
2459  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2460  return false;
2461  }
2462 
2463  return commitStorage( xStorage );
2464 }
2465 
2466 
2467 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2468 {
2469  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2470 
2471  ContentType eType = m_aProps.getType();
2472  if ( ( eType == ROOT ) || ( eType == STREAM ) )
2473  {
2474  OSL_FAIL( "copyData not supported by root and streams!" );
2475  return false;
2476  }
2477 
2478  Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2479  uno::Reference< embed::XStorage > xDestStorage
2480  = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2481 
2482  if ( !xDestStorage.is() )
2483  return false;
2484 
2485  uno::Reference< embed::XStorage > xSourceStorage
2486  = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2487 
2488  if ( !xSourceStorage.is() )
2489  return false;
2490 
2491  try
2492  {
2493  xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2494  xDestStorage,
2495  rNewName );
2496  }
2497  catch ( embed::InvalidStorageException const & )
2498  {
2499  // this storage is in invalid state for any reason
2500  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2501  return false;
2502  }
2503  catch ( lang::IllegalArgumentException const & )
2504  {
2505  // an illegal argument is provided
2506  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2507  return false;
2508  }
2509  catch ( container::NoSuchElementException const & )
2510  {
2511  // there is no element with this name in this storage
2512  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2513  return false;
2514  }
2515  catch ( container::ElementExistException const & )
2516  {
2517  // there is no element with this name in this storage
2518  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2519  return false;
2520  }
2521  catch ( io::IOException const & )
2522  {
2523  // in case of io errors during renaming
2524  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2525  return false;
2526  }
2527  catch ( embed::StorageWrappedTargetException const & )
2528  {
2529  // wraps other exceptions
2530  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2531  return false;
2532  }
2533 
2534  return commitStorage( xDestStorage );
2535 }
2536 
2537 
2538 // static
2539 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2540 {
2541  // Commit changes
2542  uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2543 
2544  OSL_ENSURE( xTO.is(),
2545  "Required interface css.embed.XTransactedObject missing!" );
2546  try
2547  {
2548  xTO->commit();
2549  }
2550  catch ( io::IOException const & )
2551  {
2552  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2553  return false;
2554  }
2555  catch ( lang::WrappedTargetException const & )
2556  {
2557  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2558  return false;
2559  }
2560 
2561  return true;
2562 }
2563 
2564 
2565 // static
2567  const uno::Reference< io::XOutputStream > & xOut )
2568 {
2569  if ( xOut.is() )
2570  {
2571  try
2572  {
2573  xOut->closeOutput();
2574  return true;
2575  }
2576  catch ( io::NotConnectedException const & )
2577  {
2578  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2579  }
2580  catch ( io::BufferSizeExceededException const & )
2581  {
2582  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2583  }
2584  catch ( io::IOException const & )
2585  {
2586  TOOLS_WARN_EXCEPTION("ucb.ucp", "");
2587  }
2588  }
2589  return false;
2590 }
2591 
2594 static OUString obtainPassword(
2595  const OUString & rName,
2596  task::PasswordRequestMode eMode,
2597  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2598 {
2600  = new DocumentPasswordRequest( eMode, rName );
2601 
2602  if ( xEnv.is() )
2603  {
2604  uno::Reference< task::XInteractionHandler > xIH
2605  = xEnv->getInteractionHandler();
2606  if ( xIH.is() )
2607  {
2608  xIH->handle( xRequest );
2609 
2611  = xRequest->getSelection();
2612 
2613  if ( xSelection.is() )
2614  {
2615  // Handler handled the request.
2616  uno::Reference< task::XInteractionAbort > xAbort(
2617  xSelection.get(), uno::UNO_QUERY );
2618  if ( xAbort.is() )
2619  {
2620  throw ucb::CommandFailedException(
2621  "Abort requested by Interaction Handler.",
2622  uno::Reference< uno::XInterface >(),
2623  xRequest->getRequest() );
2624  }
2625 
2626  uno::Reference< task::XInteractionPassword > xPassword(
2627  xSelection.get(), uno::UNO_QUERY );
2628  if ( xPassword.is() )
2629  {
2630  return xPassword->getPassword();
2631  }
2632 
2633  // Unknown selection. Should never happen.
2634  throw ucb::CommandFailedException(
2635  "Interaction Handler selected unknown continuation!",
2636  uno::Reference< uno::XInterface >(),
2637  xRequest->getRequest() );
2638  }
2639  }
2640  }
2641 
2642  // No IH or IH did not handle exception.
2643  task::DocumentPasswordRequest aRequest;
2644  xRequest->getRequest() >>= aRequest;
2645  throw aRequest;
2646 }
2647 
2648 
2649 uno::Reference< io::XInputStream > Content::getInputStream(
2650  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2651 {
2652  OUString aUri;
2653  OUString aPassword;
2654  bool bPasswordRequested = false;
2655 
2656  {
2657  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2658 
2659  OSL_ENSURE( m_aProps.getType() == STREAM,
2660  "Content::getInputStream - content is no stream!" );
2661 
2662  aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2663  }
2664 
2665  for ( ;; )
2666  {
2667  try
2668  {
2669  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2670  return m_pProvider->queryInputStream( aUri, aPassword );
2671  }
2672  catch ( packages::WrongPasswordException const & )
2673  {
2674  // Obtain (new) password.
2675  aPassword
2676  = obtainPassword( aUri, /* @@@ find better title */
2677  bPasswordRequested
2678  ? task::PasswordRequestMode_PASSWORD_REENTER
2679  : task::PasswordRequestMode_PASSWORD_ENTER,
2680  xEnv );
2681  bPasswordRequested = true;
2682  }
2683  }
2684 }
2685 
2689 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2690  const OUString & rUri,
2691  ContentProvider const * pProvider,
2692  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2693 {
2694  OUString aPassword;
2695  bool bPasswordRequested = false;
2696  for ( ;; )
2697  {
2698  try
2699  {
2700  return pProvider->queryOutputStream(
2701  rUri, aPassword, true /* truncate */ );
2702  }
2703  catch ( packages::WrongPasswordException const & )
2704  {
2705  // Obtain (new) password.
2706  aPassword
2707  = obtainPassword( rUri, /* @@@ find better title */
2708  bPasswordRequested
2709  ? task::PasswordRequestMode_PASSWORD_REENTER
2710  : task::PasswordRequestMode_PASSWORD_ENTER,
2711  xEnv );
2712  bPasswordRequested = true;
2713  }
2714  }
2715 }
2716 
2717 
2718 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2719  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2720 {
2721  OSL_ENSURE( m_aProps.getType() == STREAM,
2722  "Content::getTruncatedOutputStream - content is no stream!" );
2723 
2725  Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2726  m_pProvider,
2727  xEnv );
2728 }
2729 
2730 
2731 uno::Reference< io::XStream > Content::getStream(
2732  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2733 {
2734  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2735 
2736  OSL_ENSURE( m_aProps.getType() == STREAM,
2737  "Content::getStream - content is no stream!" );
2738 
2739  OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2740  OUString aPassword;
2741  bool bPasswordRequested = false;
2742  for ( ;; )
2743  {
2744  try
2745  {
2746  return m_pProvider->queryStream(
2747  aUri, aPassword, false /* no truncate */ );
2748  }
2749  catch ( packages::WrongPasswordException const & )
2750  {
2751  // Obtain (new) password.
2752  aPassword
2753  = obtainPassword( aUri, /* @@@ find better title */
2754  bPasswordRequested
2755  ? task::PasswordRequestMode_PASSWORD_REENTER
2756  : task::PasswordRequestMode_PASSWORD_ENTER,
2757  xEnv );
2758  bPasswordRequested = true;
2759  }
2760  }
2761 }
2762 
2763 
2764 // ContentProperties Implementation.
2765 
2766 
2767 uno::Sequence< ucb::ContentInfo >
2769 {
2770  if ( isContentCreator() )
2771  {
2772  uno::Sequence< beans::Property > aProps( 1 );
2773  aProps.getArray()[ 0 ] = beans::Property(
2774  "Title",
2775  -1,
2777  beans::PropertyAttribute::BOUND );
2778 
2779  if ( getType() == DOCUMENT )
2780  {
2781  // streams cannot be created as direct children of document root
2782  uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2783 
2784  // Folder.
2785  aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2786  aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2787  aSeq.getArray()[ 0 ].Properties = aProps;
2788 
2789  return aSeq;
2790  }
2791  else
2792  {
2793  uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2794 
2795  // Folder.
2796  aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2797  aSeq.getArray()[ 0 ].Attributes
2798  = ucb::ContentInfoAttribute::KIND_FOLDER;
2799  aSeq.getArray()[ 0 ].Properties = aProps;
2800 
2801  // Stream.
2802  aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2803  aSeq.getArray()[ 1 ].Attributes
2804  = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2805  | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2806  aSeq.getArray()[ 1 ].Properties = aProps;
2807 
2808  return aSeq;
2809  }
2810  }
2811  else
2812  {
2813  OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2814  "object!" );
2815 
2816  return uno::Sequence< ucb::ContentInfo >( 0 );
2817  }
2818 }
2819 
2820 
2822 {
2823  return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2824 }
2825 
2826 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XTYPEPROVIDER_COMMON_IMPL(Content)
css::uno::Reference< css::ucb::XContent > queryChildContent(std::u16string_view rRelativeChildUri)
Type
void transfer(const css::ucb::TransferInfo &rInfo, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::uno::XComponentContext > m_xContext
ContentType getType() const
URL aURL
bool hasValue()
std::vector< ContentImplHelperRef > ContentRefList
virtual void SAL_CALL release() noexcept override
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
bool getType(BSTR name, Type &type)
css::uno::Reference< css::frame::XModel > queryDocumentModel(const OUString &rUri) const
uno::Sequence< beans::Property > m_aProps
bool copyData(const Uri &rSourceUri, const OUString &rNewName)
css::uno::Reference< css::embed::XStorage > queryStorageClone(const OUString &rUri) const
#define TDOC_URL_SCHEME
Definition: tdoc_uri.hxx:27
Reference< XInterface > xTarget
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
sal_Int64 n
css::uno::Reference< css::io::XInputStream > queryInputStream(const OUString &rUri, const OUString &rPassword) const
css::uno::Reference< css::io::XStream > queryStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
aBuf
bool isDocument() const
Definition: tdoc_uri.hxx:98
bool isRoot() const
Definition: tdoc_uri.hxx:92
virtual OUString SAL_CALL getContentType() override
virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier() override
ContentState m_eState
void renameData(const css::uno::Reference< css::ucb::XContentIdentifier > &xOldId, const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
virtual css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL queryCreatableContentsInfo() override
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:29
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(bool bCreate)
OUString queryStorageTitle(const OUString &rUri) const
Reference< XInputStream > xStream
PropertiesInfo aProperties
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
int nCount
#define TDOC_FOLDER_CONTENT_TYPE
bool copyAdditionalPropertySet(const OUString &rSourceKey, const OUString &rTargetKey)
static bool closeOutputStream(const css::uno::Reference< css::io::XOutputStream > &xOut)
css::uno::Any open(const css::ucb::OpenCommandArgument2 &rArg, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Sequence< css::beans::Property > &rProperties)
#define TDOC_ROOT_CONTENT_TYPE
void notifyPropertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent > &evt) const
rtl::Reference< Content > ContentRef
ContentProvider * m_pProvider
static OUString obtainPassword(const OUString &rName, task::PasswordRequestMode eMode, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL queryContent(const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier) override
virtual void SAL_CALL abort(sal_Int32 CommandId) override
bool renameAdditionalPropertySet(const OUString &rOldKey, const OUString &rNewKey)
constexpr OUStringLiteral aData
DocumentType eType
bool storeData(const css::uno::Reference< css::io::XInputStream > &xData, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
static ContentType lcl_getContentType(std::u16string_view rType)
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
#define TOOLS_WARN_EXCEPTION(area, stream)
const OUString & getDecodedName() const
Definition: tdoc_uri.hxx:73
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
void notifyChildRemoved(std::u16string_view rRelativeChildUri)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::uno::Reference< css::ucb::XContentIdentifier > m_xIdentifier
OUString aId
css::uno::Reference< css::io::XOutputStream > queryOutputStream(const OUString &rUri, const OUString &rPassword, bool bTruncate) const
#define TDOC_URL_SCHEME_LENGTH
Definition: tdoc_uri.hxx:28
static bool loadData(ContentProvider const *pProvider, const Uri &rUri, ContentProperties &rProps)
uno::Reference< sdbc::XRow > xRow
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
float u
ContentProperties m_aProps
Object Value
css::uno::Reference< css::ucb::XCommandInfo > getCommandInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createNewContent(const css::ucb::ContentInfo &Info) override
void notifyChildInserted(std::u16string_view rRelativeChildUri)
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(const OUString &rUri, ContentProvider const *pProvider, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
void insert(const css::uno::Reference< css::io::XInputStream > &xData, sal_Int32 nNameClashResolve, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
rtl::Reference< ContentProviderImplHelper > m_xProvider
css::uno::Reference< css::embed::XStorage > queryStorage(const OUString &rUri, StorageAccessMode eMode) const
const PropertyValue * pValues
std::unique_ptr< char[]> aBuffer
virtual void SAL_CALL acquire() noexcept override
static bool commitStorage(const css::uno::Reference< css::embed::XStorage > &xStorage)
#define CPPU_TYPE_REF(T)
uno::Reference< ucb::XContentIdentifier > xId
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
static rtl::Reference< Content > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
void destroy(bool bDeletePhysical, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::ucb::XContentIdentifier > makeNewIdentifier(const OUString &rTitle)
Sequence< sal_Int8 > aSeq
#define TDOC_DOCUMENT_CONTENT_TYPE
const OUString & getParentUri() const
Definition: tdoc_uri.hxx:64
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
css::uno::Reference< css::io::XStream > getStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
std::vector< ContentRef > ContentRefList
const OUString & getContentType() const
static bool hasData(ContentProvider const *pProvider, const Uri &rUri)
void setTitle(const OUString &rTitle)
css::uno::Reference< css::io::XOutputStream > getTruncatedOutputStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
bool exchange(const css::uno::Reference< css::ucb::XContentIdentifier > &rNewId)
virtual OUString SAL_CALL getImplementationName() override
virtual OUString getParentURL() override
void queryChildren(ContentRefList &rChildren)
void notifyContentEvent(const css::ucb::ContentEvent &evt) const
#define TDOC_STREAM_CONTENT_TYPE
const OUString & getTitle() const
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
AnyEventRef aEvent
sal_uInt16 nPos
const OUString & getUri() const
Definition: tdoc_uri.hxx:59
css::uno::Reference< css::io::XInputStream > getInputStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)