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 #include <osl/mutex.hxx>
25 #include <osl/diagnose.h>
26 
27 #include <uno/mapping.hxx>
28 
29 #include <cppuhelper/factory.hxx>
30 #include <cppuhelper/implbase1.hxx>
31 
32 #include <tools/ref.hxx>
33 #include <tools/urlobj.hxx>
34 #include <ucbhelper/content.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <tools/stream.hxx>
37 
38 #include <com/sun/star/beans/Property.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/container/XChild.hpp>
41 #include <com/sun/star/io/XActiveDataSink.hpp>
42 #include <com/sun/star/io/XActiveDataSource.hpp>
43 #include <com/sun/star/io/XActiveDataStreamer.hpp>
44 #include <com/sun/star/sdbc/XResultSet.hpp>
45 #include <com/sun/star/ucb/CommandFailedException.hpp>
46 #include <com/sun/star/ucb/ContentInfo.hpp>
47 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
48 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
49 #include <com/sun/star/ucb/InteractiveIOException.hpp>
50 #include <com/sun/star/ucb/NameClash.hpp>
51 #include <com/sun/star/ucb/NameClashException.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
55 #include <com/sun/star/ucb/XContent.hpp>
56 #include <com/sun/star/ucb/XContentAccess.hpp>
57 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
58 #include <com/sun/star/util/XMacroExpander.hpp>
59 
60 #define IMPLEMENTATION_NAME "com.sun.star.comp.ucb.SimpleFileAccess"
61 #define SERVICE_NAME "com.sun.star.ucb.SimpleFileAccess"
62 
63 using namespace ::com::sun::star::uno;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::io;
66 using namespace ::com::sun::star::ucb;
67 using namespace ::com::sun::star::sdbc;
68 using namespace ::com::sun::star::task;
69 using namespace ::com::sun::star::util;
70 using namespace ::com::sun::star::beans;
71 using namespace ::com::sun::star::registry;
72 using namespace ::com::sun::star::container;
73 
74 namespace io_FileAccess
75 {
76 
77 
78 //===========================================================================
79 // Implementation XSimpleFileAccess
80 
81 typedef cppu::WeakImplHelper1< XSimpleFileAccess3 > FileAccessHelper;
82 class OCommandEnvironment;
83 
84 class OFileAccess : public FileAccessHelper
85 {
86     Reference< XMultiServiceFactory > mxSMgr;
87     Reference< XCommandEnvironment > mxEnvironment;
88     OCommandEnvironment* mpEnvironment;
89 
90     void transferImpl( const rtl::OUString& rSource, const rtl::OUString& rDest, sal_Bool bMoveData )
91         throw(CommandAbortedException, Exception, RuntimeException);
92     bool createNewFile( const rtl::OUString & rParentURL,
93                         const rtl::OUString & rTitle,
94                         const Reference< XInputStream >& data )
95         throw ( Exception );
96 
97 public:
98     OFileAccess( const Reference< XMultiServiceFactory > & xSMgr )
99         : mxSMgr( xSMgr), mpEnvironment( NULL ) {}
100 
101     // Methods
102     virtual void SAL_CALL copy( const ::rtl::OUString& SourceURL, const ::rtl::OUString& DestURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
103     virtual void SAL_CALL move( const ::rtl::OUString& SourceURL, const ::rtl::OUString& DestURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
104     virtual void SAL_CALL kill( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
105     virtual sal_Bool SAL_CALL isFolder( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
106     virtual sal_Bool SAL_CALL isReadOnly( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
107     virtual void SAL_CALL setReadOnly( const ::rtl::OUString& FileURL, sal_Bool bReadOnly ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
108     virtual void SAL_CALL createFolder( const ::rtl::OUString& NewFolderURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
109     virtual sal_Int32 SAL_CALL getSize( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
110     virtual ::rtl::OUString SAL_CALL getContentType( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
111     virtual ::com::sun::star::util::DateTime SAL_CALL getDateTimeModified( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
112     virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getFolderContents( const ::rtl::OUString& FolderURL, sal_Bool bIncludeFolders ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
113     virtual sal_Bool SAL_CALL exists( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
114     virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL openFileRead( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
115     virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL openFileWrite( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
116     virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XStream > SAL_CALL openFileReadWrite( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
117     virtual void SAL_CALL setInteractionHandler( const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) throw(::com::sun::star::uno::RuntimeException);
118     virtual void SAL_CALL writeFile( const ::rtl::OUString& FileURL, const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& data ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
119     virtual sal_Bool SAL_CALL isHidden( const ::rtl::OUString& FileURL ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
120     virtual void SAL_CALL setHidden( const ::rtl::OUString& FileURL, sal_Bool bHidden ) throw(::com::sun::star::ucb::CommandAbortedException, ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
121 };
122 
123 
124 //===========================================================================
125 // Implementation XActiveDataSink
126 
127 typedef cppu::WeakImplHelper1< XActiveDataSink > ActiveDataSinkHelper;
128 
129 class OActiveDataSink : public ActiveDataSinkHelper
130 {
131     Reference< XInputStream > mxStream;
132 
133 public:
134 
135     // Methods
136     virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream )
137         throw(RuntimeException);
138     virtual Reference< XInputStream > SAL_CALL getInputStream(  )
139         throw(RuntimeException);
140 };
141 
142 void OActiveDataSink::setInputStream( const Reference< XInputStream >& aStream )
143     throw(RuntimeException)
144 {
145     mxStream = aStream;
146 }
147 
148 Reference< XInputStream > OActiveDataSink::getInputStream()
149     throw(RuntimeException)
150 {
151     return mxStream;
152 }
153 
154 
155 //===========================================================================
156 // Implementation XActiveDataSource
157 
158 typedef cppu::WeakImplHelper1< XActiveDataSource > ActiveDataSourceHelper;
159 
160 class OActiveDataSource : public ActiveDataSourceHelper
161 {
162     Reference< XOutputStream > mxStream;
163 
164 public:
165 
166     // Methods
167     virtual void SAL_CALL setOutputStream( const Reference< XOutputStream >& aStream )
168         throw(RuntimeException);
169     virtual Reference< XOutputStream > SAL_CALL getOutputStream()
170         throw(RuntimeException);
171 };
172 
173 void OActiveDataSource::setOutputStream( const Reference< XOutputStream >& aStream )
174     throw(RuntimeException)
175 {
176     mxStream = aStream;
177 }
178 
179 Reference< XOutputStream > OActiveDataSource::getOutputStream()
180     throw(RuntimeException)
181 {
182     return mxStream;
183 }
184 
185 
186 //===========================================================================
187 // Implementation XActiveDataStreamer
188 
189 typedef cppu::WeakImplHelper1< XActiveDataStreamer > ActiveDataStreamerHelper;
190 
191 class OActiveDataStreamer : public ActiveDataStreamerHelper
192 {
193     Reference< XStream > mxStream;
194 
195 public:
196 
197     // Methods
198     virtual void SAL_CALL setStream( const Reference< XStream >& aStream )
199         throw(RuntimeException);
200     virtual Reference< XStream > SAL_CALL getStream()
201         throw(RuntimeException);
202 };
203 
204 void OActiveDataStreamer::setStream( const Reference< XStream >& aStream )
205     throw(RuntimeException)
206 {
207     mxStream = aStream;
208 }
209 
210 Reference< XStream > OActiveDataStreamer::getStream()
211     throw(RuntimeException)
212 {
213     return mxStream;
214 }
215 
216 
217 
218 //===========================================================================
219 // Implementation XCommandEnvironment
220 
221 typedef cppu::WeakImplHelper1< XCommandEnvironment > CommandEnvironmentHelper;
222 
223 class OCommandEnvironment : public CommandEnvironmentHelper
224 {
225     Reference< XInteractionHandler > mxInteraction;
226 
227 public:
228     void setHandler( Reference< XInteractionHandler > xInteraction_ )
229     {
230         mxInteraction = xInteraction_;
231     }
232 
233     // Methods
234     virtual Reference< XInteractionHandler > SAL_CALL getInteractionHandler()
235         throw(RuntimeException);
236     virtual Reference< XProgressHandler > SAL_CALL getProgressHandler()
237         throw(RuntimeException);
238 };
239 
240 Reference< XInteractionHandler > OCommandEnvironment::getInteractionHandler()
241     throw(RuntimeException)
242 {
243     return mxInteraction;
244 }
245 
246 Reference< XProgressHandler > OCommandEnvironment::getProgressHandler()
247     throw(RuntimeException)
248 {
249     Reference< XProgressHandler > xRet;
250     return xRet;
251 }
252 
253 //===========================================================================
254 
255 void OFileAccess::transferImpl( const rtl::OUString& rSource,
256                                 const rtl::OUString& rDest,
257                                 sal_Bool bMoveData )
258     throw(CommandAbortedException, Exception, RuntimeException)
259 {
260     // SfxContentHelper::Transfer_Impl
261     INetURLObject aSourceObj( rSource, INET_PROT_FILE );
262     INetURLObject aDestObj( rDest, INET_PROT_FILE );
263     String aName = aDestObj.getName(
264         INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
265     String aDestURL;
266     String aSourceURL = aSourceObj.GetMainURL( INetURLObject::NO_DECODE );
267     if ( aDestObj.removeSegment() )
268     {
269         // hierarchical URL.
270 
271         aDestObj.setFinalSlash();
272         aDestURL = aDestObj.GetMainURL( INetURLObject::NO_DECODE );
273     }
274     else
275     {
276         // non-hierachical URL
277 
278         // #i29648#
279         //
280 #if 0
281         // Note: A hierachical UCB content implements interface XChild, which
282         // has a method getParent(). Unfortunately this does not always help
283         // here, because it is not guaranteed that a content object for a
284         // non-existing resource can be created. Thus, it will happen that an
285         // exception is thrown when trying to create a UCB content for the
286         // destination URL.
287 
288         try
289         {
290             ucbhelper::Content aFullDest(
291                 aDestObj.GetMainURL(
292                     INetURLObject::NO_DECODE ), mxEnvironment );
293 
294             Reference< XChild > xChild( aFullDest.get(), UNO_QUERY_THROW );
295             Reference< com::sun::star::ucb::XContent >
296                 xParent( xChild->getParent(), UNO_QUERY_THROW );
297             ucbhelper::Content aParent( xParent, mxEnvironment );
298 
299             aDestURL = aParent.getURL();
300 
301             rtl::OUString aNameTmp;
302             aFullDest.getPropertyValue(
303                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ) )
304                     >>= aNameTmp;
305             aName = aNameTmp;
306         }
307         catch ( Exception const & )
308         {
309             throw RuntimeException(
310                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
311                                    "OFileAccess::transferrImpl - Unable to "
312                                    "obtain destination folder URL!" ) ),
313                 static_cast< cppu::OWeakObject * >( this ) );
314         }
315 #else
316         if ( aDestObj.GetProtocol() == INET_PROT_VND_SUN_STAR_EXPAND )
317         {
318             // Hack: Expand destination URL using Macro Expander and try again
319             //       with the hopefully hierarchical expanded URL...
320 
321             try
322             {
323                 Reference< XComponentContext > xCtx;
324                 Reference< XPropertySet > xPropSet( mxSMgr, UNO_QUERY_THROW );
325                 if ( xPropSet.is() )
326                 {
327                     xPropSet->getPropertyValue(
328                         rtl::OUString(
329                             RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) )
330                                 >>= xCtx;
331                 }
332 
333                 Reference< XMacroExpander > xExpander;
334 
335                 xCtx->getValueByName(
336                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
337                         "/singletons/com.sun.star.util.theMacroExpander" ) ) )
338                             >>= xExpander;
339 
340                 OSL_ENSURE( xExpander.is(),
341                             "Unable to obtain macro expander singleton!" );
342 
343                 aDestURL = xExpander->expandMacros(
344                     aDestObj.GetURLPath( INetURLObject::DECODE_WITH_CHARSET ) );
345             }
346             catch ( Exception const & )
347             {
348                 throw RuntimeException(
349                     rtl::OUString(
350                         RTL_CONSTASCII_USTRINGPARAM(
351                             "OFileAccess::transferrImpl - Unable to obtain "
352                             "destination folder URL!" ) ),
353                     static_cast< cppu::OWeakObject * >( this ) );
354             }
355 
356             transferImpl( rSource, aDestURL, bMoveData );
357             return;
358         }
359 
360         throw RuntimeException(
361             rtl::OUString(
362                 RTL_CONSTASCII_USTRINGPARAM(
363                     "OFileAccess::transferrImpl - Unable to obtain "
364                     "destination folder URL!" ) ),
365                 static_cast< cppu::OWeakObject * >( this ) );
366 #endif
367     }
368 
369     ucbhelper::Content aDestPath( aDestURL,   mxEnvironment );
370     ucbhelper::Content aSrc     ( aSourceURL, mxEnvironment );
371 
372     try
373     {
374         aDestPath.transferContent( aSrc,
375                                    bMoveData
376                                     ? ucbhelper::InsertOperation_MOVE
377                                     : ucbhelper::InsertOperation_COPY,
378                                    aName,
379                                    ::com::sun::star::ucb::NameClash::OVERWRITE );
380     }
381     catch ( ::com::sun::star::ucb::CommandFailedException const & )
382     {
383         // Interaction Handler already handled the error that has occured...
384     }
385 }
386 
387 void OFileAccess::copy( const rtl::OUString& SourceURL, const rtl::OUString& DestURL )
388     throw(CommandAbortedException, Exception, RuntimeException)
389 {
390     transferImpl( SourceURL, DestURL, sal_False );
391 }
392 
393 void OFileAccess::move( const rtl::OUString& SourceURL, const rtl::OUString& DestURL )
394     throw(CommandAbortedException, Exception, RuntimeException)
395 {
396     transferImpl( SourceURL, DestURL, sal_True );
397 }
398 
399 void OFileAccess::kill( const rtl::OUString& FileURL )
400     throw(CommandAbortedException, Exception, RuntimeException)
401 {
402     // SfxContentHelper::Kill
403     INetURLObject aDeleteObj( FileURL, INET_PROT_FILE );
404     ucbhelper::Content aCnt( aDeleteObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
405     try
406     {
407         aCnt.executeCommand( rtl::OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) );
408     }
409     catch ( ::com::sun::star::ucb::CommandFailedException const & )
410     {
411         // Interaction Handler already handled the error that has occured...
412     }
413 }
414 
415 sal_Bool OFileAccess::isFolder( const rtl::OUString& FileURL )
416     throw(CommandAbortedException, Exception, RuntimeException)
417 {
418     sal_Bool bRet = sal_False;
419     try
420     {
421         INetURLObject aURLObj( FileURL, INET_PROT_FILE );
422         ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
423         bRet = aCnt.isFolder();
424     }
425     catch (Exception &) {}
426     return bRet;
427 }
428 
429 sal_Bool OFileAccess::isReadOnly( const rtl::OUString& FileURL )
430     throw(CommandAbortedException, Exception, RuntimeException)
431 {
432     INetURLObject aURLObj( FileURL, INET_PROT_FILE );
433     ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
434     Any aRetAny = aCnt.getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ) );
435     sal_Bool bRet = sal_False;
436     aRetAny >>= bRet;
437     return bRet;
438 }
439 
440 void OFileAccess::setReadOnly( const rtl::OUString& FileURL, sal_Bool bReadOnly )
441     throw(CommandAbortedException, Exception, RuntimeException)
442 {
443     INetURLObject aURLObj( FileURL, INET_PROT_FILE );
444     ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
445     Any aAny;
446     aAny <<= bReadOnly;
447     aCnt.setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ), aAny );
448 }
449 
450 void OFileAccess::createFolder( const rtl::OUString& NewFolderURL )
451     throw(CommandAbortedException, Exception, RuntimeException)
452 {
453     // Does the folder already exist?
454     if( !NewFolderURL.getLength() || isFolder( NewFolderURL ) )
455         return;
456 
457     // SfxContentHelper::MakeFolder
458     INetURLObject aURL( NewFolderURL, INET_PROT_FILE );
459     String aNewFolderURLStr = aURL.GetMainURL( INetURLObject::NO_DECODE );
460     String aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
461     if ( aTitle.Len() )
462     {
463         aURL.removeSegment();
464 
465         // Does the base folder exist? Otherwise create it first
466         String aBaseFolderURLStr = aURL.GetMainURL( INetURLObject::NO_DECODE );
467         if( !isFolder( aBaseFolderURLStr ) )
468         {
469             createFolder( aBaseFolderURLStr );
470         }
471     }
472 
473     ucbhelper::Content aCnt( aURL.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
474 
475     Sequence< ContentInfo > aInfo = aCnt.queryCreatableContentsInfo();
476     sal_Int32 nCount = aInfo.getLength();
477     if ( nCount == 0 )
478         return;
479 
480     for ( sal_Int32 i = 0; i < nCount; ++i )
481     {
482         // Simply look for the first KIND_FOLDER...
483         const ContentInfo & rCurr = aInfo[i];
484         if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
485         {
486             // Make sure the only required bootstrap property is "Title",
487             const Sequence< Property > & rProps = rCurr.Properties;
488             if ( rProps.getLength() != 1 )
489                 continue;
490 
491             if ( !rProps[ 0 ].Name.equalsAsciiL(
492                     RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
493                 continue;
494 
495             Sequence<rtl::OUString> aNames(1);
496             rtl::OUString* pNames = aNames.getArray();
497             pNames[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
498             Sequence< Any > aValues(1);
499             Any* pValues = aValues.getArray();
500             pValues[0] = makeAny( rtl::OUString( aTitle ) );
501 
502             ucbhelper::Content aNew;
503             try
504             {
505                 if ( !aCnt.insertNewContent( rCurr.Type, aNames, aValues, aNew ) )
506                     continue;
507 
508                 // Success. We're done.
509                 return;
510             }
511             catch ( ::com::sun::star::ucb::CommandFailedException const & )
512             {
513                 // Interaction Handler already handled the error that has occured...
514                 continue;
515             }
516         }
517     }
518 }
519 
520 sal_Int32 OFileAccess::getSize( const rtl::OUString& FileURL )
521     throw(CommandAbortedException, Exception, RuntimeException)
522 {
523     // SfxContentHelper::GetSize
524     sal_Int32 nSize = 0;
525     sal_Int64 nTemp = 0;
526     INetURLObject aObj( FileURL, INET_PROT_FILE );
527     ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
528     aCnt.getPropertyValue( rtl::OUString::createFromAscii( "Size" ) ) >>= nTemp;
529     nSize = (sal_Int32)nTemp;
530     return nSize;
531 }
532 
533 rtl::OUString OFileAccess::getContentType( const rtl::OUString& FileURL )
534     throw(CommandAbortedException, Exception, RuntimeException)
535 {
536     INetURLObject aObj( FileURL, INET_PROT_FILE );
537     ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
538 
539     Reference< XContent > xContent = aCnt.get();
540     rtl::OUString aTypeStr = xContent->getContentType();
541     return aTypeStr;
542 }
543 
544 DateTime OFileAccess::getDateTimeModified( const rtl::OUString& FileURL )
545     throw(CommandAbortedException, Exception, RuntimeException)
546 {
547     INetURLObject aFileObj( FileURL, INET_PROT_FILE );
548     DateTime aDateTime;
549 
550     Reference< XCommandEnvironment > aCmdEnv;
551     ucbhelper::Content aYoung( aFileObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv );
552     aYoung.getPropertyValue( rtl::OUString::createFromAscii( "DateModified" ) ) >>= aDateTime;
553     return aDateTime;
554 }
555 
556 
557 DECLARE_LIST( StringList_Impl, rtl::OUString* )
558 
559 Sequence< rtl::OUString > OFileAccess::getFolderContents( const rtl::OUString& FolderURL, sal_Bool bIncludeFolders )
560     throw(CommandAbortedException, Exception, RuntimeException)
561 {
562     // SfxContentHelper::GetFolderContents
563 
564     StringList_Impl* pFiles = NULL;
565     INetURLObject aFolderObj( FolderURL, INET_PROT_FILE );
566 
567     ucbhelper::Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
568     Reference< XResultSet > xResultSet;
569     Sequence< rtl::OUString > aProps(0);
570     //Sequence< rtl::OUString > aProps(1);
571     //rtl::OUString* pProps = aProps.getArray();
572     //pProps[0] == rtl::OUString::createFromAscii( "Url" );
573 
574     ucbhelper::ResultSetInclude eInclude = bIncludeFolders ? ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS : ucbhelper::INCLUDE_DOCUMENTS_ONLY;
575 
576     try
577     {
578         xResultSet = aCnt.createCursor( aProps, eInclude );
579     }
580     catch ( ::com::sun::star::ucb::CommandFailedException const & )
581     {
582         // Interaction Handler already handled the error that has occured...
583     }
584 
585     if ( xResultSet.is() )
586     {
587         pFiles = new StringList_Impl;
588         Reference< com::sun::star::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
589 
590         while ( xResultSet->next() )
591         {
592             rtl::OUString aId = xContentAccess->queryContentIdentifierString();
593             INetURLObject aURL( aId, INET_PROT_FILE );
594             rtl::OUString* pFile = new rtl::OUString( aURL.GetMainURL( INetURLObject::NO_DECODE ) );
595             pFiles->Insert( pFile, LIST_APPEND );
596         }
597     }
598 
599     if ( pFiles )
600     {
601         sal_uIntPtr nCount = pFiles->Count();
602         Sequence < rtl::OUString > aRet( nCount );
603         rtl::OUString* pRet = aRet.getArray();
604         for ( sal_uInt16 i = 0; i < nCount; ++i )
605         {
606             rtl::OUString* pFile = pFiles->GetObject(i);
607             pRet[i] = *( pFile );
608             delete pFile;
609         }
610         delete pFiles;
611         return aRet;
612     }
613     else
614         return Sequence < rtl::OUString > ();
615 }
616 
617 sal_Bool OFileAccess::exists( const rtl::OUString& FileURL )
618     throw(CommandAbortedException, Exception, RuntimeException)
619 {
620     sal_Bool bRet = sal_False;
621     try
622     {
623         bRet = isFolder( FileURL );
624         if( !bRet )
625         {
626             Reference< XInputStream > xStream = openFileRead( FileURL );
627             bRet = xStream.is();
628             if( bRet )
629                 xStream->closeInput();
630         }
631     }
632     catch (Exception &) {}
633     return bRet;
634 }
635 
636 Reference< XInputStream > OFileAccess::openFileRead( const rtl::OUString& FileURL )
637     throw(CommandAbortedException, Exception, RuntimeException)
638 {
639     Reference< XInputStream > xRet;
640     INetURLObject aObj( FileURL, INET_PROT_FILE );
641     ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
642 
643     Reference< XActiveDataSink > xSink = (XActiveDataSink*)(new OActiveDataSink());
644 
645     try
646     {
647         sal_Bool bRet = aCnt.openStream( xSink );
648         if( bRet )
649             xRet = xSink->getInputStream();
650     }
651     catch ( ::com::sun::star::ucb::CommandFailedException const & )
652     {
653         // Interaction Handler already handled the error that has occured...
654     }
655 
656     return xRet;
657 }
658 
659 Reference< XOutputStream > OFileAccess::openFileWrite( const rtl::OUString& FileURL )
660     throw(CommandAbortedException, Exception, RuntimeException)
661 {
662     Reference< XOutputStream > xRet;
663     Reference< XStream > xStream = OFileAccess::openFileReadWrite( FileURL );
664     if( xStream.is() )
665         xRet = xStream->getOutputStream();
666     return xRet;
667 }
668 
669 Reference< XStream > OFileAccess::openFileReadWrite( const rtl::OUString& FileURL )
670     throw(CommandAbortedException, Exception, RuntimeException)
671 {
672     Reference< XActiveDataStreamer > xSink = (XActiveDataStreamer*)new OActiveDataStreamer();
673     Reference< XInterface > xSinkIface = Reference< XInterface >::query( xSink );
674 
675     OpenCommandArgument2 aArg;
676     aArg.Mode       = OpenMode::DOCUMENT;
677     aArg.Priority   = 0; // unused
678     aArg.Sink       = xSink;
679     aArg.Properties = Sequence< Property >( 0 ); // unused
680 
681     Any aCmdArg;
682     aCmdArg <<= aArg;
683 
684     INetURLObject aFileObj( FileURL, INET_PROT_FILE );
685     ucbhelper::Content aCnt( aFileObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
686 
687     // Be silent...
688     Reference< XInteractionHandler > xIH;
689     if ( mpEnvironment )
690     {
691         xIH = mpEnvironment->getInteractionHandler();
692         mpEnvironment->setHandler( 0 );
693     }
694 
695     try
696     {
697         aCnt.executeCommand( rtl::OUString::createFromAscii( "open" ), aCmdArg );
698     }
699     catch ( InteractiveIOException const & e )
700     {
701         if ( xIH.is() )
702             mpEnvironment->setHandler( xIH );
703 
704         if ( e.Code == IOErrorCode_NOT_EXISTING )
705         {
706             // Create file...
707             SvMemoryStream aStream(0,0);
708             ::utl::OInputStreamWrapper* pInput = new ::utl::OInputStreamWrapper( aStream );
709             Reference< XInputStream > xInput( pInput );
710             InsertCommandArgument aInsertArg;
711             aInsertArg.Data = xInput;
712             aInsertArg.ReplaceExisting = sal_False;
713 
714             aCmdArg <<= aInsertArg;
715             aCnt.executeCommand( rtl::OUString::createFromAscii( "insert" ), aCmdArg );
716 
717             // Retry...
718             return openFileReadWrite( FileURL );
719         }
720 
721         throw;
722     }
723 
724     if ( xIH.is() )
725         mpEnvironment->setHandler( xIH );
726 
727     Reference< XStream > xRet = xSink->getStream();
728     return xRet;
729 }
730 
731 void OFileAccess::setInteractionHandler( const Reference< XInteractionHandler >& Handler )
732     throw(RuntimeException)
733 {
734     if( !mpEnvironment )
735     {
736         mpEnvironment = new OCommandEnvironment();
737         mxEnvironment = (XCommandEnvironment*)mpEnvironment;
738     }
739     mpEnvironment->setHandler( Handler );
740 }
741 
742 bool OFileAccess::createNewFile( const rtl::OUString & rParentURL,
743                                  const rtl::OUString & rTitle,
744                                  const Reference< XInputStream >& data )
745     throw ( Exception )
746 {
747     ucbhelper::Content aParentCnt( rParentURL, mxEnvironment );
748 
749     Sequence< ContentInfo > aInfo = aParentCnt.queryCreatableContentsInfo();
750     sal_Int32 nCount = aInfo.getLength();
751     if ( nCount == 0 )
752         return false;
753 
754     for ( sal_Int32 i = 0; i < nCount; ++i )
755     {
756         const ContentInfo & rCurr = aInfo[i];
757         if ( ( rCurr.Attributes
758                & ContentInfoAttribute::KIND_DOCUMENT ) &&
759              ( rCurr.Attributes
760                & ContentInfoAttribute::INSERT_WITH_INPUTSTREAM ) )
761         {
762             // Make sure the only required bootstrap property is
763             // "Title",
764             const Sequence< Property > & rProps = rCurr.Properties;
765             if ( rProps.getLength() != 1 )
766                 continue;
767 
768             if ( !rProps[ 0 ].Name.equalsAsciiL(
769                      RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
770                 continue;
771 
772             Sequence<rtl::OUString> aNames(1);
773             rtl::OUString* pNames = aNames.getArray();
774             pNames[0] = rtl::OUString(
775                             RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
776             Sequence< Any > aValues(1);
777             Any* pValues = aValues.getArray();
778             pValues[0] = makeAny( rtl::OUString( rTitle ) );
779 
780             try
781             {
782                 ucbhelper::Content aNew;
783                 if ( aParentCnt.insertNewContent(
784                          rCurr.Type, aNames, aValues, data, aNew ) )
785                     return true; // success.
786                 else
787                     continue;
788             }
789             catch ( CommandFailedException const & )
790             {
791                 // Interaction Handler already handled the
792                 // error that has occured...
793                 continue;
794             }
795         }
796     }
797 
798     return false;
799 }
800 
801 void SAL_CALL OFileAccess::writeFile( const rtl::OUString& FileURL,
802                                       const Reference< XInputStream >& data )
803     throw ( Exception, RuntimeException )
804 {
805     INetURLObject aURL( FileURL, INET_PROT_FILE );
806     try
807     {
808         ucbhelper::Content aCnt(
809             aURL.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
810 
811         try
812         {
813             aCnt.writeStream( data, sal_True /* bReplaceExisting */ );
814         }
815         catch ( CommandFailedException const & )
816         {
817             // Interaction Handler already handled the error that has occured...
818         }
819     }
820     catch ( ContentCreationException const & e )
821     {
822         // Most probably file does not exist. Try to create.
823         if ( e.eError == ContentCreationError_CONTENT_CREATION_FAILED )
824         {
825             INetURLObject aParentURLObj( aURL );
826             if ( aParentURLObj.removeSegment() )
827             {
828                 String aParentURL
829                     = aParentURLObj.GetMainURL( INetURLObject::NO_DECODE );
830 
831                 // ensure all parent folders exist.
832                 createFolder( aParentURL );
833 
834                 // create the new file...
835                 String aTitle
836                     = aURL.getName( INetURLObject::LAST_SEGMENT,
837                                     true,
838                                     INetURLObject::DECODE_WITH_CHARSET );
839                 if ( createNewFile( aParentURL, aTitle, data ) )
840                 {
841                     // success
842                     return;
843                 }
844             }
845         }
846 
847         throw;
848     }
849 }
850 
851 sal_Bool OFileAccess::isHidden( const ::rtl::OUString& FileURL )
852     throw(CommandAbortedException, Exception, RuntimeException)
853 {
854     INetURLObject aURLObj( FileURL, INET_PROT_FILE );
855     ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
856     Any aRetAny = aCnt.getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ) );
857     sal_Bool bRet = sal_False;
858     aRetAny >>= bRet;
859     return bRet;
860 }
861 
862 void OFileAccess::setHidden( const ::rtl::OUString& FileURL, sal_Bool bHidden )
863     throw(CommandAbortedException, Exception, RuntimeException)
864 {
865     INetURLObject aURLObj( FileURL, INET_PROT_FILE );
866     ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::NO_DECODE ), mxEnvironment );
867     Any aAny;
868     aAny <<= bHidden;
869     aCnt.setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ), aAny );
870 }
871 
872 //==================================================================================================
873 //==================================================================================================
874 //==================================================================================================
875 
876 Reference< XInterface > SAL_CALL FileAccess_CreateInstance( const Reference< XMultiServiceFactory > & xSMgr )
877 {
878     return Reference < XInterface >( ( cppu::OWeakObject * ) new OFileAccess( xSMgr ) );
879 }
880 
881 
882 Sequence< rtl::OUString > FileAccess_getSupportedServiceNames()
883 {
884     static Sequence < rtl::OUString > *pNames = 0;
885     if( ! pNames )
886     {
887         osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
888         if( !pNames )
889         {
890             static Sequence< rtl::OUString > seqNames(1);
891             seqNames.getArray()[0] = rtl::OUString::createFromAscii( SERVICE_NAME );
892             pNames = &seqNames;
893         }
894     }
895     return *pNames;
896 }
897 
898 
899 }
900 
901 //==================================================================================================
902 // Component exports
903 
904 extern "C"
905 {
906 //==================================================================================================
907 void SAL_CALL component_getImplementationEnvironment(
908     const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
909 {
910     *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
911 }
912 //==================================================================================================
913 void * SAL_CALL component_getFactory(
914     const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
915 {
916     void * pRet = 0;
917 
918     if (pServiceManager && rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0)
919     {
920         Reference< XSingleServiceFactory > xFactory( cppu::createSingleFactory(
921             reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
922             rtl::OUString::createFromAscii( pImplName ),
923             io_FileAccess::FileAccess_CreateInstance,
924             io_FileAccess::FileAccess_getSupportedServiceNames() ) );
925 
926         if (xFactory.is())
927         {
928             xFactory->acquire();
929             pRet = xFactory.get();
930         }
931     }
932 
933     return pRet;
934 }
935 }
936 
937 
938