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