xref: /aoo41x/main/sot/source/sdstor/ucbstorage.cxx (revision d321cf2f)
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_sot.hxx"
26 #include <com/sun/star/io/NotConnectedException.hpp>
27 #include <com/sun/star/io/BufferSizeExceededException.hpp>
28 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <com/sun/star/lang/IllegalArgumentException.hpp>
30 #include <ucbhelper/content.hxx>
31 #include <com/sun/star/uno/Reference.h>
32 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
33 #include <unotools/tempfile.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <com/sun/star/io/XInputStream.hpp>
36 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
37 #include <com/sun/star/ucb/ResultSetException.hpp>
38 #include <com/sun/star/uno/Sequence.h>
39 #include <com/sun/star/sdbc/XResultSet.hdl>
40 #include <com/sun/star/ucb/XContentAccess.hpp>
41 #include <com/sun/star/sdbc/XRow.hpp>
42 #include <com/sun/star/ucb/CommandAbortedException.hpp>
43 #include <com/sun/star/datatransfer/DataFlavor.hpp>
44 #include <com/sun/star/ucb/ContentInfo.hpp>
45 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
46 #include <com/sun/star/beans/Property.hpp>
47 #include <com/sun/star/packages/manifest/XManifestWriter.hpp>
48 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
49 #include <com/sun/star/ucb/InteractiveIOException.hpp>
50 
51 #include <rtl/digest.h>
52 #include <tools/ref.hxx>
53 #include <tools/debug.hxx>
54 #include <unotools/streamhelper.hxx>
55 #include <unotools/streamwrap.hxx>
56 #include <unotools/ucbhelper.hxx>
57 #include <unotools/localfilehelper.hxx>
58 #include <tools/list.hxx>
59 #include <tools/urlobj.hxx>
60 #include <unotools/streamwrap.hxx>
61 #include <comphelper/processfactory.hxx>
62 #include <cppuhelper/implbase2.hxx>
63 #include <ucbhelper/commandenvironment.hxx>
64 
65 #include "sot/stg.hxx"
66 #include "sot/storinfo.hxx"
67 #include <sot/storage.hxx>
68 #include <sot/exchange.hxx>
69 #include <sot/formats.hxx>
70 #include "sot/clsids.hxx"
71 
72 #include "unostorageholder.hxx"
73 
74 using namespace ::com::sun::star::lang;
75 using namespace ::com::sun::star::beans;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::ucb;
78 using namespace ::com::sun::star::io;
79 using namespace ::com::sun::star::sdbc;
80 using namespace ::ucbhelper;
81 
82 #if OSL_DEBUG_LEVEL > 1
83 #include <stdio.h>
84 static int nOpenFiles=0;
85 static int nOpenStreams=0;
86 #endif
87 
88 typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base;
89 class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
90 {
91 protected:
92     ::osl::Mutex    m_aMutex;
93     String          m_aURL;
94     SvStream*       m_pSvStream;
95 
96 public:
97     FileStreamWrapper_Impl( const String& rName );
98     virtual ~FileStreamWrapper_Impl();
99 
100     //DECLARE_UNO3_AGG_DEFAULTS( FileStreamWrapper_Impl, FileInputStreamWrapper_Base);
101 
102     virtual void SAL_CALL seek( sal_Int64 _nLocation ) throw ( IllegalArgumentException, IOException, RuntimeException);
103     virtual sal_Int64 SAL_CALL getPosition(  ) throw ( IOException, RuntimeException);
104     virtual sal_Int64 SAL_CALL getLength(  ) throw ( IOException, RuntimeException);
105     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
106     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
107     virtual void      SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException);
108     virtual sal_Int32 SAL_CALL available() throw( NotConnectedException, RuntimeException );
109     virtual void      SAL_CALL closeInput() throw( NotConnectedException, RuntimeException );
110 
111 protected:
112     void checkConnected();
113     void checkError();
114 };
115 
116 //------------------------------------------------------------------
FileStreamWrapper_Impl(const String & rName)117 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String& rName )
118     : m_aURL( rName )
119     , m_pSvStream(0)
120 {
121     // if no URL is provided the stream is empty
122 }
123 
124 //------------------------------------------------------------------
~FileStreamWrapper_Impl()125 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
126 {
127     if ( m_pSvStream )
128     {
129         delete m_pSvStream;
130 #if OSL_DEBUG_LEVEL > 1
131         --nOpenFiles;
132 #endif
133     }
134 
135     if ( m_aURL.Len() )
136         ::utl::UCBContentHelper::Kill( m_aURL );
137 }
138 
139 //------------------------------------------------------------------------------
readBytes(Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)140 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
141                 throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
142 {
143     if ( !m_aURL.Len() )
144     {
145         aData.realloc( 0 );
146         return 0;
147     }
148 
149     checkConnected();
150 
151     if (nBytesToRead < 0)
152         throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));
153 
154     ::osl::MutexGuard aGuard( m_aMutex );
155 
156     aData.realloc(nBytesToRead);
157 
158     sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
159     checkError();
160 
161     // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
162     if (nRead < (sal_uInt32)nBytesToRead)
163         aData.realloc( nRead );
164 
165     return nRead;
166 }
167 
168 //------------------------------------------------------------------------------
readSomeBytes(Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)169 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
170 {
171     if ( !m_aURL.Len() )
172     {
173         aData.realloc( 0 );
174         return 0;
175     }
176 
177     checkError();
178 
179     if (nMaxBytesToRead < 0)
180         throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));
181 
182     if (m_pSvStream->IsEof())
183     {
184         aData.realloc(0);
185         return 0;
186     }
187     else
188         return readBytes(aData, nMaxBytesToRead);
189 }
190 
191 //------------------------------------------------------------------------------
skipBytes(sal_Int32 nBytesToSkip)192 void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
193 {
194     if ( !m_aURL.Len() )
195         return;
196 
197     ::osl::MutexGuard aGuard( m_aMutex );
198     checkError();
199 
200 #ifdef DBG_UTIL
201     sal_uInt32 nCurrentPos = m_pSvStream->Tell();
202 #endif
203 
204     m_pSvStream->SeekRel(nBytesToSkip);
205     checkError();
206 
207 #ifdef DBG_UTIL
208     nCurrentPos = m_pSvStream->Tell();
209 #endif
210 }
211 
212 //------------------------------------------------------------------------------
available()213 sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException )
214 {
215     if ( !m_aURL.Len() )
216         return 0;
217 
218     ::osl::MutexGuard aGuard( m_aMutex );
219     checkConnected();
220 
221     sal_uInt32 nPos = m_pSvStream->Tell();
222     checkError();
223 
224     m_pSvStream->Seek(STREAM_SEEK_TO_END);
225     checkError();
226 
227     sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
228     m_pSvStream->Seek(nPos);
229     checkError();
230 
231     return nAvailable;
232 }
233 
234 //------------------------------------------------------------------------------
closeInput()235 void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException )
236 {
237     if ( !m_aURL.Len() )
238         return;
239 
240     ::osl::MutexGuard aGuard( m_aMutex );
241     checkConnected();
242     DELETEZ( m_pSvStream );
243 #if OSL_DEBUG_LEVEL > 1
244     --nOpenFiles;
245 #endif
246     ::utl::UCBContentHelper::Kill( m_aURL );
247     m_aURL.Erase();
248 }
249 
250 //------------------------------------------------------------------------------
seek(sal_Int64 _nLocation)251 void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
252 {
253     if ( !m_aURL.Len() )
254         return;
255 
256     ::osl::MutexGuard aGuard( m_aMutex );
257     checkConnected();
258 
259     m_pSvStream->Seek((sal_uInt32)_nLocation);
260     checkError();
261 }
262 
263 //------------------------------------------------------------------------------
getPosition()264 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition(  ) throw (IOException, RuntimeException)
265 {
266     if ( !m_aURL.Len() )
267         return 0;
268 
269     ::osl::MutexGuard aGuard( m_aMutex );
270     checkConnected();
271 
272     sal_uInt32 nPos = m_pSvStream->Tell();
273     checkError();
274     return (sal_Int64)nPos;
275 }
276 
277 //------------------------------------------------------------------------------
getLength()278 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength(  ) throw (IOException, RuntimeException)
279 {
280     if ( !m_aURL.Len() )
281         return 0;
282 
283     ::osl::MutexGuard aGuard( m_aMutex );
284     checkConnected();
285 
286     sal_uInt32 nCurrentPos = m_pSvStream->Tell();
287     checkError();
288 
289     m_pSvStream->Seek(STREAM_SEEK_TO_END);
290     sal_uInt32 nEndPos = m_pSvStream->Tell();
291     m_pSvStream->Seek(nCurrentPos);
292 
293     checkError();
294 
295     return (sal_Int64)nEndPos;
296 }
297 
298 //------------------------------------------------------------------------------
checkConnected()299 void FileStreamWrapper_Impl::checkConnected()
300 {
301     if ( !m_aURL.Len() )
302         throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
303     if ( !m_pSvStream )
304     {
305         m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ );
306 #if OSL_DEBUG_LEVEL > 1
307         ++nOpenFiles;
308 #endif
309     }
310 }
311 
312 //------------------------------------------------------------------------------
checkError()313 void FileStreamWrapper_Impl::checkError()
314 {
315     checkConnected();
316 
317     if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
318         // TODO: really evaluate the error
319         throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
320 }
321 
322 TYPEINIT1( UCBStorageStream, BaseStorageStream );
323 TYPEINIT1( UCBStorage, BaseStorage );
324 
325 #define COMMIT_RESULT_FAILURE           0
326 #define COMMIT_RESULT_NOTHING_TO_DO     1
327 #define COMMIT_RESULT_SUCCESS           2
328 
329 #define min( x, y ) (( x < y ) ? x : y)
330 #define max( x, y ) (( x > y ) ? x : y)
331 
GetFormatId_Impl(SvGlobalName aName)332 sal_Int32 GetFormatId_Impl( SvGlobalName aName )
333 {
334 //    if ( aName == SvGlobalName( SO3_SW_CLASSID_8 ) )
335 //        return SOT_FORMATSTR_ID_STARWRITER_8;
336 //    if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_8 ) )
337 //        return SOT_FORMATSTR_ID_STARWRITERWEB_8;
338 //    if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_8 ) )
339 //        return SOT_FORMATSTR_ID_STARWRITERGLOB_8;
340 //    if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_8 ) )
341 //        return SOT_FORMATSTR_ID_STARDRAW_8;
342 //    if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_8 ) )
343 //        return SOT_FORMATSTR_ID_STARIMPRESS_8;
344 //    if ( aName == SvGlobalName( SO3_SC_CLASSID_8 ) )
345 //        return SOT_FORMATSTR_ID_STARCALC_8;
346 //    if ( aName == SvGlobalName( SO3_SCH_CLASSID_8 ) )
347 //        return SOT_FORMATSTR_ID_STARCHART_8;
348 //    if ( aName == SvGlobalName( SO3_SM_CLASSID_8 ) )
349 //        return SOT_FORMATSTR_ID_STARMATH_8;
350     if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
351         return SOT_FORMATSTR_ID_STARWRITER_60;
352     if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
353         return SOT_FORMATSTR_ID_STARWRITERWEB_60;
354     if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
355         return SOT_FORMATSTR_ID_STARWRITERGLOB_60;
356     if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
357         return SOT_FORMATSTR_ID_STARDRAW_60;
358     if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
359         return SOT_FORMATSTR_ID_STARIMPRESS_60;
360     if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
361         return SOT_FORMATSTR_ID_STARCALC_60;
362     if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
363         return SOT_FORMATSTR_ID_STARCHART_60;
364     if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
365         return SOT_FORMATSTR_ID_STARMATH_60;
366     if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
367          aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
368          aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
369          aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
370         // allowed, but not supported
371         return 0;
372     else
373     {
374         DBG_ERROR( "Unknown UCB storage format!" );
375         return 0;
376     }
377 }
378 
379 
GetClassId_Impl(sal_Int32 nFormat)380 SvGlobalName GetClassId_Impl( sal_Int32 nFormat )
381 {
382     switch ( nFormat )
383     {
384         case SOT_FORMATSTR_ID_STARWRITER_8 :
385         case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE :
386             return SvGlobalName( SO3_SW_CLASSID_60 );
387         case SOT_FORMATSTR_ID_STARWRITERWEB_8 :
388             return SvGlobalName( SO3_SWWEB_CLASSID_60 );
389         case SOT_FORMATSTR_ID_STARWRITERGLOB_8 :
390             return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
391         case SOT_FORMATSTR_ID_STARDRAW_8 :
392         case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE :
393             return SvGlobalName( SO3_SDRAW_CLASSID_60 );
394         case SOT_FORMATSTR_ID_STARIMPRESS_8 :
395         case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE :
396             return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
397         case SOT_FORMATSTR_ID_STARCALC_8 :
398         case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE :
399             return SvGlobalName( SO3_SC_CLASSID_60 );
400         case SOT_FORMATSTR_ID_STARCHART_8 :
401         case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE :
402             return SvGlobalName( SO3_SCH_CLASSID_60 );
403         case SOT_FORMATSTR_ID_STARMATH_8 :
404         case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE :
405             return SvGlobalName( SO3_SM_CLASSID_60 );
406         case SOT_FORMATSTR_ID_STARWRITER_60 :
407             return SvGlobalName( SO3_SW_CLASSID_60 );
408         case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
409             return SvGlobalName( SO3_SWWEB_CLASSID_60 );
410         case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
411             return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
412         case SOT_FORMATSTR_ID_STARDRAW_60 :
413             return SvGlobalName( SO3_SDRAW_CLASSID_60 );
414         case SOT_FORMATSTR_ID_STARIMPRESS_60 :
415             return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
416         case SOT_FORMATSTR_ID_STARCALC_60 :
417             return SvGlobalName( SO3_SC_CLASSID_60 );
418         case SOT_FORMATSTR_ID_STARCHART_60 :
419             return SvGlobalName( SO3_SCH_CLASSID_60 );
420         case SOT_FORMATSTR_ID_STARMATH_60 :
421             return SvGlobalName( SO3_SM_CLASSID_60 );
422         default :
423             //DBG_ERROR( "Unknown UCB storage format!" );
424             return SvGlobalName();
425     }
426 }
427 
428 // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
429 // class, that uses the refcounted object as impl-class.
430 
431 enum RepresentModes {
432         nonset,
433         svstream,
434         xinputstream
435 };
436 
437 class UCBStorageStream_Impl : public SvRefBase, public SvStream
438 {
439                                 ~UCBStorageStream_Impl();
440 public:
441 
442     virtual sal_uLong               GetData( void* pData, sal_uLong nSize );
443     virtual sal_uLong               PutData( const void* pData, sal_uLong nSize );
444     virtual sal_uLong               SeekPos( sal_uLong nPos );
445     virtual void                SetSize( sal_uLong nSize );
446     virtual void                FlushData();
447     virtual void                ResetError();
448 
449     UCBStorageStream*           m_pAntiImpl;    // only valid if an external reference exists
450 
451     String                      m_aOriginalName;// the original name before accessing the stream
452     String                      m_aName;        // the actual name ( changed with a Rename command at the parent )
453     String                      m_aURL;         // the full path name to create the content
454     String                      m_aContentType;
455     String                      m_aOriginalContentType;
456     ByteString                  m_aKey;
457     ::ucbhelper::Content*       m_pContent;     // the content that provides the data
458     Reference<XInputStream>     m_rSource;      // the stream covering the original data of the content
459     SvStream*                   m_pStream;      // the stream worked on; for readonly streams it is the original stream of the content
460                                                 // for read/write streams it's a copy into a temporary file
461     String                      m_aTempURL;     // URL of this temporary stream
462     RepresentModes              m_nRepresentMode; // should it be used as XInputStream or as SvStream
463     long                        m_nError;
464     StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
465     sal_Bool                        m_bSourceRead;  // Source still contains useful information
466     sal_Bool                        m_bModified;    // only modified streams will be sent to the original content
467     sal_Bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
468     sal_Bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
469                                                 // this means that the root storage does an autocommit when its external
470                                                 // reference is destroyed
471     sal_Bool                        m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
472 
473                                 UCBStorageStream_Impl( const String&, StreamMode, UCBStorageStream*, sal_Bool, const ByteString* pKey=0, sal_Bool bRepair = sal_False, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() );
474 
475     void                        Free();
476     sal_Bool                        Init();
477     sal_Bool                        Clear();
478     sal_Int16                   Commit();       // if modified and commited: transfer an XInputStream to the content
479     sal_Bool                        Revert();       // discard all changes
480     BaseStorage*                CreateStorage();// create an OLE Storage on the UCBStorageStream
481     sal_uLong                       GetSize();
482 
483     sal_uLong                       ReadSourceWriteTemporary( sal_uLong aLength ); // read aLength from source and copy to temporary,
484                                                                            // no seeking is produced
485     sal_uLong                       ReadSourceWriteTemporary();                // read source till the end and copy to temporary,
486                                                                            // no seeking is produced
487 #if 0
488     sal_uLong                       CopySourceToTemporary( sal_uLong aLength ); // same as ReadSourceWriteToTemporary( aLength )
489                                                                         // but the writing is done at the end of temporary
490                                                                         // pointer position is not changed
491 #endif
492 
493     sal_uLong                       CopySourceToTemporary();                // same as ReadSourceWriteToTemporary()
494                                                                         // but the writing is done at the end of temporary
495                                                                         // pointer position is not changed
496     Reference<XInputStream>     GetXInputStream();                      // return XInputStream, after that
497                                                                         // this class is close to be unusable
498                                                                         // since it can not read and write
499     using SvStream::SetError;
500     void                        SetError( sal_uInt32 nError );
501     void                        PrepareCachedForReopen( StreamMode nMode );
502 };
503 
504 SV_DECL_IMPL_REF( UCBStorageStream_Impl );
505 
506 struct UCBStorageElement_Impl;
507 DECLARE_LIST( UCBStorageElementList_Impl, UCBStorageElement_Impl* )
508 
509 class UCBStorage_Impl : public SvRefBase
510 {
511                                 ~UCBStorage_Impl();
512 public:
513     UCBStorage*                 m_pAntiImpl;    // only valid if external references exists
514 
515     String                      m_aOriginalName;// the original name before accessing the storage
516     String                      m_aName;        // the actual name ( changed with a Rename command at the parent )
517     String                      m_aURL;         // the full path name to create the content
518     String                      m_aContentType;
519     String                      m_aOriginalContentType;
520     ::ucbhelper::Content*       m_pContent;     // the content that provides the storage elements
521     ::utl::TempFile*            m_pTempFile;    // temporary file, only for storages on stream
522     SvStream*                   m_pSource;      // original stream, only for storages on a stream
523     //SvStream*                   m_pStream;      // the corresponding editable stream, only for storage on a stream
524     long                        m_nError;
525     StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
526     sal_Bool                        m_bModified;    // only modified elements will be sent to the original content
527     sal_Bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
528     sal_Bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
529                                                 // this means that the root storage does an autocommit when its external
530                                                 // reference is destroyed
531     sal_Bool                        m_bIsRoot;      // marks this storage as root storages that manages all oommits and reverts
532     sal_Bool                        m_bDirty;           // ???
533     sal_Bool                        m_bIsLinked;
534     sal_Bool                        m_bListCreated;
535     sal_uLong                       m_nFormat;
536     String                      m_aUserTypeName;
537     SvGlobalName                m_aClassId;
538 
539     UCBStorageElementList_Impl  m_aChildrenList;
540 
541     sal_Bool                        m_bRepairPackage;
542     Reference< XProgressHandler > m_xProgressHandler;
543 
544     UNOStorageHolderList*       m_pUNOStorageHolderList;
545                                 UCBStorage_Impl( const ::ucbhelper::Content&, const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() );
546                                 UCBStorage_Impl( const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() );
547                                 UCBStorage_Impl( SvStream&, UCBStorage*, sal_Bool );
548     void                        Init();
549     sal_Int16                   Commit();
550     sal_Bool                        Revert();
551     sal_Bool                        Insert( ::ucbhelper::Content *pContent );
552     UCBStorage_Impl*            OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect );
553     UCBStorageStream_Impl*      OpenStream( UCBStorageElement_Impl*, StreamMode, sal_Bool, const ByteString* pKey=0 );
554     void                        SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& );
555     void                        GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const String& );
556     sal_Int32                   GetObjectCount();
557     void                        ReadContent();
558     void                        CreateContent();
GetContent()559     ::ucbhelper::Content*       GetContent()
560                                 { if ( !m_pContent ) CreateContent(); return m_pContent; }
GetChildrenList()561     UCBStorageElementList_Impl& GetChildrenList()
562                                 {
563                                   long nError = m_nError;
564                                   ReadContent();
565                                   if ( m_nMode & STREAM_WRITE )
566                                   {
567                                     m_nError = nError;
568                                     if ( m_pAntiImpl )
569                                     {
570                                         m_pAntiImpl->ResetError();
571                                         m_pAntiImpl->SetError( nError );
572                                     }
573                                   }
574 
575                                   return m_aChildrenList;
576                                 }
577 
578     void                        SetError( long nError );
579 };
580 
581 SV_DECL_IMPL_REF( UCBStorage_Impl );
582 
583 // this struct contains all neccessary information on an element inside a UCBStorage
584 struct UCBStorageElement_Impl
585 {
586     String                      m_aName;        // the actual URL relative to the root "folder"
587     String                      m_aOriginalName;// the original name in the content
588     sal_uLong                       m_nSize;
589     sal_Bool                        m_bIsFolder;    // Only sal_True when it is a UCBStorage !
590     sal_Bool                        m_bIsStorage;   // Also sal_True when it is an OLEStorage !
591     sal_Bool                        m_bIsRemoved;   // element will be removed on commit
592     sal_Bool                        m_bIsInserted;  // element will be removed on revert
593     UCBStorage_ImplRef          m_xStorage;     // reference to the "real" storage
594     UCBStorageStream_ImplRef    m_xStream;      // reference to the "real" stream
595 
UCBStorageElement_ImplUCBStorageElement_Impl596                                 UCBStorageElement_Impl( const ::rtl::OUString& rName,
597                                             sal_Bool bIsFolder = sal_False, sal_uLong nSize = 0 )
598                                     : m_aName( rName )
599                                     , m_aOriginalName( rName )
600                                     , m_nSize( nSize )
601                                     , m_bIsFolder( bIsFolder )
602                                     , m_bIsStorage( bIsFolder )
603                                     , m_bIsRemoved( sal_False )
604                                     , m_bIsInserted( sal_False )
605                                 {
606                                 }
607 
608     ::ucbhelper::Content*       GetContent();
609     sal_Bool                        IsModified();
610     String                      GetContentType();
611     void                        SetContentType( const String& );
612     String                      GetOriginalContentType();
IsLoadedUCBStorageElement_Impl613     sal_Bool                        IsLoaded()
614                                 { return m_xStream.Is() || m_xStorage.Is(); }
615 };
616 
GetContent()617 ::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
618 {
619     if ( m_xStream.Is() )
620         return m_xStream->m_pContent;
621     else if ( m_xStorage.Is() )
622         return m_xStorage->GetContent();
623     else
624         return NULL;
625 }
626 
GetContentType()627 String UCBStorageElement_Impl::GetContentType()
628 {
629     if ( m_xStream.Is() )
630         return m_xStream->m_aContentType;
631     else if ( m_xStorage.Is() )
632         return m_xStorage->m_aContentType;
633     else
634     {
635         DBG_ERROR("Element not loaded!");
636         return String();
637     }
638 }
639 
SetContentType(const String & rType)640 void UCBStorageElement_Impl::SetContentType( const String& rType )
641 {
642     if ( m_xStream.Is() ) {
643         m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
644     }
645     else if ( m_xStorage.Is() ) {
646         m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
647     }
648     else {
649         DBG_ERROR("Element not loaded!");
650     }
651 }
652 
GetOriginalContentType()653 String UCBStorageElement_Impl::GetOriginalContentType()
654 {
655     if ( m_xStream.Is() )
656         return m_xStream->m_aOriginalContentType;
657     else if ( m_xStorage.Is() )
658         return m_xStorage->m_aOriginalContentType;
659     else
660         return String();
661 }
662 
IsModified()663 sal_Bool UCBStorageElement_Impl::IsModified()
664 {
665     sal_Bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
666     if ( bModified )
667     {
668         if ( m_xStream.Is() )
669             bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
670         else if ( m_xStorage.Is() )
671             bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
672     }
673 
674     return bModified;
675 }
676 
UCBStorageStream_Impl(const String & rName,StreamMode nMode,UCBStorageStream * pStream,sal_Bool bDirect,const ByteString * pKey,sal_Bool bRepair,Reference<XProgressHandler> xProgress)677 UCBStorageStream_Impl::UCBStorageStream_Impl( const String& rName, StreamMode nMode, UCBStorageStream* pStream, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress  )
678     : m_pAntiImpl( pStream )
679     , m_aURL( rName )
680     , m_pContent( NULL )
681     , m_pStream( NULL )
682     , m_nRepresentMode( nonset )
683     , m_nError( 0 )
684     , m_nMode( nMode )
685     , m_bSourceRead( !( nMode & STREAM_TRUNC ) )
686     , m_bModified( sal_False )
687     , m_bCommited( sal_False )
688     , m_bDirect( bDirect )
689     , m_bIsOLEStorage( sal_False )
690 {
691     // name is last segment in URL
692     INetURLObject aObj( rName );
693     m_aName = m_aOriginalName = aObj.GetLastName();
694     try
695     {
696         // create the content
697         Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
698 
699         ::rtl::OUString aTemp( rName );
700 
701         if ( bRepair )
702         {
703             xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
704                                                      xProgress );
705             aTemp += rtl::OUString::createFromAscii("?repairpackage");
706         }
707 
708         m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
709 
710         if ( pKey )
711         {
712             m_aKey = *pKey;
713 
714             // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
715             sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1];
716             rtlDigestError nErr = rtl_digest_SHA1( pKey->GetBuffer(), pKey->Len(), aBuffer, RTL_DIGEST_LENGTH_SHA1 );
717             if ( nErr == rtl_Digest_E_None )
718             {
719                 sal_uInt8* pBuffer = aBuffer;
720                 ::com::sun::star::uno::Sequence < sal_Int8 > aSequ( (sal_Int8*) pBuffer, RTL_DIGEST_LENGTH_SHA1 );
721                 ::com::sun::star::uno::Any aAny;
722                 aAny <<= aSequ;
723                 m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii("EncryptionKey"), aAny );
724             }
725         }
726     }
727     catch ( ContentCreationException& )
728     {
729         // content could not be created
730         SetError( SVSTREAM_CANNOT_MAKE );
731     }
732     catch ( RuntimeException& )
733     {
734         // any other error - not specified
735         SetError( ERRCODE_IO_GENERAL );
736     }
737 }
738 
~UCBStorageStream_Impl()739 UCBStorageStream_Impl::~UCBStorageStream_Impl()
740 {
741     if( m_rSource.is() )
742         m_rSource = Reference< XInputStream >();
743 
744     if( m_pStream )
745         delete m_pStream;
746 
747     if ( m_aTempURL.Len() )
748         ::utl::UCBContentHelper::Kill( m_aTempURL );
749 
750     if( m_pContent )
751         delete m_pContent;
752 }
753 
754 
GetXInputStream()755 Reference<XInputStream> UCBStorageStream_Impl::GetXInputStream()
756 {
757     Reference< XInputStream > aResult;
758 
759     if( m_pAntiImpl && m_nRepresentMode != nonset )
760     {
761         DBG_ERROR( "Misuse of the XInputstream!" );
762         SetError( ERRCODE_IO_ACCESSDENIED );
763     }
764     else
765     {
766         if( m_bModified )
767         {
768             // use wrapper around temporary stream
769             if( Init() )
770             {
771                 CopySourceToTemporary();
772 
773                 // owner transfer of stream to wrapper
774                 aResult = new ::utl::OInputStreamWrapper( m_pStream, sal_True );
775                 m_pStream->Seek(0);
776 
777                 if( aResult.is() )
778                 {
779                     // temporary stream can not be used here any more
780                     // and can not be opened untill wrapper is closed
781                     // stream is deleted by wrapper after use
782                     m_pStream = NULL;
783                     m_nRepresentMode = xinputstream;
784                 }
785             }
786         }
787         else
788         {
789             Free();
790 
791             // open a new instance of XInputStream
792             try
793             {
794                 aResult = m_pContent->openStream();
795             }
796             catch ( Exception& )
797             {
798                 // usually means that stream could not be opened
799             }
800 
801             if( aResult.is() )
802                 m_nRepresentMode = xinputstream;
803             else
804                 SetError( ERRCODE_IO_ACCESSDENIED );
805         }
806     }
807 
808     return aResult;
809 }
810 
Init()811 sal_Bool UCBStorageStream_Impl::Init()
812 {
813     if( m_nRepresentMode == xinputstream )
814     {
815         DBG_ERROR( "XInputStream misuse!" );
816         SetError( ERRCODE_IO_ACCESSDENIED );
817         return sal_False;
818     }
819 
820     if( !m_pStream )
821     {
822         // no temporary stream was created
823         // create one
824 
825         m_nRepresentMode = svstream; // can not be used as XInputStream
826 
827         if ( !m_aTempURL.Len() )
828             m_aTempURL = ::utl::TempFile().GetURL();
829 
830         m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, STREAM_STD_READWRITE, sal_True /* bFileExists */ );
831 #if OSL_DEBUG_LEVEL > 1
832         ++nOpenFiles;
833 #endif
834 
835         if( !m_pStream )
836         {
837             DBG_ERROR( "Suspicious temporary stream creation!" );
838             SetError( SVSTREAM_CANNOT_MAKE );
839             return sal_False;
840         }
841 
842         SetError( m_pStream->GetError() );
843     }
844 
845     if( m_bSourceRead && !m_rSource.is() )
846     {
847         // source file contain usefull information and is not opened
848         // open it from the point of noncopied data
849 
850         try
851         {
852             m_rSource = m_pContent->openStream();
853         }
854         catch ( Exception& )
855         {
856             // usually means that stream could not be opened
857         }
858 
859             if( m_rSource.is() )
860         {
861             m_pStream->Seek( STREAM_SEEK_TO_END );
862 
863             try
864             {
865                 m_rSource->skipBytes( m_pStream->Tell() );
866             }
867             catch( BufferSizeExceededException& )
868             {
869                 // the temporary stream already contain all the data
870                 m_bSourceRead = sal_False;
871             }
872             catch( Exception& )
873             {
874                 // something is really wrong
875                 m_bSourceRead = sal_False;
876                 DBG_ERROR( "Can not operate original stream!" );
877                 SetError( SVSTREAM_CANNOT_MAKE );
878             }
879 
880             m_pStream->Seek( 0 );
881         }
882         else
883         {
884             // if the new file is edited than no source exist
885             m_bSourceRead = sal_False;
886                 //SetError( SVSTREAM_CANNOT_MAKE );
887         }
888     }
889 
890     DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
891 
892     return sal_True;
893 }
894 
ReadSourceWriteTemporary()895 sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary()
896 {
897     // read source stream till the end and copy all the data to
898     // the current position of the temporary stream
899 
900     sal_uLong aResult = 0;
901 
902     if( m_bSourceRead )
903     {
904         Sequence<sal_Int8> aData(32000);
905 
906         try
907         {
908             sal_uLong aReaded;
909             do
910             {
911                 aReaded = m_rSource->readBytes( aData, 32000 );
912                 aResult += m_pStream->Write( aData.getArray(), aReaded );
913             } while( aReaded == 32000 );
914         }
915 #if OSL_DEBUG_LEVEL > 1
916         catch( Exception & e )
917         {
918             OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
919 #else
920         catch( Exception & )
921         {
922 #endif
923         }
924     }
925 
926     m_bSourceRead = sal_False;
927 
928     return aResult;
929 
930 }
931 
932 sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength )
933 {
934     // read aLength bite from the source stream and copy them to the current
935     // position of the temporary stream
936 
937     sal_uLong aResult = 0;
938 
939     if( m_bSourceRead )
940     {
941         Sequence<sal_Int8> aData(32000);
942 
943         try
944         {
945 
946             sal_uLong aReaded = 32000;
947 
948             for( sal_uLong pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 )
949             {
950                 sal_uLong aToCopy = min( aLength - pInd, 32000 );
951                 aReaded = m_rSource->readBytes( aData, aToCopy );
952                 aResult += m_pStream->Write( aData.getArray(), aReaded );
953             }
954 
955             if( aResult < aLength )
956                 m_bSourceRead = sal_False;
957         }
958 #if OSL_DEBUG_LEVEL > 1
959         catch( Exception & e )
960         {
961             OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
962 #else
963         catch( Exception & )
964         {
965 #endif
966         }
967     }
968 
969     return aResult;
970 }
971 
972 sal_uLong UCBStorageStream_Impl::CopySourceToTemporary()
973 {
974     // current position of the temporary stream is not changed
975     sal_uLong aResult = 0;
976 
977     if( m_bSourceRead )
978     {
979         sal_uLong aPos = m_pStream->Tell();
980         m_pStream->Seek( STREAM_SEEK_TO_END );
981         aResult = ReadSourceWriteTemporary();
982         m_pStream->Seek( aPos );
983     }
984 
985     return aResult;
986 
987 }
988 
989 #if 0
990 sal_uLong UCBStorageStream_Impl::CopySourceToTemporary( sal_uLong aLength )
991 {
992     // current position of the temporary stream is not changed
993     sal_uLong aResult = 0;
994 
995     if( m_bSourceRead )
996     {
997         sal_uLong aPos = m_pStream->Tell();
998         m_pStream->Seek( STREAM_SEEK_TO_END );
999         aResult = ReadSourceWriteTemporary( aLength );
1000         m_pStream->Seek( aPos );
1001     }
1002 
1003     return aResult;
1004 
1005 }
1006 #endif
1007 
1008 // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
1009 // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
1010 sal_uLong UCBStorageStream_Impl::GetData( void* pData, sal_uLong nSize )
1011 {
1012     sal_uLong aResult = 0;
1013 
1014     if( !Init() )
1015         return 0;
1016 
1017 
1018     // read data that is in temporary stream
1019     aResult = m_pStream->Read( pData, nSize );
1020     if( m_bSourceRead && aResult < nSize )
1021     {
1022         // read the tail of the data from original stream
1023         // copy this tail to the temporary stream
1024 
1025         sal_uLong aToRead = nSize - aResult;
1026         pData = (void*)( (char*)pData + aResult );
1027 
1028         try
1029         {
1030             Sequence<sal_Int8> aData( aToRead );
1031             sal_uLong aReaded = m_rSource->readBytes( aData, aToRead );
1032             aResult += m_pStream->Write( (void*)aData.getArray(), aReaded );
1033             memcpy( pData, aData.getArray(), aReaded );
1034         }
1035 #if OSL_DEBUG_LEVEL > 1
1036         catch( Exception & e )
1037         {
1038             OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
1039 #else
1040         catch( Exception & )
1041         {
1042 #endif
1043         }
1044 
1045         if( aResult < nSize )
1046             m_bSourceRead = sal_False;
1047     }
1048 
1049     return aResult;
1050 }
1051 
1052 sal_uLong UCBStorageStream_Impl::PutData( const void* pData, sal_uLong nSize )
1053 {
1054     if ( !(m_nMode & STREAM_WRITE) )
1055     {
1056         SetError( ERRCODE_IO_ACCESSDENIED );
1057         return 0; // ?mav?
1058     }
1059 
1060     if( !nSize || !Init() )
1061         return 0;
1062 
1063     sal_uLong aResult = m_pStream->Write( pData, nSize );
1064 
1065     m_bModified = aResult > 0;
1066 
1067     return aResult;
1068 
1069 }
1070 
1071 sal_uLong UCBStorageStream_Impl::SeekPos( sal_uLong nPos )
1072 {
1073     if( !Init() )
1074         return 0;
1075 
1076     sal_uLong aResult;
1077 
1078     if( nPos == STREAM_SEEK_TO_END )
1079     {
1080         m_pStream->Seek( STREAM_SEEK_TO_END );
1081         ReadSourceWriteTemporary();
1082         aResult = m_pStream->Tell();
1083     }
1084     else
1085     {
1086         // the problem is that even if nPos is larger the the length
1087         // of the stream the stream pointer will be moved to this position
1088         // so we have to check if temporary stream does not contain required position
1089 
1090         if( m_pStream->Tell() > nPos
1091             || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
1092         {
1093             // no copiing is required
1094             aResult = m_pStream->Seek( nPos );
1095         }
1096         else
1097         {
1098             // the temp stream pointer points to the end now
1099             aResult = m_pStream->Tell();
1100 
1101             if( aResult < nPos )
1102             {
1103                 if( m_bSourceRead )
1104                 {
1105                     aResult += ReadSourceWriteTemporary( nPos - aResult );
1106                     if( aResult < nPos )
1107                         m_bSourceRead = sal_False;
1108 
1109                     DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
1110                 }
1111 
1112                 if( (m_nMode & STREAM_WRITE) && !m_bSourceRead && aResult < nPos )
1113                 {
1114                     // it means that all the Source stream was copied already
1115                     // but the required position still was not reached
1116                     // for writable streams it should be done
1117                     m_pStream->SetStreamSize( nPos );
1118                     aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
1119                     DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
1120                 }
1121             }
1122         }
1123     }
1124 
1125     return aResult;
1126 }
1127 
1128 void  UCBStorageStream_Impl::SetSize( sal_uLong nSize )
1129 {
1130     if ( !(m_nMode & STREAM_WRITE) )
1131     {
1132         SetError( ERRCODE_IO_ACCESSDENIED );
1133         return;
1134     }
1135 
1136     if( !Init() )
1137         return;
1138 
1139     m_bModified = sal_True;
1140 
1141     if( m_bSourceRead )
1142     {
1143         sal_uLong aPos = m_pStream->Tell();
1144         m_pStream->Seek( STREAM_SEEK_TO_END );
1145         if( m_pStream->Tell() < nSize )
1146             ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
1147         m_pStream->Seek( aPos );
1148     }
1149 
1150     m_pStream->SetStreamSize( nSize );
1151     m_bSourceRead = sal_False;
1152 }
1153 
1154 void  UCBStorageStream_Impl::FlushData()
1155 {
1156     if( m_pStream )
1157     {
1158         CopySourceToTemporary();
1159         m_pStream->Flush();
1160     }
1161 
1162     m_bCommited = sal_True;
1163 }
1164 
1165 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr )
1166 {
1167     if ( !m_nError )
1168     {
1169         m_nError = nErr;
1170         SvStream::SetError( nErr );
1171         if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
1172     }
1173 }
1174 
1175 void  UCBStorageStream_Impl::ResetError()
1176 {
1177     m_nError = 0;
1178     SvStream::ResetError();
1179     if ( m_pAntiImpl )
1180         m_pAntiImpl->ResetError();
1181 }
1182 
1183 sal_uLong UCBStorageStream_Impl::GetSize()
1184 {
1185     if( !Init() )
1186         return 0;
1187 
1188     sal_uLong nPos = m_pStream->Tell();
1189     m_pStream->Seek( STREAM_SEEK_TO_END );
1190     ReadSourceWriteTemporary();
1191     sal_uLong nRet = m_pStream->Tell();
1192     m_pStream->Seek( nPos );
1193 
1194     return nRet;
1195 }
1196 
1197 BaseStorage* UCBStorageStream_Impl::CreateStorage()
1198 {
1199     // create an OLEStorage on a SvStream ( = this )
1200     // it gets the root attribute because otherwise it would probably not write before my root is commited
1201     UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1202     Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1203 
1204     // GetError() call cleares error code for OLE storages, must be changed in future
1205     long nTmpErr = pStorage->GetError();
1206     pStorage->SetError( nTmpErr );
1207 
1208     m_bIsOLEStorage = !nTmpErr;
1209     return static_cast< BaseStorage* > ( pStorage );
1210 }
1211 
1212 sal_Int16 UCBStorageStream_Impl::Commit()
1213 {
1214     // send stream to the original content
1215     // the  parent storage is responsible for the correct handling of deleted contents
1216     if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1217     {
1218         // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1219         // was commited as well ( if not opened in direct mode )
1220 
1221         if ( m_bModified )
1222         {
1223             try
1224             {
1225                 CopySourceToTemporary();
1226 
1227                 // release all stream handles
1228                 Free();
1229 
1230                 // the temporary file does not exist only for truncated streams
1231                 DBG_ASSERT( m_aTempURL.Len() || ( m_nMode & STREAM_TRUNC ), "No temporary file to read from!");
1232                 if ( !m_aTempURL.Len() && !( m_nMode & STREAM_TRUNC ) )
1233                     throw RuntimeException();
1234 
1235                 // create wrapper to stream that is only used while reading inside package component
1236                 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1237 
1238                 Any aAny;
1239                 InsertCommandArgument aArg;
1240                 aArg.Data = xStream;
1241                 aArg.ReplaceExisting = sal_True;
1242                 aAny <<= aArg;
1243                 m_pContent->executeCommand( ::rtl::OUString::createFromAscii("insert"), aAny );
1244 
1245                 // wrapper now controls lifetime of temporary file
1246                 m_aTempURL.Erase();
1247 
1248                 INetURLObject aObj( m_aURL );
1249                 aObj.SetName( m_aName );
1250                 m_aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
1251                 m_bModified = sal_False;
1252                 m_bSourceRead = sal_True;
1253             }
1254             catch ( CommandAbortedException& )
1255             {
1256                 // any command wasn't executed successfully - not specified
1257                 SetError( ERRCODE_IO_GENERAL );
1258                 return COMMIT_RESULT_FAILURE;
1259             }
1260             catch ( RuntimeException& )
1261             {
1262                 // any other error - not specified
1263                 SetError( ERRCODE_IO_GENERAL );
1264                 return COMMIT_RESULT_FAILURE;
1265             }
1266             catch ( Exception& )
1267             {
1268                 // any other error - not specified
1269                 SetError( ERRCODE_IO_GENERAL );
1270                 return COMMIT_RESULT_FAILURE;
1271             }
1272 
1273             m_bCommited = sal_False;
1274             return COMMIT_RESULT_SUCCESS;
1275         }
1276     }
1277 
1278     return COMMIT_RESULT_NOTHING_TO_DO;
1279 }
1280 
1281 sal_Bool UCBStorageStream_Impl::Revert()
1282 {
1283     // if an OLEStorage is created on this stream, no "revert" is neccessary because OLEStorages do nothing on "Revert" !
1284     if ( m_bCommited )
1285     {
1286         DBG_ERROR("Revert while commit is in progress!" );
1287         return sal_False;                   //  ???
1288     }
1289 
1290     Free();
1291     if ( m_aTempURL.Len() )
1292     {
1293         ::utl::UCBContentHelper::Kill( m_aTempURL );
1294         m_aTempURL.Erase();
1295     }
1296 
1297     m_bSourceRead = sal_False;
1298     try
1299     {
1300         m_rSource = m_pContent->openStream();
1301         if( m_rSource.is() )
1302         {
1303             if ( m_pAntiImpl && ( m_nMode & STREAM_TRUNC ) )
1304                 // stream is in use and should be truncated
1305                 m_bSourceRead = sal_False;
1306             else
1307             {
1308                 m_nMode &= ~STREAM_TRUNC;
1309                 m_bSourceRead = sal_True;
1310             }
1311         }
1312         else
1313             SetError( SVSTREAM_CANNOT_MAKE );
1314     }
1315     catch ( ContentCreationException& )
1316     {
1317         SetError( ERRCODE_IO_GENERAL );
1318     }
1319     catch ( RuntimeException& )
1320     {
1321         SetError( ERRCODE_IO_GENERAL );
1322     }
1323     catch ( Exception& )
1324     {
1325     }
1326 
1327     m_bModified = sal_False;
1328     m_aName = m_aOriginalName;
1329     m_aContentType = m_aOriginalContentType;
1330     return ( GetError() == ERRCODE_NONE );
1331 }
1332 
1333 sal_Bool UCBStorageStream_Impl::Clear()
1334 {
1335     sal_Bool bRet = ( m_pAntiImpl == NULL );
1336     DBG_ASSERT( bRet, "Removing used stream!" );
1337     if( bRet )
1338     {
1339         Free();
1340     }
1341 
1342     return bRet;
1343 }
1344 
1345 void UCBStorageStream_Impl::Free()
1346 {
1347 #if OSL_DEBUG_LEVEL > 1
1348     if ( m_pStream )
1349     {
1350         if ( m_aTempURL.Len() )
1351             --nOpenFiles;
1352         else
1353             --nOpenStreams;
1354     }
1355 #endif
1356 
1357     m_nRepresentMode = nonset;
1358     m_rSource = Reference< XInputStream >();
1359     DELETEZ( m_pStream );
1360 }
1361 
1362 void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1363 {
1364     sal_Bool isWritable = (( m_nMode & STREAM_WRITE ) != 0 );
1365     if ( isWritable )
1366     {
1367         // once stream was writable, never reset to readonly
1368         nMode |= STREAM_WRITE;
1369     }
1370 
1371     m_nMode = nMode;
1372     Free();
1373 
1374     if ( nMode & STREAM_TRUNC )
1375     {
1376         m_bSourceRead = 0; // usually it should be 0 already but just in case...
1377 
1378         if ( m_aTempURL.Len() )
1379         {
1380             ::utl::UCBContentHelper::Kill( m_aTempURL );
1381             m_aTempURL.Erase();
1382         }
1383     }
1384 }
1385 
1386 UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
1387 {
1388     // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1389     // to class UCBStorageStream !
1390     pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey );
1391     pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
1392     StorageBase::m_nMode = pImp->m_nMode;
1393 }
1394 
1395 UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress )
1396 {
1397     // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1398     // to class UCBStorageStream !
1399     pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey, bRepair, xProgress );
1400     pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
1401     StorageBase::m_nMode = pImp->m_nMode;
1402 }
1403 
1404 UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1405     : pImp( pImpl )
1406 {
1407     pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
1408     pImp->m_pAntiImpl = this;
1409     SetError( pImp->m_nError );
1410     StorageBase::m_nMode = pImp->m_nMode;
1411 }
1412 
1413 UCBStorageStream::~UCBStorageStream()
1414 {
1415     if ( pImp->m_nMode & STREAM_WRITE )
1416         pImp->Flush();
1417     pImp->m_pAntiImpl = NULL;
1418     pImp->Free();
1419     pImp->ReleaseRef();
1420 }
1421 
1422 sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
1423 {
1424     //return pImp->m_pStream->Read( pData, nSize );
1425     return pImp->GetData( pData, nSize );
1426 }
1427 
1428 sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
1429 {
1430 /*
1431     // mba: does occur in writer !
1432     if ( pImp->m_bCommited )
1433     {
1434         DBG_ERROR("Writing while commit is in progress!" );
1435         return 0;
1436     }
1437 */
1438     // pImp->m_bModified = sal_True;
1439     //return pImp->m_pStream->Write( pData, nSize );
1440     return pImp->PutData( pData, nSize );
1441 }
1442 
1443 sal_uLong UCBStorageStream::Seek( sal_uLong nPos )
1444 {
1445     //return pImp->m_pStream->Seek( nPos );
1446     return pImp->Seek( nPos );
1447 }
1448 
1449 sal_uLong UCBStorageStream::Tell()
1450 {
1451     if( !pImp->Init() )
1452         return 0;
1453     return pImp->m_pStream->Tell();
1454 }
1455 
1456 void UCBStorageStream::Flush()
1457 {
1458     // streams are never really transacted, so flush also means commit !
1459     Commit();
1460 }
1461 
1462 sal_Bool UCBStorageStream::SetSize( sal_uLong nNewSize )
1463 {
1464 /*
1465     if ( pImp->m_bCommited )
1466     {
1467         DBG_ERROR("Changing stream size while commit is in progress!" );
1468         return sal_False;
1469     }
1470 */
1471     // pImp->m_bModified = sal_True;
1472     //return pImp->m_pStream->SetStreamSize( nNewSize );
1473     pImp->SetSize( nNewSize );
1474     return !pImp->GetError();
1475 }
1476 
1477 sal_Bool UCBStorageStream::Validate( sal_Bool bWrite ) const
1478 {
1479     return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
1480 }
1481 
1482 sal_Bool UCBStorageStream::ValidateMode( StreamMode m ) const
1483 {
1484     // ???
1485     if( m == ( STREAM_READ | STREAM_TRUNC ) )  // from stg.cxx
1486         return sal_True;
1487     sal_uInt16 nCurMode = 0xFFFF;
1488     if( ( m & 3 ) == STREAM_READ )
1489     {
1490         // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1491         if( ( ( m & STREAM_SHARE_DENYWRITE )
1492            && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
1493          || ( ( m & STREAM_SHARE_DENYALL )
1494            && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
1495             return sal_True;
1496     }
1497     else
1498     {
1499         // only SHARE_DENYALL allowed
1500         // storages open in r/o mode are OK, since only
1501         // the commit may fail
1502         if( ( m & STREAM_SHARE_DENYALL )
1503          && ( nCurMode & STREAM_SHARE_DENYALL ) )
1504             return sal_True;
1505     }
1506 
1507     return sal_True;
1508 }
1509 
1510 const SvStream* UCBStorageStream::GetSvStream() const
1511 {
1512     if( !pImp->Init() )
1513         return NULL;
1514 
1515     pImp->CopySourceToTemporary();
1516     return pImp->m_pStream; // should not live longer then pImp!!!
1517 }
1518 
1519 SvStream* UCBStorageStream::GetModifySvStream()
1520 {
1521     return (SvStream*)pImp;
1522 }
1523 
1524 Reference< XInputStream > UCBStorageStream::GetXInputStream() const
1525 {
1526     return pImp->GetXInputStream();
1527 }
1528 
1529 sal_Bool  UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1530 {
1531     // ???
1532     return ((BaseStorageStream*) this ) == &rStream;
1533 }
1534 
1535 sal_Bool UCBStorageStream::Commit()
1536 {
1537     // mark this stream for sending it on root commit
1538     pImp->FlushData();
1539     return sal_True;
1540 }
1541 
1542 sal_Bool UCBStorageStream::Revert()
1543 {
1544     return pImp->Revert();
1545 }
1546 
1547 sal_Bool UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1548 {
1549     if( !pImp->Init() )
1550         return sal_False;
1551 
1552     UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
1553     if ( pStg )
1554         pStg->pImp->m_aContentType = pImp->m_aContentType;
1555 
1556     pDestStm->SetSize( 0 );
1557     Seek( STREAM_SEEK_TO_END );
1558     sal_Int32 n = Tell();
1559     if( n < 0 )
1560         return sal_False;
1561 
1562     if( pDestStm->SetSize( n ) && n )
1563     {
1564         sal_uInt8* p = new sal_uInt8[ 4096 ];
1565         Seek( 0L );
1566         pDestStm->Seek( 0L );
1567         while( n )
1568         {
1569             sal_uInt32 nn = n;
1570             if( nn > 4096 )
1571                 nn = 4096;
1572             if( Read( p, nn ) != nn )
1573                 break;
1574             if( pDestStm->Write( p, nn ) != nn )
1575                 break;
1576             n -= nn;
1577         }
1578 
1579         delete[] p;
1580     }
1581 
1582     return sal_True;
1583 }
1584 
1585 sal_Bool UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
1586 {
1587     if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
1588         return sal_False;
1589 
1590     if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
1591     {
1592         ::rtl::OUString aTmp;
1593         rValue >>= aTmp;
1594         pImp->m_aContentType = aTmp;
1595     }
1596 
1597     try
1598     {
1599         if ( pImp->m_pContent )
1600         {
1601             pImp->m_pContent->setPropertyValue( rName, rValue );
1602             return sal_True;
1603         }
1604     }
1605     catch ( Exception& )
1606     {
1607     }
1608 
1609     return sal_False;
1610 }
1611 
1612 sal_Bool UCBStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
1613 {
1614     try
1615     {
1616         if ( pImp->m_pContent )
1617         {
1618             rValue = pImp->m_pContent->getPropertyValue( rName );
1619             return sal_True;
1620         }
1621     }
1622     catch ( Exception& )
1623     {
1624     }
1625 
1626     return sal_False;
1627 }
1628 
1629 UCBStorage::UCBStorage( SvStream& rStrm, sal_Bool bDirect )
1630 {
1631     String aURL = GetLinkedFile( rStrm );
1632     if ( aURL.Len() )
1633     {
1634         StreamMode nMode = STREAM_READ;
1635         if( rStrm.IsWritable() )
1636             nMode = STREAM_READ | STREAM_WRITE;
1637 
1638         ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >() );
1639         pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, sal_True );
1640     }
1641     else
1642     {
1643         // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1644         // to class UCBStorage !
1645         pImp = new UCBStorage_Impl( rStrm, this, bDirect );
1646     }
1647 
1648     pImp->AddRef();
1649     pImp->Init();
1650     StorageBase::m_nMode = pImp->m_nMode;
1651 }
1652 
1653 UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot )
1654 {
1655     // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1656     // to class UCBStorage !
1657     pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1658     pImp->AddRef();
1659     pImp->Init();
1660     StorageBase::m_nMode = pImp->m_nMode;
1661 }
1662 
1663 UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
1664 {
1665     // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1666     // to class UCBStorage !
1667     pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1668     pImp->AddRef();
1669     pImp->Init();
1670     StorageBase::m_nMode = pImp->m_nMode;
1671 }
1672 
1673 UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot )
1674 {
1675     // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1676     // to class UCBStorage !
1677     pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, sal_False, Reference< XProgressHandler >() );
1678     pImp->AddRef();
1679     pImp->Init();
1680     StorageBase::m_nMode = pImp->m_nMode;
1681 }
1682 
1683 UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1684     : pImp( pImpl )
1685 {
1686     pImp->m_pAntiImpl = this;
1687     SetError( pImp->m_nError );
1688     pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
1689     StorageBase::m_nMode = pImp->m_nMode;
1690 }
1691 
1692 UCBStorage::~UCBStorage()
1693 {
1694     if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1695         // DirectMode is simulated with an AutoCommit
1696         Commit();
1697 
1698     pImp->m_pAntiImpl = NULL;
1699     pImp->ReleaseRef();
1700 }
1701 
1702 UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler  )
1703     : m_pAntiImpl( pStorage )
1704     , m_pContent( new ::ucbhelper::Content( rContent ) )
1705     , m_pTempFile( NULL )
1706     , m_pSource( NULL )
1707     //, m_pStream( NULL )
1708     , m_nError( 0 )
1709     , m_nMode( nMode )
1710     , m_bModified( sal_False )
1711     , m_bCommited( sal_False )
1712     , m_bDirect( bDirect )
1713     , m_bIsRoot( bIsRoot )
1714     , m_bDirty( sal_False )
1715     , m_bIsLinked( sal_True )
1716     , m_bListCreated( sal_False )
1717     , m_nFormat( 0 )
1718     , m_aClassId( SvGlobalName() )
1719     , m_bRepairPackage( bIsRepair )
1720     , m_xProgressHandler( xProgressHandler )
1721     , m_pUNOStorageHolderList( NULL )
1722 
1723 {
1724     String aName( rName );
1725     if( !aName.Len() )
1726     {
1727         // no name given = use temporary name!
1728         DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1729         m_pTempFile = new ::utl::TempFile;
1730         m_pTempFile->EnableKillingFile( sal_True );
1731         m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1732     }
1733 
1734     m_aURL = rName;
1735 }
1736 
1737 UCBStorage_Impl::UCBStorage_Impl( const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
1738     : m_pAntiImpl( pStorage )
1739     , m_pContent( NULL )
1740     , m_pTempFile( NULL )
1741     , m_pSource( NULL )
1742     //, m_pStream( NULL )
1743     , m_nError( 0 )
1744     , m_nMode( nMode )
1745     , m_bModified( sal_False )
1746     , m_bCommited( sal_False )
1747     , m_bDirect( bDirect )
1748     , m_bIsRoot( bIsRoot )
1749     , m_bDirty( sal_False )
1750     , m_bIsLinked( sal_False )
1751     , m_bListCreated( sal_False )
1752     , m_nFormat( 0 )
1753     , m_aClassId( SvGlobalName() )
1754     , m_bRepairPackage( bIsRepair )
1755     , m_xProgressHandler( xProgressHandler )
1756     , m_pUNOStorageHolderList( NULL )
1757 {
1758     String aName( rName );
1759     if( !aName.Len() )
1760     {
1761         // no name given = use temporary name!
1762         DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1763         m_pTempFile = new ::utl::TempFile;
1764         m_pTempFile->EnableKillingFile( sal_True );
1765         m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1766     }
1767 
1768     if ( m_bIsRoot )
1769     {
1770         // create the special package URL for the package content
1771         String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
1772         aTemp += String(INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1773         m_aURL = aTemp;
1774 
1775         if ( m_nMode & STREAM_WRITE )
1776         {
1777             // the root storage opens the package, so make sure that there is any
1778             SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READWRITE, m_pTempFile != 0 /* bFileExists */ );
1779             delete pStream;
1780         }
1781     }
1782     else
1783     {
1784         // substorages are opened like streams: the URL is a "child URL" of the root package URL
1785         m_aURL = rName;
1786         if ( m_aURL.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 )
1787             m_bIsLinked = sal_True;
1788     }
1789 }
1790 
1791 UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, sal_Bool bDirect )
1792     : m_pAntiImpl( pStorage )
1793     , m_pContent( NULL )
1794     , m_pTempFile( new ::utl::TempFile )
1795     , m_pSource( &rStream )
1796     , m_nError( 0 )
1797     , m_bModified( sal_False )
1798     , m_bCommited( sal_False )
1799     , m_bDirect( bDirect )
1800     , m_bIsRoot( sal_True )
1801     , m_bDirty( sal_False )
1802     , m_bIsLinked( sal_False )
1803     , m_bListCreated( sal_False )
1804     , m_nFormat( 0 )
1805     , m_aClassId( SvGlobalName() )
1806     , m_bRepairPackage( sal_False )
1807     , m_pUNOStorageHolderList( NULL )
1808 {
1809     // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1810     // which will be called in the storages' dtor
1811     m_pTempFile->EnableKillingFile( sal_True );
1812     DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1813 
1814     // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1815     // accessed readonly
1816     // the root storage opens the package; create the special package URL for the package content
1817     String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
1818     aTemp += String(INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1819     m_aURL = aTemp;
1820 
1821     // copy data into the temporary file
1822     SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, sal_True /* bFileExists */ );
1823     if ( pStream )
1824     {
1825         rStream.Seek(0);
1826         rStream >> *pStream;
1827         pStream->Flush();
1828         DELETEZ( pStream );
1829     }
1830 
1831     // close stream and let content access the file
1832     m_pSource->Seek(0);
1833 
1834     // check opening mode
1835     m_nMode = STREAM_READ;
1836     if( rStream.IsWritable() )
1837         m_nMode = STREAM_READ | STREAM_WRITE;
1838 }
1839 
1840 void UCBStorage_Impl::Init()
1841 {
1842     // name is last segment in URL
1843     INetURLObject aObj( m_aURL );
1844     if ( !m_aName.Len() )
1845         // if the name was not already set to a temp name
1846         m_aName = m_aOriginalName = aObj.GetLastName();
1847 
1848     // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
1849     if ( !m_pContent && !( m_nMode & STORAGE_DISKSPANNED_MODE ) )
1850         CreateContent();
1851 
1852     if ( m_nMode & STORAGE_DISKSPANNED_MODE )
1853     {
1854         // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
1855         // disk spanned file
1856         m_aContentType = m_aOriginalContentType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.xml.impress") );
1857     }
1858     else if ( m_pContent )
1859     {
1860         if ( m_bIsLinked )
1861         {
1862             if( m_bIsRoot )
1863             {
1864                 ReadContent();
1865                 if ( m_nError == ERRCODE_NONE )
1866                 {
1867                     // read the manifest.xml file
1868                     aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("META-INF") ) );
1869                     aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("manifest.xml") ) );
1870 
1871                     // create input stream
1872                     SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
1873                     // no stream means no manifest.xml
1874                     if ( pStream )
1875                     {
1876                         if ( !pStream->GetError() )
1877                         {
1878                             ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1879                             com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xInputStream;
1880                             xInputStream = pHelper;
1881 
1882                             // create a manifest reader object that will read in the manifest from the stream
1883                             Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader =
1884                                 Reference< ::com::sun::star::packages::manifest::XManifestReader >
1885                                     ( ::comphelper::getProcessServiceFactory()->createInstance(
1886                                         ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestReader" )), UNO_QUERY) ;
1887                             Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1888 
1889                             // cleanup
1890                             xReader = NULL;
1891                             xInputStream = NULL;
1892                             SetProps( aProps, String() );
1893                         }
1894 
1895                         delete pStream;
1896                     }
1897                 }
1898             }
1899             else
1900                 ReadContent();
1901         }
1902         else
1903         {
1904             // get the manifest information from the package
1905             try {
1906                 Any aAny = m_pContent->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
1907                 rtl::OUString aTmp;
1908                 if ( ( aAny >>= aTmp ) && aTmp.getLength() )
1909                     m_aContentType = m_aOriginalContentType = aTmp;
1910             }
1911             catch( Exception& )
1912             {
1913                 DBG_ASSERT( sal_False,
1914                             "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1915             }
1916         }
1917     }
1918 
1919     if ( m_aContentType.Len() )
1920     {
1921         // get the clipboard format using the content type
1922         ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
1923         aDataFlavor.MimeType = m_aContentType;
1924         m_nFormat = SotExchange::GetFormat( aDataFlavor );
1925 
1926         // get the ClassId using the clipboard format ( internal table )
1927         m_aClassId = GetClassId_Impl( m_nFormat );
1928 
1929         // get human presentable name using the clipboard format
1930         SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1931         m_aUserTypeName = aDataFlavor.HumanPresentableName;
1932 
1933         if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1934             ReadContent();
1935     }
1936 }
1937 
1938 void UCBStorage_Impl::CreateContent()
1939 {
1940     try
1941     {
1942         // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1943         Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1944 
1945         ::rtl::OUString aTemp( m_aURL );
1946 
1947         if ( m_bRepairPackage )
1948         {
1949             xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
1950                                                      m_xProgressHandler );
1951             aTemp += rtl::OUString::createFromAscii("?repairpackage");
1952         }
1953 
1954         m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
1955     }
1956     catch ( ContentCreationException& )
1957     {
1958         // content could not be created
1959         SetError( SVSTREAM_CANNOT_MAKE );
1960     }
1961     catch ( RuntimeException& )
1962     {
1963         // any other error - not specified
1964         SetError( SVSTREAM_CANNOT_MAKE );
1965     }
1966 }
1967 
1968 void UCBStorage_Impl::ReadContent()
1969 {
1970    if ( m_bListCreated )
1971         return;
1972 
1973     m_bListCreated = sal_True;
1974 
1975     // create cursor for access to children
1976     Sequence< ::rtl::OUString > aProps(4);
1977     ::rtl::OUString* pProps = aProps.getArray();
1978     pProps[0] = ::rtl::OUString::createFromAscii( "Title" );
1979     pProps[1] = ::rtl::OUString::createFromAscii( "IsFolder" );
1980     pProps[2] = ::rtl::OUString::createFromAscii( "MediaType" );
1981     pProps[3] = ::rtl::OUString::createFromAscii( "Size" );
1982     ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS;
1983 
1984     try
1985     {
1986         GetContent();
1987         if ( !m_pContent )
1988             return;
1989 
1990         Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude );
1991         Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
1992         Reference< XRow > xRow( xResultSet, UNO_QUERY );
1993         if ( xResultSet.is() )
1994         {
1995             while ( xResultSet->next() )
1996             {
1997                 // insert all into the children list
1998                 ::rtl::OUString aTitle( xRow->getString(1) );
1999                 ::rtl::OUString aContentType;
2000                 if ( m_bIsLinked )
2001                 {
2002                     // unpacked storages have to deal with the meta-inf folder by themselves
2003                     if( aTitle.equalsAscii("META-INF") )
2004                         continue;
2005                 }
2006                 else
2007                 {
2008                     aContentType = xRow->getString(3);
2009                 }
2010 
2011                 sal_Bool bIsFolder( xRow->getBoolean(2) );
2012                 sal_Int64 nSize = xRow->getLong(4);
2013                 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (sal_uLong) nSize );
2014                 m_aChildrenList.Insert( pElement, LIST_APPEND );
2015 
2016                 sal_Bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
2017                 if ( bIsFolder )
2018                 {
2019                     if ( m_bIsLinked )
2020                         OpenStorage( pElement, m_nMode, m_bDirect );
2021                     if ( pElement->m_xStorage.Is() )
2022                         pElement->m_xStorage->Init();
2023                 }
2024                 else if ( bIsOfficeDocument )
2025                 {
2026                     // streams can be external OLE objects, so they are now folders, but storages!
2027                     String aName( m_aURL );
2028                     aName += '/';
2029                     aName += String( xRow->getString(1) );
2030 
2031                     Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
2032                     if ( m_bRepairPackage )
2033                     {
2034                         xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
2035                                                                 m_xProgressHandler );
2036                             aName += String( RTL_CONSTASCII_USTRINGPARAM( "?repairpackage" ) );
2037                     }
2038 
2039                     ::ucbhelper::Content aContent( aName, xComEnv );
2040 
2041                     ::rtl::OUString aMediaType;
2042                     Any aAny = aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
2043                     if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
2044                         pElement->m_bIsStorage = sal_True;
2045                     else if ( !aMediaType.getLength() )
2046                     {
2047                         // older files didn't have that special content type, so they must be detected
2048                         OpenStream( pElement, STREAM_STD_READ, m_bDirect );
2049                         if ( Storage::IsStorageFile( pElement->m_xStream ) )
2050                             pElement->m_bIsStorage = sal_True;
2051                         else
2052                             pElement->m_xStream->Free();
2053                     }
2054                 }
2055             }
2056         }
2057     }
2058     catch ( InteractiveIOException& r )
2059     {
2060         if ( r.Code != IOErrorCode_NOT_EXISTING )
2061             SetError( ERRCODE_IO_GENERAL );
2062     }
2063     catch ( CommandAbortedException& )
2064     {
2065         // any command wasn't executed successfully - not specified
2066         if ( !( m_nMode & STREAM_WRITE ) )
2067             // if the folder was just inserted and not already commited, this is not an error!
2068             SetError( ERRCODE_IO_GENERAL );
2069     }
2070     catch ( RuntimeException& )
2071     {
2072         // any other error - not specified
2073         SetError( ERRCODE_IO_GENERAL );
2074     }
2075     catch ( ResultSetException& )
2076     {
2077         // means that the package file is broken
2078         SetError( ERRCODE_IO_BROKENPACKAGE );
2079     }
2080     catch ( SQLException& )
2081     {
2082         // means that the file can be broken
2083         SetError( ERRCODE_IO_WRONGFORMAT );
2084     }
2085     catch ( Exception& )
2086     {
2087         // any other error - not specified
2088         SetError( ERRCODE_IO_GENERAL );
2089     }
2090 }
2091 
2092 void UCBStorage_Impl::SetError( long nError )
2093 {
2094     if ( !m_nError )
2095     {
2096         m_nError = nError;
2097         if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
2098     }
2099 }
2100 
2101 sal_Int32 UCBStorage_Impl::GetObjectCount()
2102 {
2103     sal_Int32 nCount = m_aChildrenList.Count();
2104     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2105     while ( pElement )
2106     {
2107         DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2108         if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2109             nCount += pElement->m_xStorage->GetObjectCount();
2110         pElement = m_aChildrenList.Next();
2111     }
2112 
2113     return nCount;
2114 }
2115 
2116 ::rtl::OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const ::rtl::OUString& rPath )
2117 {
2118     sal_Bool bFound = sal_False;
2119     for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
2120     {
2121         const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
2122         ::rtl::OUString aType;
2123 
2124         for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
2125         {
2126             const PropertyValue& rAny = rMyProps[nProps];
2127             if ( rAny.Name.equalsAscii("FullPath") )
2128             {
2129                 rtl::OUString aTmp;
2130                 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
2131                     bFound = sal_True;
2132                 if ( aType.getLength() )
2133                     break;
2134             }
2135             else if ( rAny.Name.equalsAscii("MediaType") )
2136             {
2137                 if ( ( rAny.Value >>= aType ) && aType.getLength() && bFound )
2138                     break;
2139             }
2140         }
2141 
2142         if ( bFound )
2143             return aType;
2144     }
2145 
2146     return ::rtl::OUString();
2147 }
2148 
2149 void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2150 {
2151     String aPath( rPath );
2152     if ( !m_bIsRoot )
2153         aPath += m_aName;
2154     aPath += '/';
2155 
2156     m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
2157 
2158     if ( m_bIsRoot )
2159         // the "FullPath" of a child always starts without '/'
2160         aPath.Erase();
2161 
2162     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2163     while ( pElement )
2164     {
2165         DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2166         if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2167             pElement->m_xStorage->SetProps( rSequence, aPath );
2168         else
2169         {
2170             String aElementPath( aPath );
2171             aElementPath += pElement->m_aName;
2172             pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
2173         }
2174 
2175         pElement = m_aChildrenList.Next();
2176     }
2177 
2178     if ( m_aContentType.Len() )
2179     {
2180         // get the clipboard format using the content type
2181         ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2182         aDataFlavor.MimeType = m_aContentType;
2183         m_nFormat = SotExchange::GetFormat( aDataFlavor );
2184 
2185         // get the ClassId using the clipboard format ( internal table )
2186         m_aClassId = GetClassId_Impl( m_nFormat );
2187 
2188         // get human presentable name using the clipboard format
2189         SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
2190         m_aUserTypeName = aDataFlavor.HumanPresentableName;
2191     }
2192 }
2193 
2194 void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2195 {
2196     // first my own properties
2197     Sequence < PropertyValue > aProps(2);
2198 
2199     // first property is the "FullPath" name
2200     // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2201     String aPath( rPath );
2202     if ( !m_bIsRoot )
2203         aPath += m_aName;
2204     aPath += '/';
2205     aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2206     aProps[0].Value <<= (::rtl::OUString ) m_aContentType;
2207     aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2208     aProps[1].Value <<= (::rtl::OUString ) aPath;
2209     rSequence[ nProps++ ] = aProps;
2210 
2211     if ( m_bIsRoot )
2212         // the "FullPath" of a child always starts without '/'
2213         aPath.Erase();
2214 
2215     // now the properties of my elements
2216     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2217     while ( pElement )
2218     {
2219         DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2220         if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2221             // storages add there properties by themselves ( see above )
2222             pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
2223         else
2224         {
2225             // properties of streams
2226             String aElementPath( aPath );
2227             aElementPath += pElement->m_aName;
2228             aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2229             aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType();
2230             aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2231             aProps[1].Value <<= (::rtl::OUString ) aElementPath;
2232             rSequence[ nProps++ ] = aProps;
2233         }
2234 
2235         pElement = m_aChildrenList.Next();
2236     }
2237 }
2238 
2239 UCBStorage_Impl::~UCBStorage_Impl()
2240 {
2241     if ( m_pUNOStorageHolderList )
2242     {
2243         for ( UNOStorageHolderList::iterator aIter = m_pUNOStorageHolderList->begin();
2244               aIter != m_pUNOStorageHolderList->end(); aIter++ )
2245             if ( *aIter )
2246             {
2247                 (*aIter)->InternalDispose();
2248                 (*aIter)->release();
2249                 (*aIter) = NULL;
2250             }
2251 
2252         m_pUNOStorageHolderList->clear();
2253         DELETEZ( m_pUNOStorageHolderList );
2254     }
2255 
2256     // first delete elements!
2257     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2258     while ( pElement )
2259     {
2260         delete pElement;
2261         pElement = m_aChildrenList.Next();
2262     }
2263 
2264     m_aChildrenList.Clear();
2265     delete m_pContent;
2266     delete m_pTempFile;
2267 }
2268 
2269 sal_Bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
2270 {
2271     // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2272     // it must be inserted with a title and a type
2273     sal_Bool bRet = sal_False;
2274 
2275     try
2276     {
2277         Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
2278         sal_Int32 nCount = aInfo.getLength();
2279         if ( nCount == 0 )
2280             return sal_False;
2281 
2282         for ( sal_Int32 i = 0; i < nCount; ++i )
2283         {
2284             // Simply look for the first KIND_FOLDER...
2285             const ContentInfo & rCurr = aInfo[i];
2286             if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
2287             {
2288                 // Make sure the only required bootstrap property is "Title",
2289                 const Sequence< Property > & rProps = rCurr.Properties;
2290                 if ( rProps.getLength() != 1 )
2291                     continue;
2292 
2293                 if ( !rProps[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
2294                     continue;
2295 
2296                 Sequence < ::rtl::OUString > aNames(1);
2297                 ::rtl::OUString* pNames = aNames.getArray();
2298                 pNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
2299                 Sequence < Any > aValues(1);
2300                 Any* pValues = aValues.getArray();
2301                 pValues[0] = makeAny( ::rtl::OUString( m_aName ) );
2302 
2303                 Content aNewFolder;
2304                 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
2305                     continue;
2306 
2307                 // remove old content, create an "empty" new one and initialize it with the new inserted
2308                 DELETEZ( m_pContent );
2309                 m_pContent = new ::ucbhelper::Content( aNewFolder );
2310                 bRet = sal_True;
2311             }
2312         }
2313     }
2314     catch ( CommandAbortedException& )
2315     {
2316         // any command wasn't executed successfully - not specified
2317         SetError( ERRCODE_IO_GENERAL );
2318     }
2319     catch ( RuntimeException& )
2320     {
2321         // any other error - not specified
2322         SetError( ERRCODE_IO_GENERAL );
2323     }
2324     catch ( Exception& )
2325     {
2326         // any other error - not specified
2327         SetError( ERRCODE_IO_GENERAL );
2328     }
2329 
2330     return bRet;
2331 }
2332 
2333 sal_Int16 UCBStorage_Impl::Commit()
2334 {
2335     // send all changes to the package
2336     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2337     sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
2338 
2339     // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2340     // commit command has been sent
2341     if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) )
2342     {
2343         try
2344         {
2345             // all errors will be caught in the "catch" statement outside the loop
2346             while ( pElement && nRet )
2347             {
2348                 ::ucbhelper::Content* pContent = pElement->GetContent();
2349                 sal_Bool bDeleteContent = sal_False;
2350                 if ( !pContent && pElement->IsModified() )
2351                 {
2352                     // if the element has never been opened, no content has been created until now
2353                     bDeleteContent = sal_True;  // remember to delete it later
2354                     String aName( m_aURL );
2355                     aName += '/';
2356                     aName += pElement->m_aOriginalName;
2357                     pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
2358                 }
2359 
2360                 if ( pElement->m_bIsRemoved )
2361                 {
2362                     // was it inserted, then removed (so there would be nothing to do!)
2363                     if ( !pElement->m_bIsInserted )
2364                     {
2365                         // first remove all open stream handles
2366                         if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() )
2367                         {
2368                             pContent->executeCommand( ::rtl::OUString::createFromAscii("delete"), makeAny( sal_Bool( sal_True ) ) );
2369                             nRet = COMMIT_RESULT_SUCCESS;
2370                         }
2371                         else
2372                             // couldn't release stream because there are external references to it
2373                             nRet = COMMIT_RESULT_FAILURE;
2374                     }
2375                 }
2376                 else
2377                 {
2378                     sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2379                     if ( pElement->m_xStorage.Is() )
2380                     {
2381                         // element is a storage
2382                         // do a commit in the following cases:
2383                         //  - if storage is already inserted, and changed
2384                         //  - storage is not in a package
2385                         //  - it's a new storage, try to insert and commit if successful inserted
2386                         if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
2387                         {
2388                             nLocalRet = pElement->m_xStorage->Commit();
2389                             pContent = pElement->GetContent();
2390                         }
2391                     }
2392                     else if ( pElement->m_xStream.Is() )
2393                     {
2394                         // element is a stream
2395                         nLocalRet = pElement->m_xStream->Commit();
2396                         if ( pElement->m_xStream->m_bIsOLEStorage )
2397                         {
2398                             // OLE storage should be stored encrytped, if the storage uses encryption
2399                             pElement->m_xStream->m_aContentType = String::CreateFromAscii("application/vnd.sun.star.oleobject");
2400                             Any aValue;
2401                             aValue <<= (sal_Bool) sal_True;
2402                             pElement->m_xStream->m_pContent->setPropertyValue(String::CreateFromAscii("Encrypted"), aValue );
2403                         }
2404 
2405                         pContent = pElement->GetContent();
2406                     }
2407 
2408                     if ( pElement->m_aName != pElement->m_aOriginalName )
2409                     {
2410                         // name ( title ) of the element was changed
2411                         nLocalRet = COMMIT_RESULT_SUCCESS;
2412                         Any aAny;
2413                         aAny <<= (rtl::OUString) pElement->m_aName;
2414                         pContent->setPropertyValue( ::rtl::OUString::createFromAscii("Title"), aAny );
2415                     }
2416 
2417                     if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() )
2418                     {
2419                         // mediatype of the element was changed
2420                         nLocalRet = COMMIT_RESULT_SUCCESS;
2421                         Any aAny;
2422                         aAny <<= (rtl::OUString) pElement->GetContentType();
2423                         pContent->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
2424                     }
2425 
2426                     if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2427                         nRet = nLocalRet;
2428                 }
2429 
2430                 if ( bDeleteContent )
2431                     // content was created inside the loop
2432                     delete pContent;
2433 
2434                 if ( nRet == COMMIT_RESULT_FAILURE )
2435                     break;
2436 
2437                 pElement = m_aChildrenList.Next();
2438             }
2439         }
2440         catch ( ContentCreationException& )
2441         {
2442             // content could not be created
2443             SetError( ERRCODE_IO_NOTEXISTS );
2444             return COMMIT_RESULT_FAILURE;
2445         }
2446         catch ( CommandAbortedException& )
2447         {
2448             // any command wasn't executed successfully - not specified
2449             SetError( ERRCODE_IO_GENERAL );
2450             return COMMIT_RESULT_FAILURE;
2451         }
2452         catch ( RuntimeException& )
2453         {
2454             // any other error - not specified
2455             SetError( ERRCODE_IO_GENERAL );
2456             return COMMIT_RESULT_FAILURE;
2457         }
2458         catch ( Exception& )
2459         {
2460             // any other error - not specified
2461             SetError( ERRCODE_IO_GENERAL );
2462             return COMMIT_RESULT_FAILURE;
2463         }
2464 
2465         if ( m_bIsRoot && m_pContent )
2466         {
2467             // the root storage must flush the root package content
2468             if ( nRet == COMMIT_RESULT_SUCCESS )
2469             {
2470                 try
2471                 {
2472                     // commit the media type to the JAR file
2473                     // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2474                     Any aType;
2475                     aType <<= (rtl::OUString) m_aContentType;
2476                     m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType );
2477 
2478                     if (  m_bIsLinked )
2479                     {
2480                         // write a manifest file
2481                         // first create a subfolder "META-inf"
2482                         Content aNewSubFolder;
2483                         sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, String::CreateFromAscii("META-INF"), aNewSubFolder );
2484                         if ( bRet )
2485                         {
2486                             // create a stream to write the manifest file - use a temp file
2487                             String aURL( aNewSubFolder.getURL() );
2488                             ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL );
2489 
2490                             // get the stream from the temp file and create an output stream wrapper
2491                             SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE );
2492                             ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2493                             com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper );
2494 
2495                             // create a manifest writer object that will fill the stream
2496                             Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter =
2497                                 Reference< ::com::sun::star::packages::manifest::XManifestWriter >
2498                                     ( ::comphelper::getProcessServiceFactory()->createInstance(
2499                                         ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestWriter" )), UNO_QUERY) ;
2500                             sal_Int32 nCount = GetObjectCount() + 1;
2501                             Sequence < Sequence < PropertyValue > > aProps( nCount );
2502                             sal_Int32 nProps = 0;
2503                             GetProps( nProps, aProps, String() );
2504                             xWriter->writeManifestSequence( xOutputStream, aProps );
2505 
2506                             // move the stream to its desired location
2507                             Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
2508                             xWriter = NULL;
2509                             xOutputStream = NULL;
2510                             DELETEZ( pTempFile );
2511                             aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE );
2512                         }
2513                     }
2514                     else
2515                     {
2516 #if OSL_DEBUG_LEVEL > 1
2517                         fprintf ( stderr, "Files: %i\n", nOpenFiles );
2518                         fprintf ( stderr, "Streams: %i\n", nOpenStreams );
2519 #endif
2520                         // force writing
2521                         Any aAny;
2522                         m_pContent->executeCommand( ::rtl::OUString::createFromAscii("flush"), aAny );
2523                         if ( m_pSource != 0 )
2524                         {
2525                             SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ );
2526                             m_pSource->SetStreamSize(0);
2527                             // m_pSource->Seek(0);
2528                             *pStream >> *m_pSource;
2529                             DELETEZ( pStream );
2530                             m_pSource->Seek(0);
2531                         }
2532                     }
2533                 }
2534                 catch ( CommandAbortedException& )
2535                 {
2536                     // how to tell the content : forget all changes ?!
2537                     // or should we assume that the content does it by itself because he throwed an exception ?!
2538                     // any command wasn't executed successfully - not specified
2539                     SetError( ERRCODE_IO_GENERAL );
2540                     return COMMIT_RESULT_FAILURE;
2541                 }
2542                 catch ( RuntimeException& )
2543                 {
2544                     // how to tell the content : forget all changes ?!
2545                     // or should we assume that the content does it by itself because he throwed an exception ?!
2546                     // any other error - not specified
2547                     SetError( ERRCODE_IO_GENERAL );
2548                     return COMMIT_RESULT_FAILURE;
2549                 }
2550                 catch ( InteractiveIOException& r )
2551                 {
2552                     if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2553                         SetError( ERRCODE_IO_ACCESSDENIED );
2554                     else if ( r.Code == IOErrorCode_NOT_EXISTING )
2555                         SetError( ERRCODE_IO_NOTEXISTS );
2556                     else if ( r.Code == IOErrorCode_CANT_READ )
2557                         SetError( ERRCODE_IO_CANTREAD );
2558                     else if ( r.Code == IOErrorCode_CANT_WRITE )
2559                         SetError( ERRCODE_IO_CANTWRITE );
2560                     else
2561                         SetError( ERRCODE_IO_GENERAL );
2562 
2563                     return COMMIT_RESULT_FAILURE;
2564                 }
2565                 catch ( Exception& )
2566                 {
2567                     // how to tell the content : forget all changes ?!
2568                     // or should we assume that the content does it by itself because he throwed an exception ?!
2569                     // any other error - not specified
2570                     SetError( ERRCODE_IO_GENERAL );
2571                     return COMMIT_RESULT_FAILURE;
2572                 }
2573             }
2574             else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2575             {
2576                 // how to tell the content : forget all changes ?! Should we ?!
2577                 SetError( ERRCODE_IO_GENERAL );
2578                 return nRet;
2579             }
2580 
2581             // after successfull root commit all elements names and types are adjusted and all removed elements
2582             // are also removed from the lists
2583             UCBStorageElement_Impl* pInnerElement = m_aChildrenList.First();
2584             sal_Bool bRet = sal_True;
2585             while ( pInnerElement && bRet )
2586             {
2587                 UCBStorageElement_Impl* pNext = m_aChildrenList.Next();
2588                 if ( pInnerElement->m_bIsRemoved )
2589                 {
2590                     // is this correct use of our list class ?!
2591                     m_aChildrenList.Remove( pInnerElement );
2592                 }
2593                 else
2594                 {
2595                     pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2596                     pInnerElement->m_bIsInserted = sal_False;
2597                 }
2598 
2599                 pInnerElement = pNext;
2600             }
2601         }
2602 
2603         m_bCommited = sal_False;
2604     }
2605 
2606     return nRet;
2607 }
2608 
2609 sal_Bool UCBStorage_Impl::Revert()
2610 {
2611     UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2612     sal_Bool bRet = sal_True;
2613     while ( pElement && bRet )
2614     {
2615         pElement->m_bIsRemoved = sal_False;
2616         if ( pElement->m_bIsInserted )
2617         {
2618             m_aChildrenList.Remove( pElement );  // correct usage of list ???
2619         }
2620         else
2621         {
2622             if ( pElement->m_xStream.Is() )
2623             {
2624                 pElement->m_xStream->m_bCommited = sal_False;
2625                 pElement->m_xStream->Revert();
2626             }
2627             else if ( pElement->m_xStorage.Is() )
2628             {
2629                 pElement->m_xStorage->m_bCommited = sal_False;
2630                 pElement->m_xStorage->Revert();
2631             }
2632 
2633             pElement->m_aName = pElement->m_aOriginalName;
2634             pElement->m_bIsRemoved = sal_False;
2635         }
2636 
2637         pElement = m_aChildrenList.Next();
2638     }
2639 
2640     return bRet;
2641 }
2642 
2643 const String& UCBStorage::GetName() const
2644 {
2645     return pImp->m_aName; // pImp->m_aURL ?!
2646 }
2647 
2648 sal_Bool UCBStorage::IsRoot() const
2649 {
2650     return pImp->m_bIsRoot;
2651 }
2652 
2653 void UCBStorage::SetDirty()
2654 {
2655     pImp->m_bDirty = sal_True;
2656 }
2657 
2658 void UCBStorage::SetClass( const SvGlobalName & rClass, sal_uLong nOriginalClipFormat, const String & rUserTypeName )
2659 {
2660     pImp->m_aClassId = rClass;
2661     pImp->m_nFormat = nOriginalClipFormat;
2662     pImp->m_aUserTypeName = rUserTypeName;
2663 
2664     // in UCB storages only the content type will be stored, all other information can be reconstructed
2665     // ( see the UCBStorage_Impl::Init() method )
2666     ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2667     SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2668     pImp->m_aContentType = aDataFlavor.MimeType;
2669 }
2670 
2671 void UCBStorage::SetClassId( const ClsId& rClsId )
2672 {
2673     pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId );
2674     if ( pImp->m_aClassId == SvGlobalName() )
2675         return;
2676 
2677     // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2678     // stored in one the substreams
2679     // UCB storages store the content type information as content type in the manifest file and so this information must be
2680     // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2681     // the content type
2682     pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2683     if ( pImp->m_nFormat )
2684     {
2685         ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2686         SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2687         pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2688         pImp->m_aContentType = aDataFlavor.MimeType;
2689     }
2690 }
2691 
2692 const ClsId& UCBStorage::GetClassId() const
2693 {
2694     return ( const ClsId& ) pImp->m_aClassId.GetCLSID();
2695 }
2696 
2697 void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, sal_uLong /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ )
2698 {
2699     // ???
2700 }
2701 
2702 sal_Bool UCBStorage::ShouldConvert()
2703 {
2704     // ???
2705     return sal_False;
2706 }
2707 
2708 SvGlobalName UCBStorage::GetClassName()
2709 {
2710     return  pImp->m_aClassId;
2711 }
2712 
2713 sal_uLong UCBStorage::GetFormat()
2714 {
2715     return pImp->m_nFormat;
2716 }
2717 
2718 String UCBStorage::GetUserName()
2719 {
2720     DBG_ERROR("UserName is not implemented in UCB storages!" );
2721     return pImp->m_aUserTypeName;
2722 }
2723 
2724 void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2725 {
2726     // put information in childrenlist into StorageInfoList
2727     UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2728     while ( pElement )
2729     {
2730         if ( !pElement->m_bIsRemoved )
2731         {
2732             // problem: what about the size of a substorage ?!
2733             sal_uLong nSize = pElement->m_nSize;
2734             if ( pElement->m_xStream.Is() )
2735                 nSize = pElement->m_xStream->GetSize();
2736             SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2737             pList->Append( aInfo );
2738         }
2739 
2740         pElement = pImp->m_aChildrenList.Next();
2741     }
2742 }
2743 
2744 sal_Bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const String& rNew ) const
2745 {
2746     // insert stream or storage into the list or stream of the destination storage
2747     // not into the content, this will be done on commit !
2748     // be aware of name changes !
2749     if ( !rElement.m_bIsStorage )
2750     {
2751         // copy the streams data
2752         // the destination stream must not be open
2753         BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2754         BaseStorageStream* pStream = NULL;
2755         sal_Bool bDeleteStream = sal_False;
2756 
2757         // if stream is already open, it is allowed to copy it, so be aware of this
2758         if ( rElement.m_xStream.Is() )
2759             pStream = rElement.m_xStream->m_pAntiImpl;
2760         if ( !pStream )
2761         {
2762             pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect );
2763             bDeleteStream = sal_True;
2764         }
2765 
2766         pStream->CopyTo( pOtherStream );
2767         SetError( pStream->GetError() );
2768         if( pOtherStream->GetError() )
2769             pDest->SetError( pOtherStream->GetError() );
2770         else
2771             pOtherStream->Commit();
2772 
2773         if ( bDeleteStream )
2774             delete pStream;
2775         delete pOtherStream;
2776     }
2777     else
2778     {
2779         // copy the storage content
2780         // the destination storage must not be open
2781         BaseStorage* pStorage = NULL;
2782 
2783         // if stream is already open, it is allowed to copy it, so be aware of this
2784         sal_Bool bDeleteStorage = sal_False;
2785         if ( rElement.m_xStorage.Is() )
2786             pStorage = rElement.m_xStorage->m_pAntiImpl;
2787         if ( !pStorage )
2788         {
2789             pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2790             bDeleteStorage = sal_True;
2791         }
2792 
2793         UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
2794         UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );
2795 
2796         sal_Bool bOpenUCBStorage = pUCBDest && pUCBCopy;
2797         BaseStorage* pOtherStorage = bOpenUCBStorage ?
2798                 pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) :
2799                 pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2800 
2801         // For UCB storages, the class id and the format id may differ,
2802         // do passing the class id is not sufficient.
2803         if( bOpenUCBStorage )
2804             pOtherStorage->SetClass( pStorage->GetClassName(),
2805                                      pStorage->GetFormat(),
2806                                      pUCBCopy->pImp->m_aUserTypeName );
2807         else
2808             pOtherStorage->SetClassId( pStorage->GetClassId() );
2809         pStorage->CopyTo( pOtherStorage );
2810         SetError( pStorage->GetError() );
2811         if( pOtherStorage->GetError() )
2812             pDest->SetError( pOtherStorage->GetError() );
2813         else
2814             pOtherStorage->Commit();
2815 
2816         if ( bDeleteStorage )
2817             delete pStorage;
2818         delete pOtherStorage;
2819     }
2820 
2821     return sal_Bool( Good() && pDest->Good() );
2822 }
2823 
2824 UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const String& rName ) const
2825 {
2826     DBG_ASSERT( rName.Len(), "Name is empty!" );
2827     UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2828     while ( pElement )
2829     {
2830         if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2831             break;
2832         pElement = pImp->m_aChildrenList.Next();
2833     }
2834 
2835     return pElement;
2836 }
2837 
2838 sal_Bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2839 {
2840     DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
2841     if ( pDestStg == ((BaseStorage*)this) )
2842         return sal_False;
2843 
2844     // perhaps it's also a problem if one storage is a parent of the other ?!
2845     // or if not: could be optimized ?!
2846 
2847     // For UCB storages, the class id and the format id may differ,
2848     // do passing the class id is not sufficient.
2849     if( pDestStg->ISA( UCBStorage ) )
2850         pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2851                             pImp->m_aUserTypeName );
2852     else
2853         pDestStg->SetClassId( GetClassId() );
2854     pDestStg->SetDirty();
2855 
2856     sal_Bool bRet = sal_True;
2857     UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2858     while ( pElement && bRet )
2859     {
2860         if ( !pElement->m_bIsRemoved )
2861             bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2862         pElement = pImp->m_aChildrenList.Next();
2863     }
2864 
2865     if( !bRet )
2866         SetError( pDestStg->GetError() );
2867     return sal_Bool( Good() && pDestStg->Good() );
2868 }
2869 
2870 sal_Bool UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew )
2871 {
2872     if( !rElemName.Len() )
2873         return sal_False;
2874 
2875     if ( pDest == ((BaseStorage*) this) )
2876     {
2877         // can't double an element
2878         return sal_False;
2879     }
2880     else
2881     {
2882         // for copying no optimization is usefull, because in every case the stream data must be copied
2883             UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2884         if ( pElement )
2885             return CopyStorageElement_Impl( *pElement, pDest, rNew );
2886         else
2887         {
2888             SetError( SVSTREAM_FILE_NOT_FOUND );
2889             return sal_False;
2890         }
2891     }
2892 }
2893 
2894 sal_Bool UCBStorage::Commit()
2895 {
2896     // mark this storage for sending it on root commit
2897     pImp->m_bCommited = sal_True;
2898     if ( pImp->m_bIsRoot )
2899         // the root storage coordinates commiting by sending a Commit command to its content
2900         return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2901     else
2902         return sal_True;
2903 }
2904 
2905 sal_Bool UCBStorage::Revert()
2906 {
2907     return pImp->Revert();
2908 }
2909 
2910 BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
2911 {
2912     if( !rEleName.Len() )
2913         return NULL;
2914 
2915     // try to find the storage element
2916     UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2917     if ( !pElement )
2918     {
2919         // element does not exist, check if creation is allowed
2920         if( ( nMode & STREAM_NOCREATE ) )
2921         {
2922             SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2923             String aName( pImp->m_aURL );
2924             aName += '/';
2925             aName += rEleName;
2926             UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2927             pStream->SetError( GetError() );
2928             pStream->pImp->m_aName = rEleName;
2929             return pStream;
2930         }
2931         else
2932         {
2933             // create a new UCBStorageElement and insert it into the list
2934             pElement = new UCBStorageElement_Impl( rEleName );
2935             pElement->m_bIsInserted = sal_True;
2936             pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
2937         }
2938     }
2939 
2940     if ( pElement && !pElement->m_bIsFolder )
2941     {
2942         // check if stream is already created
2943         if ( pElement->m_xStream.Is() )
2944         {
2945             // stream has already been created; if it has no external reference, it may be opened another time
2946             if ( pElement->m_xStream->m_pAntiImpl )
2947             {
2948                 DBG_ERROR("Stream is already open!" );
2949                 SetError( SVSTREAM_ACCESS_DENIED );  // ???
2950                 return NULL;
2951             }
2952             else
2953             {
2954                 // check if stream is opened with the same keyword as before
2955                 // if not, generate a new stream because it could be encrypted vs. decrypted!
2956                 ByteString aKey;
2957                 if ( pKey )
2958                     aKey = *pKey;
2959                 if ( pElement->m_xStream->m_aKey == aKey )
2960                 {
2961                     pElement->m_xStream->PrepareCachedForReopen( nMode );
2962 
2963     //              DBG_ASSERT( bDirect == pElement->m_xStream->m_bDirect, "Wrong DirectMode!" );
2964                     return new UCBStorageStream( pElement->m_xStream );
2965                 }
2966             }
2967         }
2968 
2969         // stream is opened the first time
2970         pImp->OpenStream( pElement, nMode, bDirect, pKey );
2971 
2972         // if name has been changed before creating the stream: set name!
2973         pElement->m_xStream->m_aName = rEleName;
2974         return new UCBStorageStream( pElement->m_xStream );
2975     }
2976 
2977     return NULL;
2978 }
2979 
2980 UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
2981 {
2982     String aName( m_aURL );
2983     aName += '/';
2984     aName += pElement->m_aOriginalName;
2985     pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler );
2986     return pElement->m_xStream;
2987 }
2988 
2989 BaseStorage* UCBStorage::OpenUCBStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
2990 {
2991     if( !rEleName.Len() )
2992         return NULL;
2993 
2994     return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
2995 }
2996 
2997 BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
2998 {
2999     if( !rEleName.Len() )
3000         return NULL;
3001 
3002     return OpenStorage_Impl( rEleName, nMode, bDirect, sal_False );
3003 }
3004 
3005 BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
3006 {
3007     if( !rEleName.Len() )
3008         return NULL;
3009 
3010     return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
3011 }
3012 
3013 BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, sal_Bool bDirect, sal_Bool bForceUCBStorage )
3014 {
3015     // try to find the storage element
3016     UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3017     if ( !pElement )
3018     {
3019         // element does not exist, check if creation is allowed
3020         if( ( nMode & STREAM_NOCREATE ) )
3021         {
3022             SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3023             String aName( pImp->m_aURL );
3024             aName += '/';
3025             aName += rEleName;  //  ???
3026             UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3027             pStorage->pImp->m_bIsRoot = sal_False;
3028             pStorage->pImp->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3029             pStorage->SetError( GetError() );
3030             return pStorage;
3031         }
3032 
3033         // create a new UCBStorageElement and insert it into the list
3034         // problem: perhaps an OLEStorage should be created ?!
3035         // Because nothing is known about the element that should be created, an external parameter is needed !
3036         pElement = new UCBStorageElement_Impl( rEleName );
3037         pElement->m_bIsInserted = sal_True;
3038         pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
3039     }
3040 
3041     if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
3042     {
3043         // create OLE storages on a stream ( see ctor of SotStorage )
3044         // Such a storage will be created on a UCBStorageStream; it will write into the stream
3045         // if it is opened in direct mode or when it is committed. In this case the stream will be
3046         // modified and then it MUST be treated as commited.
3047         if ( !pElement->m_xStream.Is() )
3048         {
3049             BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
3050             UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr );
3051             if ( !pStream )
3052             {
3053                 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3054                 return NULL;
3055             }
3056 
3057             pElement->m_xStream = pStream->pImp;
3058             delete pStream;
3059         }
3060 
3061         pElement->m_xStream->PrepareCachedForReopen( nMode );
3062         pElement->m_xStream->Init();
3063 
3064         pElement->m_bIsStorage = sal_True;
3065         return pElement->m_xStream->CreateStorage();  // can only be created in transacted mode
3066     }
3067     else if ( pElement->m_xStorage.Is() )
3068     {
3069         // storage has already been opened; if it has no external reference, it may be opened another time
3070         if ( pElement->m_xStorage->m_pAntiImpl )
3071         {
3072             DBG_ERROR("Storage is already open!" );
3073             SetError( SVSTREAM_ACCESS_DENIED );  // ???
3074         }
3075         else
3076         {
3077             sal_Bool bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0);
3078             if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 ))
3079             {
3080                 String aName( pImp->m_aURL );
3081                 aName += '/';
3082                 aName += pElement->m_aOriginalName;
3083                 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3084                 pElement->m_xStorage = pStorage->pImp;
3085                 return pStorage;
3086             }
3087             else
3088             {
3089 //                    DBG_ASSERT( bDirect == pElement->m_xStorage->m_bDirect, "Wrong DirectMode!" );
3090                 return new UCBStorage( pElement->m_xStorage );
3091             }
3092         }
3093     }
3094     else if ( !pElement->m_xStream.Is() )
3095     {
3096         // storage is opened the first time
3097         sal_Bool bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 );
3098         if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
3099         {
3100             // make sure that the root storage object has been created before substorages will be created
3101             INetURLObject aFolderObj( pImp->m_aURL );
3102             String aName = aFolderObj.GetName();
3103             aFolderObj.removeSegment();
3104 
3105             Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >() );
3106             pImp->m_pContent = new Content;
3107             sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
3108             if ( !bRet )
3109             {
3110                 SetError( SVSTREAM_CANNOT_MAKE );
3111                 return NULL;
3112             }
3113         }
3114 
3115         UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
3116         if ( pStor )
3117         {
3118             if ( pElement->m_bIsInserted )
3119                 pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3120 
3121             return new UCBStorage( pStor );
3122         }
3123     }
3124 
3125     return NULL;
3126 }
3127 
3128 UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect )
3129 {
3130     UCBStorage_Impl* pRet = NULL;
3131     String aName( m_aURL );
3132     aName += '/';
3133     aName += pElement->m_aOriginalName;  //  ???
3134 
3135     pElement->m_bIsStorage = pElement->m_bIsFolder = sal_True;
3136 
3137     if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
3138     {
3139         Content aNewFolder;
3140         sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
3141         if ( bRet )
3142             pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
3143     }
3144     else
3145     {
3146         pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
3147     }
3148 
3149     if ( pRet )
3150     {
3151         pRet->m_bIsLinked = m_bIsLinked;
3152         pRet->m_bIsRoot = sal_False;
3153 
3154         // if name has been changed before creating the stream: set name!
3155         pRet->m_aName = pElement->m_aOriginalName;
3156         pElement->m_xStorage = pRet;
3157     }
3158 
3159     if ( pRet )
3160         pRet->Init();
3161 
3162     return pRet;
3163 }
3164 
3165 sal_Bool UCBStorage::IsStorage( const String& rEleName ) const
3166 {
3167     if( !rEleName.Len() )
3168         return sal_False;
3169 
3170     const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3171     return ( pElement && pElement->m_bIsStorage );
3172 }
3173 
3174 sal_Bool UCBStorage::IsStream( const String& rEleName ) const
3175 {
3176     if( !rEleName.Len() )
3177         return sal_False;
3178 
3179     const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3180     return ( pElement && !pElement->m_bIsStorage );
3181 }
3182 
3183 sal_Bool UCBStorage::IsContained( const String & rEleName ) const
3184 {
3185     if( !rEleName.Len() )
3186         return sal_False;
3187     const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3188     return ( pElement != NULL );
3189 }
3190 
3191 sal_Bool UCBStorage::Remove( const String& rEleName )
3192 {
3193     if( !rEleName.Len() )
3194         return sal_False;
3195 
3196     UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3197     if ( pElement )
3198     {
3199         pElement->m_bIsRemoved = sal_True;
3200     }
3201     else
3202         SetError( SVSTREAM_FILE_NOT_FOUND );
3203 
3204     return ( pElement != NULL );
3205 }
3206 
3207 sal_Bool UCBStorage::Rename( const String& rEleName, const String& rNewName )
3208 {
3209     if( !rEleName.Len()|| !rNewName.Len() )
3210         return sal_False;
3211 
3212     UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
3213     if ( pAlreadyExisting )
3214     {
3215         SetError( SVSTREAM_ACCESS_DENIED );
3216         return sal_False;                       // can't change to a name that is already used
3217     }
3218 
3219     UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3220     if ( pElement )
3221     {
3222         pElement->m_aName = rNewName;
3223     }
3224     else
3225         SetError( SVSTREAM_FILE_NOT_FOUND );
3226 
3227     return pElement != NULL;
3228 }
3229 
3230 sal_Bool UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName )
3231 {
3232     if( !rEleName.Len() || !rNewName.Len() )
3233         return sal_False;
3234 
3235     if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
3236     {
3237         return Rename( rEleName, rNewName );
3238     }
3239     else
3240     {
3241 /*
3242         if ( PTR_CAST( UCBStorage, pNewSt ) )
3243         {
3244             // because the element is moved, not copied, a special optimization is possible :
3245             // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3246             // clear original name/type of the new element
3247             // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3248             // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3249                 // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3250             // belong to the new content
3251             // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3252             // stream of the destination object
3253             // Not implemented at the moment ( risky?! ), perhaps later
3254         }
3255 */
3256         // MoveTo is done by first copying to the new destination and then removing the old element
3257         sal_Bool bRet = CopyTo( rEleName, pNewSt, rNewName );
3258         if ( bRet )
3259             bRet = Remove( rEleName );
3260         return bRet;
3261     }
3262 }
3263 
3264 sal_Bool UCBStorage::ValidateFAT()
3265 {
3266     // ???
3267     return sal_True;
3268 }
3269 
3270 sal_Bool UCBStorage::Validate( sal_Bool  bWrite ) const
3271 {
3272     // ???
3273     return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
3274 }
3275 
3276 sal_Bool UCBStorage::ValidateMode( StreamMode m ) const
3277 {
3278     // ???
3279     if( m == ( STREAM_READ | STREAM_TRUNC ) )  // from stg.cxx
3280         return sal_True;
3281     sal_uInt16 nCurMode = 0xFFFF;
3282     if( ( m & 3 ) == STREAM_READ )
3283     {
3284         // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3285         if( ( ( m & STREAM_SHARE_DENYWRITE )
3286            && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
3287          || ( ( m & STREAM_SHARE_DENYALL )
3288            && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
3289             return sal_True;
3290     }
3291     else
3292     {
3293         // only SHARE_DENYALL allowed
3294         // storages open in r/o mode are OK, since only
3295         // the commit may fail
3296         if( ( m & STREAM_SHARE_DENYALL )
3297          && ( nCurMode & STREAM_SHARE_DENYALL ) )
3298             return sal_True;
3299     }
3300 
3301     return sal_True;
3302 }
3303 
3304 const SvStream* UCBStorage::GetSvStream() const
3305 {
3306     // this would cause a complete download of the file
3307     // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3308     return pImp->m_pSource;
3309 }
3310 
3311 sal_Bool UCBStorage::Equals( const BaseStorage& rStorage ) const
3312 {
3313     // ???
3314     return ((BaseStorage*)this) == &rStorage;
3315 }
3316 
3317 sal_Bool UCBStorage::IsStorageFile( const String& rFileName )
3318 {
3319     String aFileURL = rFileName;
3320     INetURLObject aObj( aFileURL );
3321     if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
3322     {
3323         ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFileName, aFileURL );
3324         aObj.SetURL( aFileURL );
3325         aFileURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3326     }
3327 
3328     SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_STD_READ );
3329     sal_Bool bRet = UCBStorage::IsStorageFile( pStm );
3330     delete pStm;
3331     return bRet;
3332 }
3333 
3334 sal_Bool UCBStorage::IsStorageFile( SvStream* pFile )
3335 {
3336     if ( !pFile )
3337         return sal_False;
3338 
3339     sal_uLong nPos = pFile->Tell();
3340     pFile->Seek( STREAM_SEEK_TO_END );
3341     if ( pFile->Tell() < 4 )
3342         return sal_False;
3343 
3344     pFile->Seek(0);
3345     sal_uInt32 nBytes;
3346     *pFile >> nBytes;
3347 
3348     // search for the magic bytes
3349     sal_Bool bRet = ( nBytes == 0x04034b50 );
3350     if ( !bRet )
3351     {
3352         // disk spanned file have an additional header in front of the usual one
3353         bRet = ( nBytes == 0x08074b50 );
3354         if ( bRet )
3355         {
3356             *pFile >> nBytes;
3357             bRet = ( nBytes == 0x04034b50 );
3358         }
3359     }
3360 
3361     pFile->Seek( nPos );
3362     return bRet;
3363 }
3364 
3365 sal_Bool UCBStorage::IsDiskSpannedFile( SvStream* pFile )
3366 {
3367     if ( !pFile )
3368         return sal_False;
3369 
3370     sal_uLong nPos = pFile->Tell();
3371     pFile->Seek( STREAM_SEEK_TO_END );
3372     if ( !pFile->Tell() )
3373         return sal_False;
3374 
3375     pFile->Seek(0);
3376     sal_uInt32 nBytes;
3377     *pFile >> nBytes;
3378 
3379     // disk spanned file have an additional header in front of the usual one
3380     sal_Bool bRet = ( nBytes == 0x08074b50 );
3381     if ( bRet )
3382     {
3383         *pFile >> nBytes;
3384         bRet = ( nBytes == 0x04034b50 );
3385     }
3386 
3387     pFile->Seek( nPos );
3388     return bRet;
3389 }
3390 
3391 String UCBStorage::GetLinkedFile( SvStream &rStream )
3392 {
3393     String aString;
3394     sal_uLong nPos = rStream.Tell();
3395     rStream.Seek( STREAM_SEEK_TO_END );
3396     if ( !rStream.Tell() )
3397         return aString;
3398 
3399     rStream.Seek(0);
3400     sal_uInt32 nBytes;
3401     rStream >> nBytes;
3402     if( nBytes == 0x04034b50 )
3403     {
3404         ByteString aTmp;
3405         rStream.ReadByteString( aTmp );
3406         if ( aTmp.CompareTo( "ContentURL=", 11 ) == COMPARE_EQUAL )
3407         {
3408             aTmp.Erase( 0, 11 );
3409             aString = String( aTmp, RTL_TEXTENCODING_UTF8 );
3410         }
3411     }
3412 
3413     rStream.Seek( nPos );
3414     return aString;
3415 }
3416 
3417 String UCBStorage::CreateLinkFile( const String& rName )
3418 {
3419     // create a stream to write the link file - use a temp file, because it may be no file content
3420     INetURLObject aFolderObj( rName );
3421     String aName = aFolderObj.GetName();
3422     aFolderObj.removeSegment();
3423     String aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) );
3424     ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL );
3425 
3426     // get the stream from the temp file
3427     SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC );
3428 
3429     // write header
3430     *pStream << ( sal_uInt32 ) 0x04034b50;
3431 
3432     // assemble a new folder name in the destination folder
3433     INetURLObject aObj( rName );
3434     String aTmpName = aObj.GetName();
3435     String aTitle = String::CreateFromAscii( "content." );
3436     aTitle += aTmpName;
3437 
3438     // create a folder and store its URL
3439     Content aFolder( aFolderURL, Reference < XCommandEnvironment >() );
3440     Content aNewFolder;
3441     sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
3442     if ( !bRet )
3443     {
3444         aFolderObj.insertName( aTitle );
3445         if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3446         {
3447             // Hack, because already existing files give the same CommandAbortedException as any other error !
3448             // append a number until the name can be used for a new folder
3449             aTitle += '.';
3450             for ( sal_Int32 i=0; !bRet; i++ )
3451             {
3452                 String aTmp( aTitle );
3453                 aTmp += String::CreateFromInt32( i );
3454                 bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder );
3455                 if ( bRet )
3456                     aTitle = aTmp;
3457                 else
3458                 {
3459                     aFolderObj.SetName( aTmp );
3460                     if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3461                         // Hack, because already existing files give the same CommandAbortedException as any other error !
3462                         break;
3463                 }
3464             }
3465         }
3466     }
3467 
3468     if ( bRet )
3469     {
3470         // get the URL
3471         aObj.SetName( aTitle );
3472         String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3473 
3474         // store it as key/value pair
3475         String aLink = String::CreateFromAscii("ContentURL=");
3476         aLink += aURL;
3477         pStream->WriteByteString( aLink, RTL_TEXTENCODING_UTF8 );
3478         pStream->Flush();
3479 
3480         // move the stream to its desired location
3481         Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
3482         DELETEZ( pTempFile );
3483         aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE );
3484         return aURL;
3485     }
3486 
3487     pTempFile->EnableKillingFile( sal_True );
3488     delete pTempFile;
3489     return String();
3490 }
3491 
3492 sal_Bool UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
3493 {
3494     if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
3495         return sal_False;
3496 
3497     if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
3498     {
3499         ::rtl::OUString aTmp;
3500         rValue >>= aTmp;
3501         pImp->m_aContentType = aTmp;
3502     }
3503 
3504     try
3505     {
3506         if ( pImp->GetContent() )
3507         {
3508             pImp->m_pContent->setPropertyValue( rName, rValue );
3509             return sal_True;
3510         }
3511     }
3512     catch ( Exception& )
3513     {
3514     }
3515 
3516     return sal_False;
3517 }
3518 
3519 sal_Bool UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
3520 {
3521     try
3522     {
3523         if ( pImp->GetContent() )
3524         {
3525             rValue = pImp->m_pContent->getPropertyValue( rName );
3526             return sal_True;
3527         }
3528     }
3529     catch ( Exception& )
3530     {
3531     }
3532 
3533     return sal_False;
3534 }
3535 
3536 sal_Bool UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
3537 {
3538     UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName );
3539     if ( !pEle )
3540         return sal_False;
3541 
3542     if ( !pEle->m_bIsFolder )
3543     {
3544         if ( !pEle->m_xStream.Is() )
3545             pImp->OpenStream( pEle, pImp->m_nMode, pImp->m_bDirect );
3546         if ( pEle->m_xStream->m_nError )
3547         {
3548             pEle->m_xStream.Clear();
3549             return sal_False;
3550         }
3551 
3552         try
3553         {
3554             if ( pEle->m_xStream->m_pContent )
3555             {
3556                 rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName );
3557                 return sal_True;
3558             }
3559         }
3560         catch ( Exception& )
3561         {
3562         }
3563     }
3564     else
3565     {
3566         if ( !pEle->m_xStorage.Is() )
3567             pImp->OpenStorage( pEle, pImp->m_nMode, pImp->m_bDirect );
3568         if ( pEle->m_xStorage->m_nError )
3569         {
3570             pEle->m_xStorage.Clear();
3571             return sal_False;
3572         }
3573 
3574         try
3575         {
3576             if ( pEle->m_xStorage->GetContent() )
3577             {
3578                 rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName );
3579                 return sal_True;
3580             }
3581         }
3582         catch ( Exception& )
3583         {
3584         }
3585     }
3586 
3587     return sal_False;
3588 }
3589 
3590 UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList()
3591 {
3592     if ( !pImp->m_pUNOStorageHolderList )
3593         pImp->m_pUNOStorageHolderList = new UNOStorageHolderList;
3594 
3595     return pImp->m_pUNOStorageHolderList;
3596 }
3597 
3598