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 <osl/diagnose.h>
32 #include <rtl/ustrbuf.hxx>
33 #include <com/sun/star/beans/IllegalTypeException.hpp>
34 #include <com/sun/star/beans/PropertyAttribute.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/embed/InvalidStorageException.hpp>
37 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
38 #include <com/sun/star/embed/XTransactedObject.hpp>
39 #include <com/sun/star/io/BufferSizeExceededException.hpp>
40 #include <com/sun/star/io/IOException.hpp>
41 #include <com/sun/star/io/NotConnectedException.hpp>
42 #include <com/sun/star/io/XActiveDataSink.hpp>
43 #include <com/sun/star/io/XActiveDataStreamer.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/packages/WrongPasswordException.hpp>
46 #include <com/sun/star/task/DocumentPasswordRequest.hpp>
47 #include <com/sun/star/task/XInteractionPassword.hpp>
48 #include <com/sun/star/ucb/CommandFailedException.hpp>
49 #include <com/sun/star/ucb/ContentAction.hpp>
50 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
51 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
52 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
53 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
54 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
55 #include <com/sun/star/ucb/NameClash.hpp>
56 #include <com/sun/star/ucb/NameClashException.hpp>
57 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
58 #include <com/sun/star/ucb/OpenMode.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
61 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
62 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
63 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
64 #include <com/sun/star/ucb/XCommandInfo.hpp>
65 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
66 
72 #include <ucbhelper/macros.hxx>
73 
74 #include "tdoc_content.hxx"
75 #include "tdoc_resultset.hxx"
76 #include "tdoc_passwordrequest.hxx"
77 
78 #include "../inc/urihelper.hxx"
79 
80 using namespace com::sun::star;
81 using namespace tdoc_ucp;
82 
83 
84 static ContentType lcl_getContentType( const OUString & rType )
85 {
86  if ( rType == TDOC_ROOT_CONTENT_TYPE )
87  return ROOT;
88  else if ( rType == TDOC_DOCUMENT_CONTENT_TYPE )
89  return DOCUMENT;
90  else if ( rType == TDOC_FOLDER_CONTENT_TYPE )
91  return FOLDER;
92  else if ( rType == TDOC_STREAM_CONTENT_TYPE )
93  return STREAM;
94  else
95  {
96  OSL_FAIL( "Content::Content - unsupported content type string" );
97  return STREAM;
98  }
99 }
100 
101 
102 // Content Implementation.
103 
104 
105 // static ( "virtual" ctor )
106 Content* Content::create(
107  const uno::Reference< uno::XComponentContext >& rxContext,
108  ContentProvider* pProvider,
109  const uno::Reference< ucb::XContentIdentifier >& Identifier )
110 {
111  // Fail, if resource does not exist.
112  ContentProperties aProps;
113  if ( !Content::loadData( pProvider,
114  Uri( Identifier->getContentIdentifier() ),
115  aProps ) )
116  return nullptr;
117 
118  return new Content( rxContext, pProvider, Identifier, aProps );
119 }
120 
121 
122 // static ( "virtual" ctor )
123 Content* Content::create(
124  const uno::Reference< uno::XComponentContext >& rxContext,
125  ContentProvider* pProvider,
126  const uno::Reference< ucb::XContentIdentifier >& Identifier,
127  const ucb::ContentInfo& Info )
128 {
129  if ( Info.Type.isEmpty() )
130  return nullptr;
131 
132  if ( Info.Type != TDOC_FOLDER_CONTENT_TYPE && Info.Type != TDOC_STREAM_CONTENT_TYPE )
133  {
134  OSL_FAIL( "Content::create - unsupported content type!" );
135  return nullptr;
136  }
137 
138  return new Content( rxContext, pProvider, Identifier, Info );
139 }
140 
141 
142 Content::Content(
143  const uno::Reference< uno::XComponentContext > & rxContext,
144  ContentProvider * pProvider,
145  const uno::Reference< ucb::XContentIdentifier > & Identifier,
146  const ContentProperties & rProps )
147 : ContentImplHelper( rxContext, pProvider, Identifier ),
148  m_aProps( rProps ),
149  m_eState( PERSISTENT ),
150  m_pProvider( pProvider )
151 {
152 }
153 
154 
155 // ctor for a content just created via XContentCreator::createNewContent()
156 Content::Content(
157  const uno::Reference< uno::XComponentContext >& rxContext,
158  ContentProvider* pProvider,
159  const uno::Reference< ucb::XContentIdentifier >& Identifier,
160  const ucb::ContentInfo& Info )
161  : ContentImplHelper( rxContext, pProvider, Identifier ),
162  m_aProps( lcl_getContentType( Info.Type ), OUString() ), // no Title (yet)
163  m_eState( TRANSIENT ),
164  m_pProvider( pProvider )
165 {
166 }
167 
168 
169 // virtual
170 Content::~Content()
171 {
172 }
173 
174 
175 // XInterface methods.
176 
177 
178 // virtual
179 void SAL_CALL Content::acquire()
180  throw( )
181 {
182  ContentImplHelper::acquire();
183 }
184 
185 
186 // virtual
187 void SAL_CALL Content::release()
188  throw( )
189 {
190  ContentImplHelper::release();
191 }
192 
193 
194 // virtual
195 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
196 {
197  uno::Any aRet = ContentImplHelper::queryInterface( rType );
198 
199  if ( !aRet.hasValue() )
200  {
201  aRet = cppu::queryInterface(
202  rType, static_cast< ucb::XContentCreator * >( this ) );
203  if ( aRet.hasValue() )
204  {
205  if ( !m_aProps.isContentCreator() )
206  return uno::Any();
207  }
208  }
209 
210  return aRet;
211 }
212 
213 
214 // XTypeProvider methods.
215 
216 
218 
219 
220 // virtual
221 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
222 {
223  if ( m_aProps.isContentCreator() )
224  {
225  static cppu::OTypeCollection s_aFolderTypes(
226  CPPU_TYPE_REF( lang::XTypeProvider ),
227  CPPU_TYPE_REF( lang::XServiceInfo ),
228  CPPU_TYPE_REF( lang::XComponent ),
229  CPPU_TYPE_REF( ucb::XContent ),
230  CPPU_TYPE_REF( ucb::XCommandProcessor ),
231  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
232  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
233  CPPU_TYPE_REF( beans::XPropertyContainer ),
234  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
235  CPPU_TYPE_REF( container::XChild ),
236  CPPU_TYPE_REF( ucb::XContentCreator ) );
237 
238  return s_aFolderTypes.getTypes();
239  }
240  else
241  {
242  static cppu::OTypeCollection s_aDocumentTypes(
243  CPPU_TYPE_REF( lang::XTypeProvider ),
244  CPPU_TYPE_REF( lang::XServiceInfo ),
245  CPPU_TYPE_REF( lang::XComponent ),
246  CPPU_TYPE_REF( ucb::XContent ),
247  CPPU_TYPE_REF( ucb::XCommandProcessor ),
248  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
249  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
250  CPPU_TYPE_REF( beans::XPropertyContainer ),
251  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
252  CPPU_TYPE_REF( container::XChild ) );
253 
254  return s_aDocumentTypes.getTypes();
255  }
256 }
257 
258 
259 // XServiceInfo methods.
260 
261 
262 // virtual
264 {
265  return "com.sun.star.comp.ucb.TransientDocumentsContent";
266 }
267 
268 
269 // virtual
270 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
271 {
272  osl::Guard< osl::Mutex > aGuard( m_aMutex );
273 
274  uno::Sequence< OUString > aSNS( 1 );
275 
276  if ( m_aProps.getType() == STREAM )
277  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsStreamContent";
278  else if ( m_aProps.getType() == FOLDER )
279  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsFolderContent";
280  else if ( m_aProps.getType() == DOCUMENT )
281  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsDocumentContent";
282  else
283  aSNS.getArray()[ 0 ] = "com.sun.star.ucb.TransientDocumentsRootContent";
284 
285  return aSNS;
286 }
287 
288 
289 // XContent methods.
290 
291 
292 // virtual
293 OUString SAL_CALL Content::getContentType()
294 {
295  osl::Guard< osl::Mutex > aGuard( m_aMutex );
296  return m_aProps.getContentType();
297 }
298 
299 
300 // virtual
301 uno::Reference< ucb::XContentIdentifier > SAL_CALL
303 {
304  {
305  osl::Guard< osl::Mutex > aGuard( m_aMutex );
306 
307  // Transient?
308  if ( m_eState == TRANSIENT )
309  {
310  // Transient contents have no identifier.
311  return uno::Reference< ucb::XContentIdentifier >();
312  }
313  }
314  return ContentImplHelper::getIdentifier();
315 }
316 
317 
318 // XCommandProcessor methods.
319 
320 
321 // virtual
322 uno::Any SAL_CALL Content::execute(
323  const ucb::Command& aCommand,
324  sal_Int32 /*CommandId*/,
325  const uno::Reference< ucb::XCommandEnvironment >& Environment )
326 {
327  uno::Any aRet;
328 
329  if ( aCommand.Name == "getPropertyValues" )
330  {
331 
332  // getPropertyValues
333 
334 
335  uno::Sequence< beans::Property > Properties;
336  if ( !( aCommand.Argument >>= Properties ) )
337  {
339  uno::makeAny( lang::IllegalArgumentException(
340  "Wrong argument type!",
341  static_cast< cppu::OWeakObject * >( this ),
342  -1 ) ),
343  Environment );
344  // Unreachable
345  }
346 
347  aRet <<= getPropertyValues( Properties );
348  }
349  else if ( aCommand.Name == "setPropertyValues" )
350  {
351 
352  // setPropertyValues
353 
354 
355  uno::Sequence< beans::PropertyValue > aProperties;
356  if ( !( aCommand.Argument >>= aProperties ) )
357  {
359  uno::makeAny( lang::IllegalArgumentException(
360  "Wrong argument type!",
361  static_cast< cppu::OWeakObject * >( this ),
362  -1 ) ),
363  Environment );
364  // Unreachable
365  }
366 
367  if ( !aProperties.hasElements() )
368  {
370  uno::makeAny( lang::IllegalArgumentException(
371  "No properties!",
372  static_cast< cppu::OWeakObject * >( this ),
373  -1 ) ),
374  Environment );
375  // Unreachable
376  }
377 
378  aRet <<= setPropertyValues( aProperties, Environment );
379  }
380  else if ( aCommand.Name == "getPropertySetInfo" )
381  {
382 
383  // getPropertySetInfo
384 
385 
386  aRet <<= getPropertySetInfo( Environment );
387  }
388  else if ( aCommand.Name == "getCommandInfo" )
389  {
390 
391  // getCommandInfo
392 
393 
394  aRet <<= getCommandInfo( Environment );
395  }
396  else if ( aCommand.Name == "open" )
397  {
398 
399  // open
400 
401 
402  ucb::OpenCommandArgument2 aOpenCommand;
403  if ( !( aCommand.Argument >>= aOpenCommand ) )
404  {
406  uno::makeAny( lang::IllegalArgumentException(
407  "Wrong argument type!",
408  static_cast< cppu::OWeakObject * >( this ),
409  -1 ) ),
410  Environment );
411  // Unreachable
412  }
413 
414  aRet = open( aOpenCommand, Environment );
415  }
416  else if ( aCommand.Name == "insert" )
417  {
418 
419  // insert ( Supported by folders and streams only )
420 
421 
423  if ( ( eType != FOLDER ) && ( eType != STREAM ) )
424  {
426  uno::makeAny( ucb::UnsupportedCommandException(
427  "insert command only supported by "
428  "folders and streams!",
429  static_cast< cppu::OWeakObject * >( this ) ) ),
430  Environment );
431  // Unreachable
432  }
433 
434  if ( eType == STREAM )
435  {
436  Uri aUri( m_xIdentifier->getContentIdentifier() );
437  Uri aParentUri( aUri.getParentUri() );
438  if ( aParentUri.isDocument() )
439  {
441  uno::makeAny( ucb::UnsupportedCommandException(
442  "insert command not supported by "
443  "streams that are direct children "
444  "of document root!",
445  static_cast< cppu::OWeakObject * >(
446  this ) ) ),
447  Environment );
448  // Unreachable
449  }
450  }
451 
452  ucb::InsertCommandArgument aArg;
453  if ( !( aCommand.Argument >>= aArg ) )
454  {
456  uno::makeAny( lang::IllegalArgumentException(
457  "Wrong argument type!",
458  static_cast< cppu::OWeakObject * >( this ),
459  -1 ) ),
460  Environment );
461  // Unreachable
462  }
463 
464  sal_Int32 nNameClash = aArg.ReplaceExisting
465  ? ucb::NameClash::OVERWRITE
466  : ucb::NameClash::ERROR;
467  insert( aArg.Data, nNameClash, Environment );
468  }
469  else if ( aCommand.Name == "delete" )
470  {
471 
472  // delete ( Supported by folders and streams only )
473 
474 
475  {
476  osl::MutexGuard aGuard( m_aMutex );
477 
478  ContentType eType = m_aProps.getType();
479  if ( ( eType != FOLDER ) && ( eType != STREAM ) )
480  {
482  uno::makeAny( ucb::UnsupportedCommandException(
483  "delete command only supported by "
484  "folders and streams!",
485  static_cast< cppu::OWeakObject * >(
486  this ) ) ),
487  Environment );
488  // Unreachable
489  }
490  }
491 
492  bool bDeletePhysical = false;
493  aCommand.Argument >>= bDeletePhysical;
494  destroy( bDeletePhysical, Environment );
495 
496  // Remove own and all children's persistent data.
497  if ( !removeData() )
498  {
499  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
500  {
501  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
502  }));
504  ucb::IOErrorCode_CANT_WRITE,
505  aArgs,
506  Environment,
507  "Cannot remove persistent data!",
508  this );
509  // Unreachable
510  }
511 
512  // Remove own and all children's Additional Core Properties.
514  }
515  else if ( aCommand.Name == "transfer" )
516  {
517 
518  // transfer ( Supported by document and folders only )
519 
520 
521  {
522  osl::MutexGuard aGuard( m_aMutex );
523 
524  ContentType eType = m_aProps.getType();
525  if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
526  {
528  uno::makeAny( ucb::UnsupportedCommandException(
529  "transfer command only supported "
530  "by folders and documents!",
531  static_cast< cppu::OWeakObject * >(
532  this ) ) ),
533  Environment );
534  // Unreachable
535  }
536  }
537 
538  ucb::TransferInfo aInfo;
539  if ( !( aCommand.Argument >>= aInfo ) )
540  {
541  OSL_FAIL( "Wrong argument type!" );
543  uno::makeAny( lang::IllegalArgumentException(
544  "Wrong argument type!",
545  static_cast< cppu::OWeakObject * >( this ),
546  -1 ) ),
547  Environment );
548  // Unreachable
549  }
550 
551  transfer( aInfo, Environment );
552  }
553  else if ( aCommand.Name == "createNewContent" )
554  {
555 
556  // createNewContent ( Supported by document and folders only )
557 
558 
559  {
560  osl::MutexGuard aGuard( m_aMutex );
561 
562  ContentType eType = m_aProps.getType();
563  if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
564  {
566  uno::makeAny( ucb::UnsupportedCommandException(
567  "createNewContent command only "
568  "supported by folders and "
569  "documents!",
570  static_cast< cppu::OWeakObject * >(
571  this ) ) ),
572  Environment );
573  // Unreachable
574  }
575  }
576 
577  ucb::ContentInfo aInfo;
578  if ( !( aCommand.Argument >>= aInfo ) )
579  {
580  OSL_FAIL( "Wrong argument type!" );
582  uno::makeAny( lang::IllegalArgumentException(
583  "Wrong argument type!",
584  static_cast< cppu::OWeakObject * >( this ),
585  -1 ) ),
586  Environment );
587  // Unreachable
588  }
589 
590  aRet <<= createNewContent( aInfo );
591  }
592  else
593  {
594 
595  // Unsupported command
596 
597 
599  uno::makeAny( ucb::UnsupportedCommandException(
600  OUString(),
601  static_cast< cppu::OWeakObject * >( this ) ) ),
602  Environment );
603  // Unreachable
604  }
605 
606  return aRet;
607 }
608 
609 
610 // virtual
611 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
612 {
613 }
614 
615 
616 // XContentCreator methods.
617 
618 
619 // virtual
620 uno::Sequence< ucb::ContentInfo > SAL_CALL
622 {
624 }
625 
626 
627 // virtual
628 uno::Reference< ucb::XContent > SAL_CALL
629 Content::createNewContent( const ucb::ContentInfo& Info )
630 {
631  if ( m_aProps.isContentCreator() )
632  {
633  osl::Guard< osl::Mutex > aGuard( m_aMutex );
634 
635  if ( Info.Type.isEmpty() )
636  return uno::Reference< ucb::XContent >();
637 
638  bool bCreateFolder = Info.Type == TDOC_FOLDER_CONTENT_TYPE;
639 
640  // streams cannot be created as direct children of document root
641  if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
642  {
643  OSL_FAIL( "Content::createNewContent - streams cannot be "
644  "created as direct children of document root!" );
645  return uno::Reference< ucb::XContent >();
646  }
647  if ( !bCreateFolder && Info.Type != TDOC_STREAM_CONTENT_TYPE )
648  {
649  OSL_FAIL( "Content::createNewContent - unsupported type!" );
650  return uno::Reference< ucb::XContent >();
651  }
652 
653  OUString aURL = m_xIdentifier->getContentIdentifier();
654 
655  OSL_ENSURE( !aURL.isEmpty(),
656  "Content::createNewContent - empty identifier!" );
657 
658  if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
659  aURL += "/";
660 
661  if ( bCreateFolder )
662  aURL += "New_Folder";
663  else
664  aURL += "New_Stream";
665 
666  uno::Reference< ucb::XContentIdentifier > xId
667  = new ::ucbhelper::ContentIdentifier( aURL );
668 
669  return create( m_xContext, m_pProvider, xId, Info );
670  }
671  else
672  {
673  OSL_FAIL( "createNewContent called on non-contentcreator object!" );
674  return uno::Reference< ucb::XContent >();
675  }
676 }
677 
678 
679 // virtual
681 {
682  osl::Guard< osl::Mutex > aGuard( m_aMutex );
683  Uri aUri( m_xIdentifier->getContentIdentifier() );
684  return aUri.getParentUri();
685 }
686 
687 
688 uno::Reference< ucb::XContentIdentifier >
689 Content::makeNewIdentifier( const OUString& rTitle )
690 {
691  osl::Guard< osl::Mutex > aGuard( m_aMutex );
692 
693  // Assemble new content identifier...
694  Uri aUri( m_xIdentifier->getContentIdentifier() );
695  OUStringBuffer aNewURL = aUri.getParentUri();
696  aNewURL.append( ::ucb_impl::urihelper::encodeSegment( rTitle ) );
697 
698  return
699  uno::Reference< ucb::XContentIdentifier >(
700  new ::ucbhelper::ContentIdentifier( aNewURL.makeStringAndClear() ) );
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 identitity.
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 uno::Reference< sdbc::XRow >( xRow.get() );
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 uno::Reference< sdbc::XRow >( xRow.get() );
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  OUStringBuffer aNewURL = aUri.getParentUri();
1534  aNewURL.append( m_aProps.getTitle() );
1535  Uri aNewUri( aNewURL.makeStringAndClear() );
1536 
1537  // Handle possible name clash...
1538  switch ( nNameClashResolve )
1539  {
1540  // fail.
1541  case ucb::NameClash::ERROR:
1542  if ( hasData( aNewUri ) )
1543  {
1545  uno::makeAny( ucb::NameClashException(
1546  OUString(),
1547  static_cast< cppu::OWeakObject * >( this ),
1548  task::InteractionClassification_ERROR,
1549  m_aProps.getTitle() ) ),
1550  xEnv );
1551  // Unreachable
1552  }
1553  break;
1554 
1555  // replace (possibly) existing object.
1556  case ucb::NameClash::OVERWRITE:
1557  break;
1558 
1559  // "invent" a new valid title.
1560  case ucb::NameClash::RENAME:
1561  if ( hasData( aNewUri ) )
1562  {
1563  sal_Int32 nTry = 0;
1564 
1565  do
1566  {
1567  OUStringBuffer aNew = aNewUri.getUri();
1568  aNew.append( "_" );
1569  aNew.append( OUString::number( ++nTry ) );
1570  aNewUri.setUri( aNew.makeStringAndClear() );
1571  }
1572  while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1573 
1574  if ( nTry == 1000 )
1575  {
1577  uno::makeAny(
1578  ucb::UnsupportedNameClashException(
1579  "Unable to resolve name clash!",
1580  static_cast< cppu::OWeakObject * >( this ),
1581  nNameClashResolve ) ),
1582  xEnv );
1583  // Unreachable
1584  }
1585  else
1586  {
1587  OUStringBuffer aNewTitle = m_aProps.getTitle();
1588  aNewTitle.append( "_" );
1589  aNewTitle.append( OUString::number( ++nTry ) );
1590  m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1591  }
1592  }
1593  break;
1594 
1595  case ucb::NameClash::KEEP: // deprecated
1596  case ucb::NameClash::ASK:
1597  default:
1598  if ( hasData( aNewUri ) )
1599  {
1601  uno::makeAny(
1602  ucb::UnsupportedNameClashException(
1603  OUString(),
1604  static_cast< cppu::OWeakObject * >( this ),
1605  nNameClashResolve ) ),
1606  xEnv );
1607  // Unreachable
1608  }
1609  break;
1610  }
1611 
1612  // Identifier changed?
1613  bool bNewId = ( aUri != aNewUri );
1614 
1615  if ( bNewId )
1616  {
1618  = new ::ucbhelper::ContentIdentifier( aNewUri.getUri() );
1619  }
1620 
1621  if ( !storeData( xData, xEnv ) )
1622  {
1623  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1624  {
1625  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1626  }));
1628  ucb::IOErrorCode_CANT_WRITE,
1629  aArgs,
1630  xEnv,
1631  "Cannot store persistent data!",
1632  this );
1633  // Unreachable
1634  }
1635 
1636  m_eState = PERSISTENT;
1637 
1638  if ( bNewId )
1639  {
1640  //loadData( m_pProvider, m_aUri, m_aProps );
1641 
1642  aGuard.clear();
1643  inserted();
1644  }
1645 }
1646 
1647 
1648 void Content::destroy( bool bDeletePhysical,
1649  const uno::Reference<
1650  ucb::XCommandEnvironment > & xEnv )
1651 {
1652  // @@@ take care about bDeletePhysical -> trashcan support
1653 
1654  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1655 
1656  ContentType eType = m_aProps.getType();
1657 
1658  OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1659  "delete command only supported by streams and folders!" );
1660 
1661  uno::Reference< ucb::XContent > xThis = this;
1662 
1663  // Persistent?
1664  if ( m_eState != PERSISTENT )
1665  {
1667  uno::makeAny( ucb::UnsupportedCommandException(
1668  "Not persistent!",
1669  static_cast< cppu::OWeakObject * >( this ) ) ),
1670  xEnv );
1671  // Unreachable
1672  }
1673 
1674  m_eState = DEAD;
1675 
1676  aGuard.clear();
1677  deleted();
1678 
1679  if ( eType == FOLDER )
1680  {
1681  // Process instantiated children...
1682 
1683  ContentRefList aChildren;
1684  queryChildren( aChildren );
1685 
1686  for ( auto& rChild : aChildren )
1687  {
1688  rChild->destroy( bDeletePhysical, xEnv );
1689  }
1690  }
1691 }
1692 
1693 
1695 {
1696  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1697 
1698  m_eState = DEAD;
1699 
1700  // @@@ anything else to reset or such?
1701 
1702  // callback follows!
1703  aGuard.clear();
1704 
1705  // Propagate destruction to content event listeners
1706  // Remove this from provider's content list.
1707  deleted();
1708 }
1709 
1710 
1711 uno::Reference< ucb::XContent >
1712 Content::queryChildContent( const OUString & rRelativeChildUri )
1713 {
1714  osl::Guard< osl::Mutex > aGuard( m_aMutex );
1715 
1716  const OUString aMyId = getIdentifier()->getContentIdentifier();
1717  OUStringBuffer aBuf( aMyId );
1718  if ( !aMyId.endsWith("/") )
1719  aBuf.append( "/" );
1720  if ( !rRelativeChildUri.startsWith("/") )
1721  aBuf.append( rRelativeChildUri );
1722  else
1723  aBuf.append( std::u16string_view(rRelativeChildUri).substr(1) );
1724 
1725  uno::Reference< ucb::XContentIdentifier > xChildId
1726  = new ::ucbhelper::ContentIdentifier( aBuf.makeStringAndClear() );
1727 
1728  uno::Reference< ucb::XContent > xChild;
1729  try
1730  {
1731  xChild = m_pProvider->queryContent( xChildId );
1732  }
1733  catch ( ucb::IllegalIdentifierException const & )
1734  {
1735  // handled below.
1736  }
1737 
1738  OSL_ENSURE( xChild.is(),
1739  "Content::queryChildContent - unable to create child content!" );
1740  return xChild;
1741 }
1742 
1743 
1744 void Content::notifyChildRemoved( const OUString & rRelativeChildUri )
1745 {
1746  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1747 
1748  // Ugly! Need to create child content object, just to fill event properly.
1749  uno::Reference< ucb::XContent > xChild
1750  = queryChildContent( rRelativeChildUri );
1751 
1752  if ( xChild.is() )
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 
1767 
1768 void Content::notifyChildInserted( const OUString & rRelativeChildUri )
1769 {
1770  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1771 
1772  // Ugly! Need to create child content object, just to fill event properly.
1773  uno::Reference< ucb::XContent > xChild
1774  = queryChildContent( rRelativeChildUri );
1775 
1776  if ( xChild.is() )
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 
1791 
1792 void Content::transfer(
1793  const ucb::TransferInfo& rInfo,
1794  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1795 {
1796  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1797 
1798  // Persistent?
1799  if ( m_eState != PERSISTENT )
1800  {
1802  uno::makeAny( ucb::UnsupportedCommandException(
1803  "Not persistent!",
1804  static_cast< cppu::OWeakObject * >( this ) ) ),
1805  xEnv );
1806  // Unreachable
1807  }
1808 
1809  // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
1810 
1811  if ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 )
1812  {
1813  // Invalid length (to short).
1815  uno::makeAny( ucb::InteractiveBadTransferURLException(
1816  OUString(),
1817  static_cast< cppu::OWeakObject * >( this ) ) ),
1818  xEnv );
1819  // Unreachable
1820  }
1821 
1822  OUString aScheme
1823  = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
1824  .toAsciiLowerCase();
1825  if ( aScheme != TDOC_URL_SCHEME ":/" )
1826  {
1827  // Invalid scheme.
1829  uno::makeAny( ucb::InteractiveBadTransferURLException(
1830  OUString(),
1831  static_cast< cppu::OWeakObject * >( this ) ) ),
1832  xEnv );
1833  // Unreachable
1834  }
1835 
1836  // Does source URI describe a tdoc folder or stream?
1837  Uri aSourceUri( rInfo.SourceURL );
1838  if ( !aSourceUri.isValid() )
1839  {
1841  uno::makeAny( lang::IllegalArgumentException(
1842  "Invalid source URI! Syntax!",
1843  static_cast< cppu::OWeakObject * >( this ),
1844  -1 ) ),
1845  xEnv );
1846  // Unreachable
1847  }
1848 
1849  if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
1850  {
1852  uno::makeAny( lang::IllegalArgumentException(
1853  "Invalid source URI! Must describe a folder or stream!",
1854  static_cast< cppu::OWeakObject * >( this ),
1855  -1 ) ),
1856  xEnv );
1857  // Unreachable
1858  }
1859 
1860  // Is source not a parent of me / not me?
1861  OUString aId = m_xIdentifier->getContentIdentifier();
1862  sal_Int32 nPos = aId.lastIndexOf( '/' );
1863  if ( nPos != ( aId.getLength() - 1 ) )
1864  {
1865  // No trailing slash found. Append.
1866  aId += "/";
1867  }
1868 
1869  if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1870  {
1871  if ( aId.startsWith( rInfo.SourceURL ) )
1872  {
1873  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1874  {
1875  {"Uri", uno::Any(rInfo.SourceURL)}
1876  }));
1878  ucb::IOErrorCode_RECURSIVE,
1879  aArgs,
1880  xEnv,
1881  "Target is equal to or is a child of source!",
1882  this );
1883  // Unreachable
1884  }
1885  }
1886 
1887  if ( m_aProps.getType() == DOCUMENT )
1888  {
1889  bool bOK = false;
1890 
1891  uno::Reference< embed::XStorage > xStorage
1893  aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
1894  if ( xStorage.is() )
1895  {
1896  try
1897  {
1898  if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
1899  {
1901  uno::makeAny( lang::IllegalArgumentException(
1902  "Invalid source URI! "
1903  "Streams cannot be created as "
1904  "children of document root!",
1905  static_cast< cppu::OWeakObject * >(
1906  this ),
1907  -1 ) ),
1908  xEnv );
1909  // Unreachable
1910  }
1911  bOK = true;
1912  }
1913  catch ( container::NoSuchElementException const & )
1914  {
1915  // handled below.
1916  }
1917  catch ( lang::IllegalArgumentException const & )
1918  {
1919  // handled below.
1920  }
1921  catch ( embed::InvalidStorageException const & )
1922  {
1923  // handled below.
1924  }
1925  }
1926 
1927  if ( !bOK )
1928  {
1930  uno::makeAny( lang::IllegalArgumentException(
1931  "Invalid source URI! Unable to determine source type!",
1932  static_cast< cppu::OWeakObject * >( this ),
1933  -1 ) ),
1934  xEnv );
1935  // Unreachable
1936  }
1937  }
1938 
1939 
1940  // Copy data.
1941 
1942 
1943  OUString aNewName( !rInfo.NewTitle.isEmpty()
1944  ? rInfo.NewTitle
1945  : aSourceUri.getDecodedName() );
1946 
1947  if ( !copyData( aSourceUri, aNewName ) )
1948  {
1949  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1950  {
1951  {"Uri", uno::Any(rInfo.SourceURL)}
1952  }));
1954  ucb::IOErrorCode_CANT_WRITE,
1955  aArgs,
1956  xEnv,
1957  "Cannot copy data!",
1958  this );
1959  // Unreachable
1960  }
1961 
1962 
1963  // Copy own and all children's Additional Core Properties.
1964 
1965 
1966  OUString aTargetUri = m_xIdentifier->getContentIdentifier();
1967  if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
1968  aTargetUri += "/";
1969 
1970  if ( !rInfo.NewTitle.isEmpty() )
1971  aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
1972  else
1973  aTargetUri += aSourceUri.getName();
1974 
1975  if ( !copyAdditionalPropertySet( aSourceUri.getUri(), aTargetUri ) )
1976  {
1977  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1978  {
1979  {"Uri", uno::Any(rInfo.SourceURL)}
1980  }));
1982  ucb::IOErrorCode_CANT_WRITE,
1983  aArgs,
1984  xEnv,
1985  "Cannot copy additional properties!",
1986  this );
1987  // Unreachable
1988  }
1989 
1990 
1991  // Propagate new content.
1992 
1993 
1994  rtl::Reference< Content > xTarget;
1995  try
1996  {
1997  uno::Reference< ucb::XContentIdentifier > xTargetId
1998  = new ::ucbhelper::ContentIdentifier( aTargetUri );
1999 
2000  // Note: The static cast is okay here, because its sure that
2001  // m_xProvider is always the WebDAVContentProvider.
2002  xTarget = static_cast< Content * >(
2003  m_pProvider->queryContent( xTargetId ).get() );
2004 
2005  }
2006  catch ( ucb::IllegalIdentifierException const & )
2007  {
2008  // queryContent
2009  }
2010 
2011  if ( !xTarget.is() )
2012  {
2013  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
2014  {
2015  {"Uri", uno::Any(aTargetUri)}
2016  }));
2018  ucb::IOErrorCode_CANT_READ,
2019  aArgs,
2020  xEnv,
2021  "Cannot instantiate target object!",
2022  this );
2023  // Unreachable
2024  }
2025 
2026  // Announce transferred content in its new folder.
2027  xTarget->inserted();
2028 
2029 
2030  // Remove source, if requested
2031 
2032 
2033  if ( rInfo.MoveData )
2034  {
2035  rtl::Reference< Content > xSource;
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  {
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  } // rInfo.MoveData
2102 }
2103 
2104 
2105 //static
2106 bool Content::hasData( ContentProvider const * pProvider, const Uri & rUri )
2107 {
2108  if ( rUri.isRoot() )
2109  {
2110  return true; // root has no storage
2111  }
2112  else if ( rUri.isDocument() )
2113  {
2114  uno::Reference< embed::XStorage > xStorage
2115  = pProvider->queryStorage( rUri.getUri(), READ );
2116  return xStorage.is();
2117  }
2118  else
2119  {
2120  // folder or stream
2121 
2122  // Ask parent storage. In case that rUri describes a stream,
2123  // ContentProvider::queryStorage( rUri ) would return null.
2124 
2125  uno::Reference< embed::XStorage > xStorage
2126  = pProvider->queryStorage( rUri.getParentUri(), READ );
2127 
2128  if ( !xStorage.is() )
2129  return false;
2130 
2131  return xStorage->hasByName( rUri.getDecodedName() );
2132  }
2133 }
2134 
2135 
2136 //static
2137 bool Content::loadData( ContentProvider const * pProvider,
2138  const Uri & rUri,
2139  ContentProperties& rProps )
2140 {
2141  if ( rUri.isRoot() ) // root has no storage, but can always be created
2142  {
2143  rProps
2145  ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2146  }
2147  else if ( rUri.isDocument() ) // document must have storage
2148  {
2149  uno::Reference< embed::XStorage > xStorage
2150  = pProvider->queryStorage( rUri.getUri(), READ );
2151 
2152  if ( !xStorage.is() )
2153  return false;
2154 
2155  rProps
2157  DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2158  }
2159  else // stream or folder; stream has no storage; folder has storage
2160  {
2161  uno::Reference< embed::XStorage > xStorage
2162  = pProvider->queryStorage( rUri.getParentUri(), READ );
2163 
2164  if ( !xStorage.is() )
2165  return false;
2166 
2167  // Check whether exists at all, is stream or folder
2168  try
2169  {
2170  // return: true -> folder
2171  // return: false -> stream
2172  // NoSuchElementException -> neither folder nor stream
2173  bool bIsFolder
2174  = xStorage->isStorageElement( rUri.getDecodedName() );
2175 
2176  rProps
2178  bIsFolder ? FOLDER : STREAM,
2179  pProvider->queryStorageTitle( rUri.getUri() ) );
2180  }
2181  catch ( container::NoSuchElementException const & )
2182  {
2183  // there is no element with such name
2184  //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2185  return false;
2186  }
2187  catch ( lang::IllegalArgumentException const & )
2188  {
2189  // an illegal argument is provided
2190  OSL_FAIL( "Caught IllegalArgumentException!" );
2191  return false;
2192  }
2193  catch ( embed::InvalidStorageException const & )
2194  {
2195  // this storage is in invalid state for any reason
2196  OSL_FAIL( "Caught InvalidStorageException!" );
2197  return false;
2198  }
2199  }
2200  return true;
2201 }
2202 
2203 
2204 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2205  const uno::Reference<
2206  ucb::XCommandEnvironment >& xEnv )
2207 {
2208  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2209 
2210  ContentType eType = m_aProps.getType();
2211  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2212  {
2213  OSL_FAIL( "storeData not supported by root and documents!" );
2214  return false;
2215  }
2216 
2217  Uri aUri( m_xIdentifier->getContentIdentifier() );
2218 
2219  if ( eType == FOLDER )
2220  {
2221  uno::Reference< embed::XStorage > xStorage
2222  = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2223 
2224  if ( !xStorage.is() )
2225  return false;
2226 
2227  uno::Reference< beans::XPropertySet > xPropSet(
2228  xStorage, uno::UNO_QUERY );
2229  OSL_ENSURE( xPropSet.is(),
2230  "Content::storeData - Got no XPropertySet interface!" );
2231  if ( !xPropSet.is() )
2232  return false;
2233 
2234  try
2235  {
2236  // According to MBA, if no mediatype is set, folder and all
2237  // its contents will be lost on save of the document!!!
2238  xPropSet->setPropertyValue(
2239  "MediaType",
2240  uno::makeAny(
2241  OUString( // @@@ better mediatype
2242  "application/binary" ) ) );
2243  }
2244  catch ( beans::UnknownPropertyException const & )
2245  {
2246  OSL_FAIL( "Property MediaType not supported!" );
2247  return false;
2248  }
2249  catch ( beans::PropertyVetoException const & )
2250  {
2251  OSL_FAIL( "Caught PropertyVetoException!" );
2252  return false;
2253  }
2254  catch ( lang::IllegalArgumentException const & )
2255  {
2256  OSL_FAIL( "Caught IllegalArgumentException!" );
2257  return false;
2258  }
2259  catch ( lang::WrappedTargetException const & )
2260  {
2261  OSL_FAIL( "Caught WrappedTargetException!" );
2262  return false;
2263  }
2264 
2265  if ( !commitStorage( xStorage ) )
2266  return false;
2267  }
2268  else if ( eType == STREAM )
2269  {
2270  // stream
2271 
2272  // Important: Parent storage and output stream must be kept alive until
2273  // changes have been committed!
2274  uno::Reference< embed::XStorage > xStorage
2276  aUri.getParentUri(), READ_WRITE_CREATE );
2277  uno::Reference< io::XOutputStream > xOut;
2278 
2279  if ( !xStorage.is() )
2280  return false;
2281 
2282  if ( xData.is() )
2283  {
2284  // May throw CommandFailedException, DocumentPasswordRequest!
2285  xOut = getTruncatedOutputStream( xEnv );
2286 
2287  OSL_ENSURE( xOut.is(), "No target data stream!" );
2288 
2289  try
2290  {
2291  uno::Sequence< sal_Int8 > aBuffer;
2292  while (true)
2293  {
2294  sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2295  if (!nRead)
2296  break;
2297  aBuffer.realloc( nRead );
2298  xOut->writeBytes( aBuffer );
2299  }
2300 
2301  closeOutputStream( xOut );
2302  }
2303  catch ( io::NotConnectedException const & )
2304  {
2305  // readSomeBytes, writeBytes
2306  OSL_FAIL( "Caught NotConnectedException!" );
2307  closeOutputStream( xOut );
2308  return false;
2309  }
2310  catch ( io::BufferSizeExceededException const & )
2311  {
2312  // readSomeBytes, writeBytes
2313  OSL_FAIL( "Caught BufferSizeExceededException!" );
2314  closeOutputStream( xOut );
2315  return false;
2316  }
2317  catch ( io::IOException const & )
2318  {
2319  // readSomeBytes, writeBytes
2320  OSL_FAIL( "Caught IOException!" );
2321  closeOutputStream( xOut );
2322  return false;
2323  }
2324  catch ( ... )
2325  {
2326  closeOutputStream( xOut );
2327  throw;
2328  }
2329  }
2330 
2331  // Commit changes.
2332  if ( !commitStorage( xStorage ) )
2333  return false;
2334  }
2335  else
2336  {
2337  OSL_FAIL( "Unknown content type!" );
2338  return false;
2339  }
2340  return true;
2341 }
2342 
2343 
2344 void Content::renameData(
2345  const uno::Reference< ucb::XContentIdentifier >& xOldId,
2346  const uno::Reference< ucb::XContentIdentifier >& xNewId )
2347 {
2348  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2349 
2350  ContentType eType = m_aProps.getType();
2351  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2352  {
2353  OSL_FAIL( "renameData not supported by root and documents!" );
2354  return;
2355  }
2356 
2357  Uri aOldUri( xOldId->getContentIdentifier() );
2358  uno::Reference< embed::XStorage > xStorage
2360  aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2361 
2362  if ( !xStorage.is() )
2363  return;
2364 
2365  try
2366  {
2367  Uri aNewUri( xNewId->getContentIdentifier() );
2368  xStorage->renameElement(
2369  aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2370  }
2371  catch ( embed::InvalidStorageException const & )
2372  {
2373  // this storage is in invalid state for any reason
2374  OSL_FAIL( "Caught InvalidStorageException!" );
2375  return;
2376  }
2377  catch ( lang::IllegalArgumentException const & )
2378  {
2379  // an illegal argument is provided
2380  OSL_FAIL( "Caught IllegalArgumentException!" );
2381  return;
2382  }
2383  catch ( container::NoSuchElementException const & )
2384  {
2385  // there is no element with old name in this storage
2386  OSL_FAIL( "Caught NoSuchElementException!" );
2387  return;
2388  }
2389  catch ( container::ElementExistException const & )
2390  {
2391  // an element with new name already exists in this storage
2392  OSL_FAIL( "Caught ElementExistException!" );
2393  return;
2394  }
2395  catch ( io::IOException const & )
2396  {
2397  // in case of io errors during renaming
2398  OSL_FAIL( "Caught IOException!" );
2399  return;
2400  }
2401  catch ( embed::StorageWrappedTargetException const & )
2402  {
2403  // wraps other exceptions
2404  OSL_FAIL( "Caught StorageWrappedTargetException!" );
2405  return;
2406  }
2407 
2408  commitStorage( xStorage );
2409 }
2410 
2411 
2413 {
2414  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2415 
2416  ContentType eType = m_aProps.getType();
2417  if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2418  {
2419  OSL_FAIL( "removeData not supported by root and documents!" );
2420  return false;
2421  }
2422 
2423  Uri aUri( m_xIdentifier->getContentIdentifier() );
2424  uno::Reference< embed::XStorage > xStorage
2426  aUri.getParentUri(), READ_WRITE_NOCREATE );
2427 
2428  if ( !xStorage.is() )
2429  return false;
2430 
2431  try
2432  {
2433  xStorage->removeElement( aUri.getDecodedName() );
2434  }
2435  catch ( embed::InvalidStorageException const & )
2436  {
2437  // this storage is in invalid state for any reason
2438  OSL_FAIL( "Caught InvalidStorageException!" );
2439  return false;
2440  }
2441  catch ( lang::IllegalArgumentException const & )
2442  {
2443  // an illegal argument is provided
2444  OSL_FAIL( "Caught IllegalArgumentException!" );
2445  return false;
2446  }
2447  catch ( container::NoSuchElementException const & )
2448  {
2449  // there is no element with this name in this storage
2450  OSL_FAIL( "Caught NoSuchElementException!" );
2451  return false;
2452  }
2453  catch ( io::IOException const & )
2454  {
2455  // in case of io errors during renaming
2456  OSL_FAIL( "Caught IOException!" );
2457  return false;
2458  }
2459  catch ( embed::StorageWrappedTargetException const & )
2460  {
2461  // wraps other exceptions
2462  OSL_FAIL( "Caught StorageWrappedTargetException!" );
2463  return false;
2464  }
2465 
2466  return commitStorage( xStorage );
2467 }
2468 
2469 
2470 bool Content::copyData( const Uri & rSourceUri, const OUString & rNewName )
2471 {
2472  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2473 
2474  ContentType eType = m_aProps.getType();
2475  if ( ( eType == ROOT ) || ( eType == STREAM ) )
2476  {
2477  OSL_FAIL( "copyData not supported by root and streams!" );
2478  return false;
2479  }
2480 
2481  Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2482  uno::Reference< embed::XStorage > xDestStorage
2483  = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2484 
2485  if ( !xDestStorage.is() )
2486  return false;
2487 
2488  uno::Reference< embed::XStorage > xSourceStorage
2489  = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2490 
2491  if ( !xSourceStorage.is() )
2492  return false;
2493 
2494  try
2495  {
2496  xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2497  xDestStorage,
2498  rNewName );
2499  }
2500  catch ( embed::InvalidStorageException const & )
2501  {
2502  // this storage is in invalid state for any reason
2503  OSL_FAIL( "Caught InvalidStorageException!" );
2504  return false;
2505  }
2506  catch ( lang::IllegalArgumentException const & )
2507  {
2508  // an illegal argument is provided
2509  OSL_FAIL( "Caught IllegalArgumentException!" );
2510  return false;
2511  }
2512  catch ( container::NoSuchElementException const & )
2513  {
2514  // there is no element with this name in this storage
2515  OSL_FAIL( "Caught NoSuchElementException!" );
2516  return false;
2517  }
2518  catch ( container::ElementExistException const & )
2519  {
2520  // there is no element with this name in this storage
2521  OSL_FAIL( "Caught ElementExistException!" );
2522  return false;
2523  }
2524  catch ( io::IOException const & )
2525  {
2526  // in case of io errors during renaming
2527  OSL_FAIL( "Caught IOException!" );
2528  return false;
2529  }
2530  catch ( embed::StorageWrappedTargetException const & )
2531  {
2532  // wraps other exceptions
2533  OSL_FAIL( "Caught StorageWrappedTargetException!" );
2534  return false;
2535  }
2536 
2537  return commitStorage( xDestStorage );
2538 }
2539 
2540 
2541 // static
2542 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2543 {
2544  // Commit changes
2545  uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2546 
2547  OSL_ENSURE( xTO.is(),
2548  "Required interface css.embed.XTransactedObject missing!" );
2549  try
2550  {
2551  xTO->commit();
2552  }
2553  catch ( io::IOException const & )
2554  {
2555  OSL_FAIL( "Caught IOException!" );
2556  return false;
2557  }
2558  catch ( lang::WrappedTargetException const & )
2559  {
2560  OSL_FAIL( "Caught WrappedTargetException!" );
2561  return false;
2562  }
2563 
2564  return true;
2565 }
2566 
2567 
2568 // static
2570  const uno::Reference< io::XOutputStream > & xOut )
2571 {
2572  if ( xOut.is() )
2573  {
2574  try
2575  {
2576  xOut->closeOutput();
2577  return true;
2578  }
2579  catch ( io::NotConnectedException const & )
2580  {
2581  OSL_FAIL( "Caught NotConnectedException!" );
2582  }
2583  catch ( io::BufferSizeExceededException const & )
2584  {
2585  OSL_FAIL( "Caught BufferSizeExceededException!" );
2586  }
2587  catch ( io::IOException const & )
2588  {
2589  OSL_FAIL( "Caught IOException!" );
2590  }
2591  }
2592  return false;
2593 }
2594 
2597 static OUString obtainPassword(
2598  const OUString & rName,
2599  task::PasswordRequestMode eMode,
2600  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2601 {
2603  = new DocumentPasswordRequest( eMode, rName );
2604 
2605  if ( xEnv.is() )
2606  {
2607  uno::Reference< task::XInteractionHandler > xIH
2608  = xEnv->getInteractionHandler();
2609  if ( xIH.is() )
2610  {
2611  xIH->handle( xRequest.get() );
2612 
2614  = xRequest->getSelection();
2615 
2616  if ( xSelection.is() )
2617  {
2618  // Handler handled the request.
2619  uno::Reference< task::XInteractionAbort > xAbort(
2620  xSelection.get(), uno::UNO_QUERY );
2621  if ( xAbort.is() )
2622  {
2623  throw ucb::CommandFailedException(
2624  "Abort requested by Interaction Handler.",
2625  uno::Reference< uno::XInterface >(),
2626  xRequest->getRequest() );
2627  }
2628 
2629  uno::Reference< task::XInteractionPassword > xPassword(
2630  xSelection.get(), uno::UNO_QUERY );
2631  if ( xPassword.is() )
2632  {
2633  return xPassword->getPassword();
2634  }
2635 
2636  // Unknown selection. Should never happen.
2637  throw ucb::CommandFailedException(
2638  "Interaction Handler selected unknown continuation!",
2639  uno::Reference< uno::XInterface >(),
2640  xRequest->getRequest() );
2641  }
2642  }
2643  }
2644 
2645  // No IH or IH did not handle exception.
2646  task::DocumentPasswordRequest aRequest;
2647  xRequest->getRequest() >>= aRequest;
2648  throw aRequest;
2649 }
2650 
2651 
2652 uno::Reference< io::XInputStream > Content::getInputStream(
2653  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2654 {
2655  OUString aUri;
2656  OUString aPassword;
2657  bool bPasswordRequested = false;
2658 
2659  {
2660  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2661 
2662  OSL_ENSURE( m_aProps.getType() == STREAM,
2663  "Content::getInputStream - content is no stream!" );
2664 
2665  aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2666  }
2667 
2668  for ( ;; )
2669  {
2670  try
2671  {
2672  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2673  return m_pProvider->queryInputStream( aUri, aPassword );
2674  }
2675  catch ( packages::WrongPasswordException const & )
2676  {
2677  // Obtain (new) password.
2678  aPassword
2679  = obtainPassword( aUri, /* @@@ find better title */
2680  bPasswordRequested
2681  ? task::PasswordRequestMode_PASSWORD_REENTER
2682  : task::PasswordRequestMode_PASSWORD_ENTER,
2683  xEnv );
2684  bPasswordRequested = true;
2685  }
2686  }
2687 }
2688 
2692 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2693  const OUString & rUri,
2694  ContentProvider const * pProvider,
2695  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2696 {
2697  OUString aPassword;
2698  bool bPasswordRequested = false;
2699  for ( ;; )
2700  {
2701  try
2702  {
2703  return pProvider->queryOutputStream(
2704  rUri, aPassword, true /* truncate */ );
2705  }
2706  catch ( packages::WrongPasswordException const & )
2707  {
2708  // Obtain (new) password.
2709  aPassword
2710  = obtainPassword( rUri, /* @@@ find better title */
2711  bPasswordRequested
2712  ? task::PasswordRequestMode_PASSWORD_REENTER
2713  : task::PasswordRequestMode_PASSWORD_ENTER,
2714  xEnv );
2715  bPasswordRequested = true;
2716  }
2717  }
2718 }
2719 
2720 
2721 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
2722  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2723 {
2724  OSL_ENSURE( m_aProps.getType() == STREAM,
2725  "Content::getTruncatedOutputStream - content is no stream!" );
2726 
2728  Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
2729  m_pProvider,
2730  xEnv );
2731 }
2732 
2733 
2734 uno::Reference< io::XStream > Content::getStream(
2735  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2736 {
2737  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2738 
2739  OSL_ENSURE( m_aProps.getType() == STREAM,
2740  "Content::getStream - content is no stream!" );
2741 
2742  OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
2743  OUString aPassword;
2744  bool bPasswordRequested = false;
2745  for ( ;; )
2746  {
2747  try
2748  {
2749  return m_pProvider->queryStream(
2750  aUri, aPassword, false /* no truncate */ );
2751  }
2752  catch ( packages::WrongPasswordException const & )
2753  {
2754  // Obtain (new) password.
2755  aPassword
2756  = obtainPassword( aUri, /* @@@ find better title */
2757  bPasswordRequested
2758  ? task::PasswordRequestMode_PASSWORD_REENTER
2759  : task::PasswordRequestMode_PASSWORD_ENTER,
2760  xEnv );
2761  bPasswordRequested = true;
2762  }
2763  }
2764 }
2765 
2766 
2767 // ContentProperties Implementation.
2768 
2769 
2770 uno::Sequence< ucb::ContentInfo >
2772 {
2773  if ( isContentCreator() )
2774  {
2775  uno::Sequence< beans::Property > aProps( 1 );
2776  aProps.getArray()[ 0 ] = beans::Property(
2777  "Title",
2778  -1,
2780  beans::PropertyAttribute::BOUND );
2781 
2782  if ( getType() == DOCUMENT )
2783  {
2784  // streams cannot be created as direct children of document root
2785  uno::Sequence< ucb::ContentInfo > aSeq( 1 );
2786 
2787  // Folder.
2788  aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2789  aSeq.getArray()[ 0 ].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
2790  aSeq.getArray()[ 0 ].Properties = aProps;
2791 
2792  return aSeq;
2793  }
2794  else
2795  {
2796  uno::Sequence< ucb::ContentInfo > aSeq( 2 );
2797 
2798  // Folder.
2799  aSeq.getArray()[ 0 ].Type = TDOC_FOLDER_CONTENT_TYPE;
2800  aSeq.getArray()[ 0 ].Attributes
2801  = ucb::ContentInfoAttribute::KIND_FOLDER;
2802  aSeq.getArray()[ 0 ].Properties = aProps;
2803 
2804  // Stream.
2805  aSeq.getArray()[ 1 ].Type = TDOC_STREAM_CONTENT_TYPE;
2806  aSeq.getArray()[ 1 ].Attributes
2807  = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
2808  | ucb::ContentInfoAttribute::KIND_DOCUMENT;
2809  aSeq.getArray()[ 1 ].Properties = aProps;
2810 
2811  return aSeq;
2812  }
2813  }
2814  else
2815  {
2816  OSL_FAIL( "getCreatableContentsInfo called on non-contentcreator "
2817  "object!" );
2818 
2819  return uno::Sequence< ucb::ContentInfo >( 0 );
2820  }
2821 }
2822 
2823 
2825 {
2826  return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
2827 }
2828 
2829 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XTYPEPROVIDER_COMMON_IMPL(Content)
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
bool hasValue()
std::vector< ContentImplHelperRef > ContentRefList
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo() const
const char aData[]
bool getType(BSTR name, Type &type)
css::uno::Reference< css::frame::XModel > queryDocumentModel(const OUString &rUri) const
static Content * create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
bool copyData(const Uri &rSourceUri, const OUString &rNewName)
virtual void SAL_CALL acquire() override
css::uno::Reference< css::embed::XStorage > queryStorageClone(const OUString &rUri) const
#define TDOC_URL_SCHEME
Definition: tdoc_uri.hxx:28
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
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:99
bool isRoot() const
Definition: tdoc_uri.hxx:93
void notifyChildRemoved(const OUString &rRelativeChildUri)
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:30
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(bool bCreate)
OUString queryStorageTitle(const OUString &rUri) const
Reference< XInputStream > xStream
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(const OUString &rKey, bool bCreate)
#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)
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
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
const OUString & getDecodedName() const
Definition: tdoc_uri.hxx:74
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
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
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:29
static bool loadData(ContentProvider const *pProvider, const Uri &rUri, ContentProperties &rProps)
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
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
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual void SAL_CALL release() override
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
DocumentType const eType
void insert(const css::uno::Reference< css::io::XInputStream > &xData, sal_Int32 nNameClashResolve, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void notifyChildInserted(const OUString &rRelativeChildUri)
rtl::Reference< ContentProviderImplHelper > m_xProvider
css::uno::Reference< css::embed::XStorage > queryStorage(const OUString &rUri, StorageAccessMode eMode) const
static bool commitStorage(const css::uno::Reference< css::embed::XStorage > &xStorage)
#define CPPU_TYPE_REF(T)
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
void destroy(bool bDeletePhysical, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::ucb::XContent > queryChildContent(const OUString &rRelativeChildUri)
css::uno::Reference< css::ucb::XContentIdentifier > makeNewIdentifier(const OUString &rTitle)
#define TDOC_DOCUMENT_CONTENT_TYPE
const OUString & getParentUri() const
Definition: tdoc_uri.hxx:65
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
static ContentType lcl_getContentType(const OUString &rType)
sal_Int32 nPos
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)
const OUString & getUri() const
Definition: tdoc_uri.hxx:60
css::uno::Reference< css::io::XInputStream > getInputStream(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)