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