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