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