update dev300-m58
[ooovba.git] / sot / source / sdstor / ucbstorage.cxx
blob8b6b902e3843ff6eb6a68db90fa511925d5a90fa
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ucbstorage.cxx,v $
10 * $Revision: 1.97 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sot.hxx"
33 #include <com/sun/star/io/NotConnectedException.hpp>
34 #include <com/sun/star/io/BufferSizeExceededException.hpp>
35 #include <com/sun/star/uno/RuntimeException.hpp>
36 #include <com/sun/star/lang/IllegalArgumentException.hpp>
37 #include <ucbhelper/content.hxx>
38 #include <com/sun/star/uno/Reference.h>
39 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
40 #include <unotools/tempfile.hxx>
41 #include <unotools/ucbstreamhelper.hxx>
42 #include <com/sun/star/io/XInputStream.hpp>
43 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
44 #include <com/sun/star/ucb/ResultSetException.hpp>
45 #include <com/sun/star/uno/Sequence.h>
46 #ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HDL_
47 #include <com/sun/star/sdbc/XResultSet.hdl>
48 #endif
49 #include <com/sun/star/ucb/XContentAccess.hpp>
50 #include <com/sun/star/sdbc/XRow.hpp>
51 #include <com/sun/star/ucb/CommandAbortedException.hpp>
52 #include <com/sun/star/datatransfer/DataFlavor.hpp>
53 #include <com/sun/star/ucb/XContentCreator.hpp>
54 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
55 #include <com/sun/star/beans/Property.hpp>
56 #include <com/sun/star/packages/manifest/XManifestWriter.hpp>
57 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
58 #ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_
59 #include <com/sun/star/ucb/InteractiveIOException.hpp>
60 #endif
62 #include <rtl/digest.h>
63 #include <tools/ref.hxx>
64 #include <tools/debug.hxx>
65 #include <unotools/streamhelper.hxx>
66 #include <unotools/streamwrap.hxx>
67 #include <unotools/ucbhelper.hxx>
68 #include <unotools/localfilehelper.hxx>
69 #include <tools/list.hxx>
70 #include <tools/urlobj.hxx>
71 #include <unotools/streamwrap.hxx>
72 #include <comphelper/processfactory.hxx>
73 #include <cppuhelper/implbase2.hxx>
74 #include <ucbhelper/commandenvironment.hxx>
76 #include "stg.hxx"
77 #include "storinfo.hxx"
78 #include <sot/storage.hxx>
79 #include <sot/exchange.hxx>
80 #include <sot/formats.hxx>
81 #include "clsids.hxx"
83 #include "unostorageholder.hxx"
85 using namespace ::com::sun::star::lang;
86 using namespace ::com::sun::star::beans;
87 using namespace ::com::sun::star::uno;
88 using namespace ::com::sun::star::ucb;
89 using namespace ::com::sun::star::io;
90 using namespace ::com::sun::star::sdbc;
91 using namespace ::ucbhelper;
93 #if OSL_DEBUG_LEVEL > 1
94 #include <stdio.h>
95 static int nOpenFiles=0;
96 static int nOpenStreams=0;
97 #endif
99 typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base;
100 class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
102 protected:
103 ::osl::Mutex m_aMutex;
104 String m_aURL;
105 SvStream* m_pSvStream;
107 public:
108 FileStreamWrapper_Impl( const String& rName );
109 virtual ~FileStreamWrapper_Impl();
111 //DECLARE_UNO3_AGG_DEFAULTS( FileStreamWrapper_Impl, FileInputStreamWrapper_Base);
113 virtual void SAL_CALL seek( sal_Int64 _nLocation ) throw ( IllegalArgumentException, IOException, RuntimeException);
114 virtual sal_Int64 SAL_CALL getPosition( ) throw ( IOException, RuntimeException);
115 virtual sal_Int64 SAL_CALL getLength( ) throw ( IOException, RuntimeException);
116 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
117 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
118 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException);
119 virtual sal_Int32 SAL_CALL available() throw( NotConnectedException, RuntimeException );
120 virtual void SAL_CALL closeInput() throw( NotConnectedException, RuntimeException );
122 protected:
123 void checkConnected();
124 void checkError();
127 //------------------------------------------------------------------
128 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String& rName )
129 : m_aURL( rName )
130 , m_pSvStream(0)
132 // if no URL is provided the stream is empty
135 //------------------------------------------------------------------
136 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
138 if ( m_pSvStream )
140 delete m_pSvStream;
141 #if OSL_DEBUG_LEVEL > 1
142 --nOpenFiles;
143 #endif
146 if ( m_aURL.Len() )
147 ::utl::UCBContentHelper::Kill( m_aURL );
150 //------------------------------------------------------------------------------
151 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
152 throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
154 if ( !m_aURL.Len() )
156 aData.realloc( 0 );
157 return 0;
160 checkConnected();
162 if (nBytesToRead < 0)
163 throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));
165 ::osl::MutexGuard aGuard( m_aMutex );
167 aData.realloc(nBytesToRead);
169 sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
170 checkError();
172 // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
173 if (nRead < (sal_uInt32)nBytesToRead)
174 aData.realloc( nRead );
176 return nRead;
179 //------------------------------------------------------------------------------
180 sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
182 if ( !m_aURL.Len() )
184 aData.realloc( 0 );
185 return 0;
188 checkError();
190 if (nMaxBytesToRead < 0)
191 throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));
193 if (m_pSvStream->IsEof())
195 aData.realloc(0);
196 return 0;
198 else
199 return readBytes(aData, nMaxBytesToRead);
202 //------------------------------------------------------------------------------
203 void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
205 if ( !m_aURL.Len() )
206 return;
208 ::osl::MutexGuard aGuard( m_aMutex );
209 checkError();
211 #ifdef DBG_UTIL
212 sal_uInt32 nCurrentPos = m_pSvStream->Tell();
213 #endif
215 m_pSvStream->SeekRel(nBytesToSkip);
216 checkError();
218 #ifdef DBG_UTIL
219 nCurrentPos = m_pSvStream->Tell();
220 #endif
223 //------------------------------------------------------------------------------
224 sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException )
226 if ( !m_aURL.Len() )
227 return 0;
229 ::osl::MutexGuard aGuard( m_aMutex );
230 checkConnected();
232 sal_uInt32 nPos = m_pSvStream->Tell();
233 checkError();
235 m_pSvStream->Seek(STREAM_SEEK_TO_END);
236 checkError();
238 sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
239 m_pSvStream->Seek(nPos);
240 checkError();
242 return nAvailable;
245 //------------------------------------------------------------------------------
246 void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException )
248 if ( !m_aURL.Len() )
249 return;
251 ::osl::MutexGuard aGuard( m_aMutex );
252 checkConnected();
253 DELETEZ( m_pSvStream );
254 #if OSL_DEBUG_LEVEL > 1
255 --nOpenFiles;
256 #endif
257 ::utl::UCBContentHelper::Kill( m_aURL );
258 m_aURL.Erase();
261 //------------------------------------------------------------------------------
262 void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
264 if ( !m_aURL.Len() )
265 return;
267 ::osl::MutexGuard aGuard( m_aMutex );
268 checkConnected();
270 m_pSvStream->Seek((sal_uInt32)_nLocation);
271 checkError();
274 //------------------------------------------------------------------------------
275 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( ) throw (IOException, RuntimeException)
277 if ( !m_aURL.Len() )
278 return 0;
280 ::osl::MutexGuard aGuard( m_aMutex );
281 checkConnected();
283 sal_uInt32 nPos = m_pSvStream->Tell();
284 checkError();
285 return (sal_Int64)nPos;
288 //------------------------------------------------------------------------------
289 sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( ) throw (IOException, RuntimeException)
291 if ( !m_aURL.Len() )
292 return 0;
294 ::osl::MutexGuard aGuard( m_aMutex );
295 checkConnected();
297 sal_uInt32 nCurrentPos = m_pSvStream->Tell();
298 checkError();
300 m_pSvStream->Seek(STREAM_SEEK_TO_END);
301 sal_uInt32 nEndPos = m_pSvStream->Tell();
302 m_pSvStream->Seek(nCurrentPos);
304 checkError();
306 return (sal_Int64)nEndPos;
309 //------------------------------------------------------------------------------
310 void FileStreamWrapper_Impl::checkConnected()
312 if ( !m_aURL.Len() )
313 throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
314 if ( !m_pSvStream )
316 m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ );
317 #if OSL_DEBUG_LEVEL > 1
318 ++nOpenFiles;
319 #endif
323 //------------------------------------------------------------------------------
324 void FileStreamWrapper_Impl::checkError()
326 checkConnected();
328 if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
329 // TODO: really evaluate the error
330 throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
333 TYPEINIT1( UCBStorageStream, BaseStorageStream );
334 TYPEINIT1( UCBStorage, BaseStorage );
336 #define COMMIT_RESULT_FAILURE 0
337 #define COMMIT_RESULT_NOTHING_TO_DO 1
338 #define COMMIT_RESULT_SUCCESS 2
340 #define min( x, y ) (( x < y ) ? x : y)
341 #define max( x, y ) (( x > y ) ? x : y)
343 sal_Int32 GetFormatId_Impl( SvGlobalName aName )
345 // if ( aName == SvGlobalName( SO3_SW_CLASSID_8 ) )
346 // return SOT_FORMATSTR_ID_STARWRITER_8;
347 // if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_8 ) )
348 // return SOT_FORMATSTR_ID_STARWRITERWEB_8;
349 // if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_8 ) )
350 // return SOT_FORMATSTR_ID_STARWRITERGLOB_8;
351 // if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_8 ) )
352 // return SOT_FORMATSTR_ID_STARDRAW_8;
353 // if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_8 ) )
354 // return SOT_FORMATSTR_ID_STARIMPRESS_8;
355 // if ( aName == SvGlobalName( SO3_SC_CLASSID_8 ) )
356 // return SOT_FORMATSTR_ID_STARCALC_8;
357 // if ( aName == SvGlobalName( SO3_SCH_CLASSID_8 ) )
358 // return SOT_FORMATSTR_ID_STARCHART_8;
359 // if ( aName == SvGlobalName( SO3_SM_CLASSID_8 ) )
360 // return SOT_FORMATSTR_ID_STARMATH_8;
361 if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
362 return SOT_FORMATSTR_ID_STARWRITER_60;
363 if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
364 return SOT_FORMATSTR_ID_STARWRITERWEB_60;
365 if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
366 return SOT_FORMATSTR_ID_STARWRITERGLOB_60;
367 if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
368 return SOT_FORMATSTR_ID_STARDRAW_60;
369 if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
370 return SOT_FORMATSTR_ID_STARIMPRESS_60;
371 if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
372 return SOT_FORMATSTR_ID_STARCALC_60;
373 if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
374 return SOT_FORMATSTR_ID_STARCHART_60;
375 if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
376 return SOT_FORMATSTR_ID_STARMATH_60;
377 if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
378 aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
379 aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
380 aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
381 // allowed, but not supported
382 return 0;
383 else
385 DBG_ERROR( "Unknown UCB storage format!" );
386 return 0;
391 SvGlobalName GetClassId_Impl( sal_Int32 nFormat )
393 switch ( nFormat )
395 case SOT_FORMATSTR_ID_STARWRITER_8 :
396 case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE :
397 return SvGlobalName( SO3_SW_CLASSID_60 );
398 case SOT_FORMATSTR_ID_STARWRITERWEB_8 :
399 return SvGlobalName( SO3_SWWEB_CLASSID_60 );
400 case SOT_FORMATSTR_ID_STARWRITERGLOB_8 :
401 return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
402 case SOT_FORMATSTR_ID_STARDRAW_8 :
403 case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE :
404 return SvGlobalName( SO3_SDRAW_CLASSID_60 );
405 case SOT_FORMATSTR_ID_STARIMPRESS_8 :
406 case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE :
407 return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
408 case SOT_FORMATSTR_ID_STARCALC_8 :
409 case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE :
410 return SvGlobalName( SO3_SC_CLASSID_60 );
411 case SOT_FORMATSTR_ID_STARCHART_8 :
412 case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE :
413 return SvGlobalName( SO3_SCH_CLASSID_60 );
414 case SOT_FORMATSTR_ID_STARMATH_8 :
415 case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE :
416 return SvGlobalName( SO3_SM_CLASSID_60 );
417 case SOT_FORMATSTR_ID_STARWRITER_60 :
418 return SvGlobalName( SO3_SW_CLASSID_60 );
419 case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
420 return SvGlobalName( SO3_SWWEB_CLASSID_60 );
421 case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
422 return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
423 case SOT_FORMATSTR_ID_STARDRAW_60 :
424 return SvGlobalName( SO3_SDRAW_CLASSID_60 );
425 case SOT_FORMATSTR_ID_STARIMPRESS_60 :
426 return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
427 case SOT_FORMATSTR_ID_STARCALC_60 :
428 return SvGlobalName( SO3_SC_CLASSID_60 );
429 case SOT_FORMATSTR_ID_STARCHART_60 :
430 return SvGlobalName( SO3_SCH_CLASSID_60 );
431 case SOT_FORMATSTR_ID_STARMATH_60 :
432 return SvGlobalName( SO3_SM_CLASSID_60 );
433 default :
434 //DBG_ERROR( "Unknown UCB storage format!" );
435 return SvGlobalName();
439 // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
440 // class, that uses the refcounted object as impl-class.
442 enum RepresentModes {
443 nonset,
444 svstream,
445 xinputstream
448 class UCBStorageStream_Impl : public SvRefBase, public SvStream
450 ~UCBStorageStream_Impl();
451 public:
453 virtual ULONG GetData( void* pData, ULONG nSize );
454 virtual ULONG PutData( const void* pData, ULONG nSize );
455 virtual ULONG SeekPos( ULONG nPos );
456 virtual void SetSize( ULONG nSize );
457 virtual void FlushData();
458 virtual void ResetError();
460 UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists
462 String m_aOriginalName;// the original name before accessing the stream
463 String m_aName; // the actual name ( changed with a Rename command at the parent )
464 String m_aURL; // the full path name to create the content
465 String m_aContentType;
466 String m_aOriginalContentType;
467 ByteString m_aKey;
468 ::ucbhelper::Content* m_pContent; // the content that provides the data
469 Reference<XInputStream> m_rSource; // the stream covering the original data of the content
470 SvStream* m_pStream; // the stream worked on; for readonly streams it is the original stream of the content
471 // for read/write streams it's a copy into a temporary file
472 String m_aTempURL; // URL of this temporary stream
473 RepresentModes m_nRepresentMode; // should it be used as XInputStream or as SvStream
474 long m_nError;
475 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
476 BOOL m_bSourceRead; // Source still contains useful information
477 BOOL m_bModified; // only modified streams will be sent to the original content
478 BOOL m_bCommited; // sending the streams is coordinated by the root storage of the package
479 BOOL m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
480 // this means that the root storage does an autocommit when its external
481 // reference is destroyed
482 BOOL m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
484 UCBStorageStream_Impl( const String&, StreamMode, UCBStorageStream*, BOOL, const ByteString* pKey=0, BOOL bRepair = FALSE, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() );
486 void Free();
487 BOOL Init();
488 BOOL Clear();
489 sal_Int16 Commit(); // if modified and commited: transfer an XInputStream to the content
490 BOOL Revert(); // discard all changes
491 BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
492 ULONG GetSize();
494 ULONG ReadSourceWriteTemporary( ULONG aLength ); // read aLength from source and copy to temporary,
495 // no seeking is produced
496 ULONG ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
497 // no seeking is produced
498 #if 0
499 ULONG CopySourceToTemporary( ULONG aLength ); // same as ReadSourceWriteToTemporary( aLength )
500 // but the writing is done at the end of temporary
501 // pointer position is not changed
502 #endif
504 ULONG CopySourceToTemporary(); // same as ReadSourceWriteToTemporary()
505 // but the writing is done at the end of temporary
506 // pointer position is not changed
507 Reference<XInputStream> GetXInputStream(); // return XInputStream, after that
508 // this class is close to be unusable
509 // since it can not read and write
510 using SvStream::SetError;
511 void SetError( sal_uInt32 nError );
512 void PrepareCachedForReopen( StreamMode nMode );
515 SV_DECL_IMPL_REF( UCBStorageStream_Impl );
517 struct UCBStorageElement_Impl;
518 DECLARE_LIST( UCBStorageElementList_Impl, UCBStorageElement_Impl* )
520 class UCBStorage_Impl : public SvRefBase
522 ~UCBStorage_Impl();
523 public:
524 UCBStorage* m_pAntiImpl; // only valid if external references exists
526 String m_aOriginalName;// the original name before accessing the storage
527 String m_aName; // the actual name ( changed with a Rename command at the parent )
528 String m_aURL; // the full path name to create the content
529 String m_aContentType;
530 String m_aOriginalContentType;
531 ::ucbhelper::Content* m_pContent; // the content that provides the storage elements
532 ::utl::TempFile* m_pTempFile; // temporary file, only for storages on stream
533 SvStream* m_pSource; // original stream, only for storages on a stream
534 //SvStream* m_pStream; // the corresponding editable stream, only for storage on a stream
535 long m_nError;
536 StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing )
537 BOOL m_bModified; // only modified elements will be sent to the original content
538 BOOL m_bCommited; // sending the streams is coordinated by the root storage of the package
539 BOOL m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages
540 // this means that the root storage does an autocommit when its external
541 // reference is destroyed
542 BOOL m_bIsRoot; // marks this storage as root storages that manages all oommits and reverts
543 BOOL m_bDirty; // ???
544 BOOL m_bIsLinked;
545 BOOL m_bListCreated;
546 ULONG m_nFormat;
547 String m_aUserTypeName;
548 SvGlobalName m_aClassId;
550 UCBStorageElementList_Impl m_aChildrenList;
552 BOOL m_bRepairPackage;
553 Reference< XProgressHandler > m_xProgressHandler;
555 UNOStorageHolderList* m_pUNOStorageHolderList;
556 UCBStorage_Impl( const ::ucbhelper::Content&, const String&, StreamMode, UCBStorage*, BOOL, BOOL, BOOL = FALSE, Reference< XProgressHandler > = Reference< XProgressHandler >() );
557 UCBStorage_Impl( const String&, StreamMode, UCBStorage*, BOOL, BOOL, BOOL = FALSE, Reference< XProgressHandler > = Reference< XProgressHandler >() );
558 UCBStorage_Impl( SvStream&, UCBStorage*, BOOL );
559 void Init();
560 sal_Int16 Commit();
561 BOOL Revert();
562 BOOL Insert( ::ucbhelper::Content *pContent );
563 UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, BOOL bDirect );
564 UCBStorageStream_Impl* OpenStream( UCBStorageElement_Impl*, StreamMode, BOOL, const ByteString* pKey=0 );
565 void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& );
566 void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const String& );
567 sal_Int32 GetObjectCount();
568 void ReadContent();
569 void CreateContent();
570 ::ucbhelper::Content* GetContent()
571 { if ( !m_pContent ) CreateContent(); return m_pContent; }
572 UCBStorageElementList_Impl& GetChildrenList()
574 long nError = m_nError;
575 ReadContent();
576 if ( m_nMode & STREAM_WRITE )
578 m_nError = nError;
579 if ( m_pAntiImpl )
581 m_pAntiImpl->ResetError();
582 m_pAntiImpl->SetError( nError );
586 return m_aChildrenList;
589 void SetError( long nError );
592 SV_DECL_IMPL_REF( UCBStorage_Impl );
594 // this struct contains all neccessary information on an element inside a UCBStorage
595 struct UCBStorageElement_Impl
597 String m_aName; // the actual URL relative to the root "folder"
598 String m_aOriginalName;// the original name in the content
599 ULONG m_nSize;
600 BOOL m_bIsFolder; // Only TRUE when it is a UCBStorage !
601 BOOL m_bIsStorage; // Also TRUE when it is an OLEStorage !
602 BOOL m_bIsRemoved; // element will be removed on commit
603 BOOL m_bIsInserted; // element will be removed on revert
604 UCBStorage_ImplRef m_xStorage; // reference to the "real" storage
605 UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream
607 UCBStorageElement_Impl( const ::rtl::OUString& rName,
608 BOOL bIsFolder = FALSE, ULONG nSize = 0 )
609 : m_aName( rName )
610 , m_aOriginalName( rName )
611 , m_nSize( nSize )
612 , m_bIsFolder( bIsFolder )
613 , m_bIsStorage( bIsFolder )
614 , m_bIsRemoved( FALSE )
615 , m_bIsInserted( FALSE )
619 ::ucbhelper::Content* GetContent();
620 BOOL IsModified();
621 String GetContentType();
622 void SetContentType( const String& );
623 String GetOriginalContentType();
624 BOOL IsLoaded()
625 { return m_xStream.Is() || m_xStorage.Is(); }
628 ::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
630 if ( m_xStream.Is() )
631 return m_xStream->m_pContent;
632 else if ( m_xStorage.Is() )
633 return m_xStorage->GetContent();
634 else
635 return NULL;
638 String UCBStorageElement_Impl::GetContentType()
640 if ( m_xStream.Is() )
641 return m_xStream->m_aContentType;
642 else if ( m_xStorage.Is() )
643 return m_xStorage->m_aContentType;
644 else
646 DBG_ERROR("Element not loaded!");
647 return String();
651 void UCBStorageElement_Impl::SetContentType( const String& rType )
653 if ( m_xStream.Is() ) {
654 m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
656 else if ( m_xStorage.Is() ) {
657 m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
659 else {
660 DBG_ERROR("Element not loaded!");
664 String UCBStorageElement_Impl::GetOriginalContentType()
666 if ( m_xStream.Is() )
667 return m_xStream->m_aOriginalContentType;
668 else if ( m_xStorage.Is() )
669 return m_xStorage->m_aOriginalContentType;
670 else
671 return String();
674 BOOL UCBStorageElement_Impl::IsModified()
676 BOOL bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
677 if ( bModified )
679 if ( m_xStream.Is() )
680 bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
681 else if ( m_xStorage.Is() )
682 bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
685 return bModified;
688 UCBStorageStream_Impl::UCBStorageStream_Impl( const String& rName, StreamMode nMode, UCBStorageStream* pStream, BOOL bDirect, const ByteString* pKey, BOOL bRepair, Reference< XProgressHandler > xProgress )
689 : m_pAntiImpl( pStream )
690 , m_aURL( rName )
691 , m_pContent( NULL )
692 , m_pStream( NULL )
693 , m_nRepresentMode( nonset )
694 , m_nError( 0 )
695 , m_nMode( nMode )
696 , m_bSourceRead( !( nMode & STREAM_TRUNC ) )
697 , m_bModified( FALSE )
698 , m_bCommited( FALSE )
699 , m_bDirect( bDirect )
700 , m_bIsOLEStorage( FALSE )
702 // name is last segment in URL
703 INetURLObject aObj( rName );
704 m_aName = m_aOriginalName = aObj.GetLastName();
707 // create the content
708 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
710 ::rtl::OUString aTemp( rName );
712 if ( bRepair )
714 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
715 xProgress );
716 aTemp += rtl::OUString::createFromAscii("?repairpackage");
719 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
721 if ( pKey )
723 m_aKey = *pKey;
725 // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
726 sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1];
727 rtlDigestError nErr = rtl_digest_SHA1( pKey->GetBuffer(), pKey->Len(), aBuffer, RTL_DIGEST_LENGTH_SHA1 );
728 if ( nErr == rtl_Digest_E_None )
730 sal_uInt8* pBuffer = aBuffer;
731 ::com::sun::star::uno::Sequence < sal_Int8 > aSequ( (sal_Int8*) pBuffer, RTL_DIGEST_LENGTH_SHA1 );
732 ::com::sun::star::uno::Any aAny;
733 aAny <<= aSequ;
734 m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii("EncryptionKey"), aAny );
738 catch ( ContentCreationException& )
740 // content could not be created
741 SetError( SVSTREAM_CANNOT_MAKE );
743 catch ( RuntimeException& )
745 // any other error - not specified
746 SetError( ERRCODE_IO_GENERAL );
750 UCBStorageStream_Impl::~UCBStorageStream_Impl()
752 if( m_rSource.is() )
753 m_rSource = Reference< XInputStream >();
755 if( m_pStream )
756 delete m_pStream;
758 if ( m_aTempURL.Len() )
759 ::utl::UCBContentHelper::Kill( m_aTempURL );
761 if( m_pContent )
762 delete m_pContent;
766 Reference<XInputStream> UCBStorageStream_Impl::GetXInputStream()
768 Reference< XInputStream > aResult;
770 if( m_pAntiImpl && m_nRepresentMode != nonset )
772 DBG_ERROR( "Misuse of the XInputstream!" );
773 SetError( ERRCODE_IO_ACCESSDENIED );
775 else
777 if( m_bModified )
779 // use wrapper around temporary stream
780 if( Init() )
782 CopySourceToTemporary();
784 // owner transfer of stream to wrapper
785 aResult = new ::utl::OInputStreamWrapper( m_pStream, TRUE );
786 m_pStream->Seek(0);
788 if( aResult.is() )
790 // temporary stream can not be used here any more
791 // and can not be opened untill wrapper is closed
792 // stream is deleted by wrapper after use
793 m_pStream = NULL;
794 m_nRepresentMode = xinputstream;
798 else
800 Free();
802 // open a new instance of XInputStream
805 aResult = m_pContent->openStream();
807 catch ( Exception& )
809 // usually means that stream could not be opened
812 if( aResult.is() )
813 m_nRepresentMode = xinputstream;
814 else
815 SetError( ERRCODE_IO_ACCESSDENIED );
819 return aResult;
822 BOOL UCBStorageStream_Impl::Init()
824 if( m_nRepresentMode == xinputstream )
826 DBG_ERROR( "XInputStream misuse!" );
827 SetError( ERRCODE_IO_ACCESSDENIED );
828 return FALSE;
831 if( !m_pStream )
833 // no temporary stream was created
834 // create one
836 m_nRepresentMode = svstream; // can not be used as XInputStream
838 if ( !m_aTempURL.Len() )
839 m_aTempURL = ::utl::TempFile().GetURL();
841 m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, STREAM_STD_READWRITE, sal_True /* bFileExists */ );
842 #if OSL_DEBUG_LEVEL > 1
843 ++nOpenFiles;
844 #endif
846 if( !m_pStream )
848 DBG_ERROR( "Suspicious temporary stream creation!" );
849 SetError( SVSTREAM_CANNOT_MAKE );
850 return FALSE;
853 SetError( m_pStream->GetError() );
856 if( m_bSourceRead && !m_rSource.is() )
858 // source file contain usefull information and is not opened
859 // open it from the point of noncopied data
863 m_rSource = m_pContent->openStream();
865 catch ( Exception& )
867 // usually means that stream could not be opened
870 if( m_rSource.is() )
872 m_pStream->Seek( STREAM_SEEK_TO_END );
876 m_rSource->skipBytes( m_pStream->Tell() );
878 catch( BufferSizeExceededException& )
880 // the temporary stream already contain all the data
881 m_bSourceRead = FALSE;
883 catch( Exception& )
885 // something is really wrong
886 m_bSourceRead = FALSE;
887 DBG_ERROR( "Can not operate original stream!" );
888 SetError( SVSTREAM_CANNOT_MAKE );
891 m_pStream->Seek( 0 );
893 else
895 // if the new file is edited than no source exist
896 m_bSourceRead = FALSE;
897 //SetError( SVSTREAM_CANNOT_MAKE );
901 DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
903 return sal_True;
906 ULONG UCBStorageStream_Impl::ReadSourceWriteTemporary()
908 // read source stream till the end and copy all the data to
909 // the current position of the temporary stream
911 ULONG aResult = 0;
913 if( m_bSourceRead )
915 Sequence<sal_Int8> aData(32000);
919 ULONG aReaded;
922 aReaded = m_rSource->readBytes( aData, 32000 );
923 aResult += m_pStream->Write( aData.getArray(), aReaded );
924 } while( aReaded == 32000 );
926 #if OSL_DEBUG_LEVEL > 1
927 catch( Exception & e )
929 OSL_ENSURE( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
930 #else
931 catch( Exception & )
933 #endif
937 m_bSourceRead = FALSE;
939 return aResult;
943 ULONG UCBStorageStream_Impl::ReadSourceWriteTemporary( ULONG aLength )
945 // read aLength bite from the source stream and copy them to the current
946 // position of the temporary stream
948 ULONG aResult = 0;
950 if( m_bSourceRead )
952 Sequence<sal_Int8> aData(32000);
957 ULONG aReaded = 32000;
959 for( ULONG pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 )
961 ULONG aToCopy = min( aLength - pInd, 32000 );
962 aReaded = m_rSource->readBytes( aData, aToCopy );
963 aResult += m_pStream->Write( aData.getArray(), aReaded );
966 if( aResult < aLength )
967 m_bSourceRead = FALSE;
969 #if OSL_DEBUG_LEVEL > 1
970 catch( Exception & e )
972 OSL_ENSURE( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
973 #else
974 catch( Exception & )
976 #endif
980 return aResult;
983 ULONG UCBStorageStream_Impl::CopySourceToTemporary()
985 // current position of the temporary stream is not changed
986 ULONG aResult = 0;
988 if( m_bSourceRead )
990 ULONG aPos = m_pStream->Tell();
991 m_pStream->Seek( STREAM_SEEK_TO_END );
992 aResult = ReadSourceWriteTemporary();
993 m_pStream->Seek( aPos );
996 return aResult;
1000 #if 0
1001 ULONG UCBStorageStream_Impl::CopySourceToTemporary( ULONG aLength )
1003 // current position of the temporary stream is not changed
1004 ULONG aResult = 0;
1006 if( m_bSourceRead )
1008 ULONG aPos = m_pStream->Tell();
1009 m_pStream->Seek( STREAM_SEEK_TO_END );
1010 aResult = ReadSourceWriteTemporary( aLength );
1011 m_pStream->Seek( aPos );
1014 return aResult;
1017 #endif
1019 // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
1020 // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
1021 ULONG UCBStorageStream_Impl::GetData( void* pData, ULONG nSize )
1023 ULONG aResult = 0;
1025 if( !Init() )
1026 return 0;
1029 // read data that is in temporary stream
1030 aResult = m_pStream->Read( pData, nSize );
1031 if( m_bSourceRead && aResult < nSize )
1033 // read the tail of the data from original stream
1034 // copy this tail to the temporary stream
1036 ULONG aToRead = nSize - aResult;
1037 pData = (void*)( (char*)pData + aResult );
1041 Sequence<sal_Int8> aData( aToRead );
1042 ULONG aReaded = m_rSource->readBytes( aData, aToRead );
1043 aResult += m_pStream->Write( (void*)aData.getArray(), aReaded );
1044 memcpy( pData, aData.getArray(), aReaded );
1046 #if OSL_DEBUG_LEVEL > 1
1047 catch( Exception & e )
1049 OSL_ENSURE( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
1050 #else
1051 catch( Exception & )
1053 #endif
1056 if( aResult < nSize )
1057 m_bSourceRead = FALSE;
1060 return aResult;
1063 ULONG UCBStorageStream_Impl::PutData( const void* pData, ULONG nSize )
1065 if ( !(m_nMode & STREAM_WRITE) )
1067 SetError( ERRCODE_IO_ACCESSDENIED );
1068 return 0; // ?mav?
1071 if( !nSize || !Init() )
1072 return 0;
1074 ULONG aResult = m_pStream->Write( pData, nSize );
1076 m_bModified = aResult > 0;
1078 return aResult;
1082 ULONG UCBStorageStream_Impl::SeekPos( ULONG nPos )
1084 if( !Init() )
1085 return 0;
1087 ULONG aResult;
1089 if( nPos == STREAM_SEEK_TO_END )
1091 m_pStream->Seek( STREAM_SEEK_TO_END );
1092 ReadSourceWriteTemporary();
1093 aResult = m_pStream->Tell();
1095 else
1097 // the problem is that even if nPos is larger the the length
1098 // of the stream the stream pointer will be moved to this position
1099 // so we have to check if temporary stream does not contain required position
1101 if( m_pStream->Tell() > nPos
1102 || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
1104 // no copiing is required
1105 aResult = m_pStream->Seek( nPos );
1107 else
1109 // the temp stream pointer points to the end now
1110 aResult = m_pStream->Tell();
1112 if( aResult < nPos )
1114 if( m_bSourceRead )
1116 aResult += ReadSourceWriteTemporary( nPos - aResult );
1117 if( aResult < nPos )
1118 m_bSourceRead = FALSE;
1120 DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
1123 if( (m_nMode & STREAM_WRITE) && !m_bSourceRead && aResult < nPos )
1125 // it means that all the Source stream was copied already
1126 // but the required position still was not reached
1127 // for writable streams it should be done
1128 m_pStream->SetStreamSize( nPos );
1129 aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
1130 DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
1136 return aResult;
1139 void UCBStorageStream_Impl::SetSize( ULONG nSize )
1141 if ( !(m_nMode & STREAM_WRITE) )
1143 SetError( ERRCODE_IO_ACCESSDENIED );
1144 return;
1147 if( !Init() )
1148 return;
1150 m_bModified = TRUE;
1152 if( m_bSourceRead )
1154 ULONG aPos = m_pStream->Tell();
1155 m_pStream->Seek( STREAM_SEEK_TO_END );
1156 if( m_pStream->Tell() < nSize )
1157 ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
1158 m_pStream->Seek( aPos );
1161 m_pStream->SetStreamSize( nSize );
1162 m_bSourceRead = FALSE;
1165 void UCBStorageStream_Impl::FlushData()
1167 if( m_pStream )
1169 CopySourceToTemporary();
1170 m_pStream->Flush();
1173 m_bCommited = TRUE;
1176 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr )
1178 if ( !m_nError )
1180 m_nError = nErr;
1181 SvStream::SetError( nErr );
1182 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
1186 void UCBStorageStream_Impl::ResetError()
1188 m_nError = 0;
1189 SvStream::ResetError();
1190 if ( m_pAntiImpl )
1191 m_pAntiImpl->ResetError();
1194 ULONG UCBStorageStream_Impl::GetSize()
1196 if( !Init() )
1197 return 0;
1199 ULONG nPos = m_pStream->Tell();
1200 m_pStream->Seek( STREAM_SEEK_TO_END );
1201 ReadSourceWriteTemporary();
1202 ULONG nRet = m_pStream->Tell();
1203 m_pStream->Seek( nPos );
1205 return nRet;
1208 BaseStorage* UCBStorageStream_Impl::CreateStorage()
1210 // create an OLEStorage on a SvStream ( = this )
1211 // it gets the root attribute because otherwise it would probably not write before my root is commited
1212 UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
1213 Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );
1215 // GetError() call cleares error code for OLE storages, must be changed in future
1216 long nTmpErr = pStorage->GetError();
1217 pStorage->SetError( nTmpErr );
1219 m_bIsOLEStorage = !nTmpErr;
1220 return static_cast< BaseStorage* > ( pStorage );
1223 sal_Int16 UCBStorageStream_Impl::Commit()
1225 // send stream to the original content
1226 // the parent storage is responsible for the correct handling of deleted contents
1227 if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
1229 // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
1230 // was commited as well ( if not opened in direct mode )
1232 if ( m_bModified )
1236 CopySourceToTemporary();
1238 // release all stream handles
1239 Free();
1241 // the temporary file does not exist only for truncated streams
1242 DBG_ASSERT( m_aTempURL.Len() || ( m_nMode & STREAM_TRUNC ), "No temporary file to read from!");
1243 if ( !m_aTempURL.Len() && !( m_nMode & STREAM_TRUNC ) )
1244 throw RuntimeException();
1246 // create wrapper to stream that is only used while reading inside package component
1247 Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );
1249 Any aAny;
1250 InsertCommandArgument aArg;
1251 aArg.Data = xStream;
1252 aArg.ReplaceExisting = sal_True;
1253 aAny <<= aArg;
1254 m_pContent->executeCommand( ::rtl::OUString::createFromAscii("insert"), aAny );
1256 // wrapper now controls lifetime of temporary file
1257 m_aTempURL.Erase();
1259 INetURLObject aObj( m_aURL );
1260 aObj.SetName( m_aName );
1261 m_aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
1262 m_bModified = FALSE;
1263 m_bSourceRead = TRUE;
1265 catch ( CommandAbortedException& )
1267 // any command wasn't executed successfully - not specified
1268 SetError( ERRCODE_IO_GENERAL );
1269 return COMMIT_RESULT_FAILURE;
1271 catch ( RuntimeException& )
1273 // any other error - not specified
1274 SetError( ERRCODE_IO_GENERAL );
1275 return COMMIT_RESULT_FAILURE;
1277 catch ( Exception& )
1279 // any other error - not specified
1280 SetError( ERRCODE_IO_GENERAL );
1281 return COMMIT_RESULT_FAILURE;
1284 m_bCommited = FALSE;
1285 return COMMIT_RESULT_SUCCESS;
1289 return COMMIT_RESULT_NOTHING_TO_DO;
1292 BOOL UCBStorageStream_Impl::Revert()
1294 // if an OLEStorage is created on this stream, no "revert" is neccessary because OLEStorages do nothing on "Revert" !
1295 if ( m_bCommited )
1297 DBG_ERROR("Revert while commit is in progress!" );
1298 return FALSE; // ???
1301 Free();
1302 if ( m_aTempURL.Len() )
1304 ::utl::UCBContentHelper::Kill( m_aTempURL );
1305 m_aTempURL.Erase();
1308 m_bSourceRead = FALSE;
1311 m_rSource = m_pContent->openStream();
1312 if( m_rSource.is() )
1314 if ( m_pAntiImpl && ( m_nMode & STREAM_TRUNC ) )
1315 // stream is in use and should be truncated
1316 m_bSourceRead = FALSE;
1317 else
1319 m_nMode &= ~STREAM_TRUNC;
1320 m_bSourceRead = TRUE;
1323 else
1324 SetError( SVSTREAM_CANNOT_MAKE );
1326 catch ( ContentCreationException& )
1328 SetError( ERRCODE_IO_GENERAL );
1330 catch ( RuntimeException& )
1332 SetError( ERRCODE_IO_GENERAL );
1334 catch ( Exception& )
1338 m_bModified = FALSE;
1339 m_aName = m_aOriginalName;
1340 m_aContentType = m_aOriginalContentType;
1341 return ( GetError() == ERRCODE_NONE );
1344 BOOL UCBStorageStream_Impl::Clear()
1346 BOOL bRet = ( m_pAntiImpl == NULL );
1347 DBG_ASSERT( bRet, "Removing used stream!" );
1348 if( bRet )
1350 Free();
1353 return bRet;
1356 void UCBStorageStream_Impl::Free()
1358 #if OSL_DEBUG_LEVEL > 1
1359 if ( m_pStream )
1361 if ( m_aTempURL.Len() )
1362 --nOpenFiles;
1363 else
1364 --nOpenStreams;
1366 #endif
1368 m_nRepresentMode = nonset;
1369 m_rSource = Reference< XInputStream >();
1370 DELETEZ( m_pStream );
1373 void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
1375 sal_Bool isWritable = (( m_nMode & STREAM_WRITE ) != 0 );
1376 if ( isWritable )
1378 // once stream was writable, never reset to readonly
1379 nMode |= STREAM_WRITE;
1382 m_nMode = nMode;
1383 Free();
1385 if ( nMode & STREAM_TRUNC )
1387 m_bSourceRead = 0; // usually it should be 0 already but just in case...
1389 if ( m_aTempURL.Len() )
1391 ::utl::UCBContentHelper::Kill( m_aTempURL );
1392 m_aTempURL.Erase();
1397 UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, BOOL bDirect, const ByteString* pKey )
1399 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1400 // to class UCBStorageStream !
1401 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey );
1402 pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1403 StorageBase::m_nMode = pImp->m_nMode;
1406 UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, BOOL bDirect, const ByteString* pKey, BOOL bRepair, Reference< XProgressHandler > xProgress )
1408 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1409 // to class UCBStorageStream !
1410 pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey, bRepair, xProgress );
1411 pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1412 StorageBase::m_nMode = pImp->m_nMode;
1415 UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
1416 : pImp( pImpl )
1418 pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1419 pImp->m_pAntiImpl = this;
1420 SetError( pImp->m_nError );
1421 StorageBase::m_nMode = pImp->m_nMode;
1424 UCBStorageStream::~UCBStorageStream()
1426 if ( pImp->m_nMode & STREAM_WRITE )
1427 pImp->Flush();
1428 pImp->m_pAntiImpl = NULL;
1429 pImp->Free();
1430 pImp->ReleaseRef();
1433 ULONG UCBStorageStream::Read( void * pData, ULONG nSize )
1435 //return pImp->m_pStream->Read( pData, nSize );
1436 return pImp->GetData( pData, nSize );
1439 ULONG UCBStorageStream::Write( const void* pData, ULONG nSize )
1442 // mba: does occur in writer !
1443 if ( pImp->m_bCommited )
1445 DBG_ERROR("Writing while commit is in progress!" );
1446 return 0;
1449 // pImp->m_bModified = TRUE;
1450 //return pImp->m_pStream->Write( pData, nSize );
1451 return pImp->PutData( pData, nSize );
1454 ULONG UCBStorageStream::Seek( ULONG nPos )
1456 //return pImp->m_pStream->Seek( nPos );
1457 return pImp->Seek( nPos );
1460 ULONG UCBStorageStream::Tell()
1462 if( !pImp->Init() )
1463 return 0;
1464 return pImp->m_pStream->Tell();
1467 void UCBStorageStream::Flush()
1469 // streams are never really transacted, so flush also means commit !
1470 Commit();
1473 BOOL UCBStorageStream::SetSize( ULONG nNewSize )
1476 if ( pImp->m_bCommited )
1478 DBG_ERROR("Changing stream size while commit is in progress!" );
1479 return FALSE;
1482 // pImp->m_bModified = TRUE;
1483 //return pImp->m_pStream->SetStreamSize( nNewSize );
1484 pImp->SetSize( nNewSize );
1485 return !pImp->GetError();
1488 BOOL UCBStorageStream::Validate( BOOL bWrite ) const
1490 return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
1493 BOOL UCBStorageStream::ValidateMode( StreamMode m ) const
1495 // ???
1496 if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
1497 return TRUE;
1498 USHORT nCurMode = 0xFFFF;
1499 if( ( m & 3 ) == STREAM_READ )
1501 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
1502 if( ( ( m & STREAM_SHARE_DENYWRITE )
1503 && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
1504 || ( ( m & STREAM_SHARE_DENYALL )
1505 && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
1506 return TRUE;
1508 else
1510 // only SHARE_DENYALL allowed
1511 // storages open in r/o mode are OK, since only
1512 // the commit may fail
1513 if( ( m & STREAM_SHARE_DENYALL )
1514 && ( nCurMode & STREAM_SHARE_DENYALL ) )
1515 return TRUE;
1518 return TRUE;
1521 const SvStream* UCBStorageStream::GetSvStream() const
1523 if( !pImp->Init() )
1524 return NULL;
1526 pImp->CopySourceToTemporary();
1527 return pImp->m_pStream; // should not live longer then pImp!!!
1530 SvStream* UCBStorageStream::GetModifySvStream()
1532 return (SvStream*)pImp;
1535 Reference< XInputStream > UCBStorageStream::GetXInputStream() const
1537 return pImp->GetXInputStream();
1540 BOOL UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
1542 // ???
1543 return ((BaseStorageStream*) this ) == &rStream;
1546 BOOL UCBStorageStream::Commit()
1548 // mark this stream for sending it on root commit
1549 pImp->FlushData();
1550 return TRUE;
1553 BOOL UCBStorageStream::Revert()
1555 return pImp->Revert();
1558 BOOL UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
1560 if( !pImp->Init() )
1561 return FALSE;
1563 UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
1564 if ( pStg )
1565 pStg->pImp->m_aContentType = pImp->m_aContentType;
1567 pDestStm->SetSize( 0 );
1568 Seek( STREAM_SEEK_TO_END );
1569 INT32 n = Tell();
1570 if( n < 0 )
1571 return FALSE;
1573 if( pDestStm->SetSize( n ) && n )
1575 BYTE* p = new BYTE[ 4096 ];
1576 Seek( 0L );
1577 pDestStm->Seek( 0L );
1578 while( n )
1580 UINT32 nn = n;
1581 if( nn > 4096 )
1582 nn = 4096;
1583 if( Read( p, nn ) != nn )
1584 break;
1585 if( pDestStm->Write( p, nn ) != nn )
1586 break;
1587 n -= nn;
1590 delete[] p;
1593 return TRUE;
1596 BOOL UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
1598 if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
1599 return FALSE;
1601 if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
1603 ::rtl::OUString aTmp;
1604 rValue >>= aTmp;
1605 pImp->m_aContentType = aTmp;
1610 if ( pImp->m_pContent )
1612 pImp->m_pContent->setPropertyValue( rName, rValue );
1613 return TRUE;
1616 catch ( Exception& )
1620 return FALSE;
1623 BOOL UCBStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
1627 if ( pImp->m_pContent )
1629 rValue = pImp->m_pContent->getPropertyValue( rName );
1630 return TRUE;
1633 catch ( Exception& )
1637 return FALSE;
1640 UCBStorage::UCBStorage( SvStream& rStrm, BOOL bDirect )
1642 String aURL = GetLinkedFile( rStrm );
1643 if ( aURL.Len() )
1645 StreamMode nMode = STREAM_READ;
1646 if( rStrm.IsWritable() )
1647 nMode = STREAM_READ | STREAM_WRITE;
1649 ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >() );
1650 pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, TRUE );
1652 else
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( rStrm, this, bDirect );
1659 pImp->AddRef();
1660 pImp->Init();
1661 StorageBase::m_nMode = pImp->m_nMode;
1664 UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, BOOL bDirect, BOOL bIsRoot )
1666 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1667 // to class UCBStorage !
1668 pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
1669 pImp->AddRef();
1670 pImp->Init();
1671 StorageBase::m_nMode = pImp->m_nMode;
1674 UCBStorage::UCBStorage( const String& rName, StreamMode nMode, BOOL bDirect, BOOL bIsRoot, BOOL bIsRepair, Reference< XProgressHandler > xProgressHandler )
1676 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1677 // to class UCBStorage !
1678 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
1679 pImp->AddRef();
1680 pImp->Init();
1681 StorageBase::m_nMode = pImp->m_nMode;
1684 UCBStorage::UCBStorage( const String& rName, StreamMode nMode, BOOL bDirect, BOOL bIsRoot )
1686 // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
1687 // to class UCBStorage !
1688 pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, sal_False, Reference< XProgressHandler >() );
1689 pImp->AddRef();
1690 pImp->Init();
1691 StorageBase::m_nMode = pImp->m_nMode;
1694 UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
1695 : pImp( pImpl )
1697 pImp->m_pAntiImpl = this;
1698 SetError( pImp->m_nError );
1699 pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used
1700 StorageBase::m_nMode = pImp->m_nMode;
1703 UCBStorage::~UCBStorage()
1705 if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
1706 // DirectMode is simulated with an AutoCommit
1707 Commit();
1709 pImp->m_pAntiImpl = NULL;
1710 pImp->ReleaseRef();
1713 UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, UCBStorage* pStorage, BOOL bDirect, BOOL bIsRoot, BOOL bIsRepair, Reference< XProgressHandler > xProgressHandler )
1714 : m_pAntiImpl( pStorage )
1715 , m_pContent( new ::ucbhelper::Content( rContent ) )
1716 , m_pTempFile( NULL )
1717 , m_pSource( NULL )
1718 //, m_pStream( NULL )
1719 , m_nError( 0 )
1720 , m_nMode( nMode )
1721 , m_bModified( FALSE )
1722 , m_bCommited( FALSE )
1723 , m_bDirect( bDirect )
1724 , m_bIsRoot( bIsRoot )
1725 , m_bDirty( FALSE )
1726 , m_bIsLinked( TRUE )
1727 , m_bListCreated( FALSE )
1728 , m_nFormat( 0 )
1729 , m_aClassId( SvGlobalName() )
1730 , m_bRepairPackage( bIsRepair )
1731 , m_xProgressHandler( xProgressHandler )
1732 , m_pUNOStorageHolderList( NULL )
1735 String aName( rName );
1736 if( !aName.Len() )
1738 // no name given = use temporary name!
1739 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1740 m_pTempFile = new ::utl::TempFile;
1741 m_pTempFile->EnableKillingFile( TRUE );
1742 m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1745 m_aURL = rName;
1748 UCBStorage_Impl::UCBStorage_Impl( const String& rName, StreamMode nMode, UCBStorage* pStorage, BOOL bDirect, BOOL bIsRoot, BOOL bIsRepair, Reference< XProgressHandler > xProgressHandler )
1749 : m_pAntiImpl( pStorage )
1750 , m_pContent( NULL )
1751 , m_pTempFile( NULL )
1752 , m_pSource( NULL )
1753 //, m_pStream( NULL )
1754 , m_nError( 0 )
1755 , m_nMode( nMode )
1756 , m_bModified( FALSE )
1757 , m_bCommited( FALSE )
1758 , m_bDirect( bDirect )
1759 , m_bIsRoot( bIsRoot )
1760 , m_bDirty( FALSE )
1761 , m_bIsLinked( FALSE )
1762 , m_bListCreated( FALSE )
1763 , m_nFormat( 0 )
1764 , m_aClassId( SvGlobalName() )
1765 , m_bRepairPackage( bIsRepair )
1766 , m_xProgressHandler( xProgressHandler )
1767 , m_pUNOStorageHolderList( NULL )
1769 String aName( rName );
1770 if( !aName.Len() )
1772 // no name given = use temporary name!
1773 DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
1774 m_pTempFile = new ::utl::TempFile;
1775 m_pTempFile->EnableKillingFile( TRUE );
1776 m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
1779 if ( m_bIsRoot )
1781 // create the special package URL for the package content
1782 String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
1783 aTemp += String(INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1784 m_aURL = aTemp;
1786 if ( m_nMode & STREAM_WRITE )
1788 // the root storage opens the package, so make sure that there is any
1789 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READWRITE, m_pTempFile != 0 /* bFileExists */ );
1790 delete pStream;
1793 else
1795 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1796 m_aURL = rName;
1797 if ( m_aURL.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 )
1798 m_bIsLinked = TRUE;
1802 UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, BOOL bDirect )
1803 : m_pAntiImpl( pStorage )
1804 , m_pContent( NULL )
1805 , m_pTempFile( new ::utl::TempFile )
1806 , m_pSource( &rStream )
1807 , m_nError( 0 )
1808 , m_bModified( FALSE )
1809 , m_bCommited( FALSE )
1810 , m_bDirect( bDirect )
1811 , m_bIsRoot( TRUE )
1812 , m_bDirty( FALSE )
1813 , m_bIsLinked( FALSE )
1814 , m_bListCreated( FALSE )
1815 , m_nFormat( 0 )
1816 , m_aClassId( SvGlobalName() )
1817 , m_bRepairPackage( FALSE )
1818 , m_pUNOStorageHolderList( NULL )
1820 // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
1821 // which will be called in the storages' dtor
1822 m_pTempFile->EnableKillingFile( TRUE );
1823 DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );
1825 // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
1826 // accessed readonly
1827 // the root storage opens the package; create the special package URL for the package content
1828 String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
1829 aTemp += String(INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
1830 m_aURL = aTemp;
1832 // copy data into the temporary file
1833 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, sal_True /* bFileExists */ );
1834 if ( pStream )
1836 rStream.Seek(0);
1837 rStream >> *pStream;
1838 pStream->Flush();
1839 DELETEZ( pStream );
1842 // close stream and let content access the file
1843 m_pSource->Seek(0);
1845 // check opening mode
1846 m_nMode = STREAM_READ;
1847 if( rStream.IsWritable() )
1848 m_nMode = STREAM_READ | STREAM_WRITE;
1851 void UCBStorage_Impl::Init()
1853 // name is last segment in URL
1854 INetURLObject aObj( m_aURL );
1855 if ( !m_aName.Len() )
1856 // if the name was not already set to a temp name
1857 m_aName = m_aOriginalName = aObj.GetLastName();
1859 // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
1860 if ( !m_pContent && !( m_nMode & STORAGE_DISKSPANNED_MODE ) )
1861 CreateContent();
1863 if ( m_nMode & STORAGE_DISKSPANNED_MODE )
1865 // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
1866 // disk spanned file
1867 m_aContentType = m_aOriginalContentType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.xml.impress") );
1869 else if ( m_pContent )
1871 if ( m_bIsLinked )
1873 if( m_bIsRoot )
1875 ReadContent();
1876 if ( m_nError == ERRCODE_NONE )
1878 // read the manifest.xml file
1879 aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("META-INF") ) );
1880 aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("manifest.xml") ) );
1882 // create input stream
1883 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
1884 // no stream means no manifest.xml
1885 if ( pStream )
1887 if ( !pStream->GetError() )
1889 ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
1890 com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xInputStream( pHelper );
1892 // create a manifest reader object that will read in the manifest from the stream
1893 Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader =
1894 Reference< ::com::sun::star::packages::manifest::XManifestReader >
1895 ( ::comphelper::getProcessServiceFactory()->createInstance(
1896 ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestReader" )), UNO_QUERY) ;
1897 Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );
1899 // cleanup
1900 xReader = NULL;
1901 xInputStream = NULL;
1902 SetProps( aProps, String() );
1905 delete pStream;
1909 else
1910 ReadContent();
1912 else
1914 // get the manifest information from the package
1915 try {
1916 Any aAny = m_pContent->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
1917 rtl::OUString aTmp;
1918 if ( ( aAny >>= aTmp ) && aTmp.getLength() )
1919 m_aContentType = m_aOriginalContentType = aTmp;
1921 catch( Exception& )
1923 DBG_ASSERT( sal_False,
1924 "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
1929 if ( m_aContentType.Len() )
1931 // get the clipboard format using the content type
1932 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
1933 aDataFlavor.MimeType = m_aContentType;
1934 m_nFormat = SotExchange::GetFormat( aDataFlavor );
1936 // get the ClassId using the clipboard format ( internal table )
1937 m_aClassId = GetClassId_Impl( m_nFormat );
1939 // get human presentable name using the clipboard format
1940 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
1941 m_aUserTypeName = aDataFlavor.HumanPresentableName;
1943 if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
1944 ReadContent();
1948 void UCBStorage_Impl::CreateContent()
1952 // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
1953 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
1955 ::rtl::OUString aTemp( m_aURL );
1957 if ( m_bRepairPackage )
1959 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
1960 m_xProgressHandler );
1961 aTemp += rtl::OUString::createFromAscii("?repairpackage");
1964 m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
1966 catch ( ContentCreationException& )
1968 // content could not be created
1969 SetError( SVSTREAM_CANNOT_MAKE );
1971 catch ( RuntimeException& )
1973 // any other error - not specified
1974 SetError( SVSTREAM_CANNOT_MAKE );
1978 void UCBStorage_Impl::ReadContent()
1980 if ( m_bListCreated )
1981 return;
1983 m_bListCreated = TRUE;
1985 // create cursor for access to children
1986 Sequence< ::rtl::OUString > aProps(4);
1987 ::rtl::OUString* pProps = aProps.getArray();
1988 pProps[0] = ::rtl::OUString::createFromAscii( "Title" );
1989 pProps[1] = ::rtl::OUString::createFromAscii( "IsFolder" );
1990 pProps[2] = ::rtl::OUString::createFromAscii( "MediaType" );
1991 pProps[3] = ::rtl::OUString::createFromAscii( "Size" );
1992 ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS;
1996 GetContent();
1997 if ( !m_pContent )
1998 return;
2000 Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude );
2001 Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
2002 Reference< XRow > xRow( xResultSet, UNO_QUERY );
2003 if ( xResultSet.is() )
2005 while ( xResultSet->next() )
2007 // insert all into the children list
2008 ::rtl::OUString aTitle( xRow->getString(1) );
2009 ::rtl::OUString aContentType;
2010 if ( m_bIsLinked )
2012 // unpacked storages have to deal with the meta-inf folder by themselves
2013 if( aTitle.equalsAscii("META-INF") )
2014 continue;
2016 else
2018 aContentType = xRow->getString(3);
2021 BOOL bIsFolder( xRow->getBoolean(2) );
2022 sal_Int64 nSize = xRow->getLong(4);
2023 UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (ULONG) nSize );
2024 m_aChildrenList.Insert( pElement, LIST_APPEND );
2026 sal_Bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
2027 if ( bIsFolder )
2029 if ( m_bIsLinked )
2030 OpenStorage( pElement, m_nMode, m_bDirect );
2031 if ( pElement->m_xStorage.Is() )
2032 pElement->m_xStorage->Init();
2034 else if ( bIsOfficeDocument )
2036 // streams can be external OLE objects, so they are now folders, but storages!
2037 String aName( m_aURL );
2038 aName += '/';
2039 aName += String( xRow->getString(1) );
2041 Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
2042 if ( m_bRepairPackage )
2044 xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
2045 m_xProgressHandler );
2046 aName += String( RTL_CONSTASCII_USTRINGPARAM( "?repairpackage" ) );
2049 ::ucbhelper::Content aContent( aName, xComEnv );
2051 ::rtl::OUString aMediaType;
2052 Any aAny = aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
2053 if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
2054 pElement->m_bIsStorage = TRUE;
2055 else if ( !aMediaType.getLength() )
2057 // older files didn't have that special content type, so they must be detected
2058 OpenStream( pElement, STREAM_STD_READ, m_bDirect );
2059 if ( Storage::IsStorageFile( pElement->m_xStream ) )
2060 pElement->m_bIsStorage = TRUE;
2061 else
2062 pElement->m_xStream->Free();
2068 catch ( InteractiveIOException& r )
2070 if ( r.Code != IOErrorCode_NOT_EXISTING )
2071 SetError( ERRCODE_IO_GENERAL );
2073 catch ( CommandAbortedException& )
2075 // any command wasn't executed successfully - not specified
2076 if ( !( m_nMode & STREAM_WRITE ) )
2077 // if the folder was just inserted and not already commited, this is not an error!
2078 SetError( ERRCODE_IO_GENERAL );
2080 catch ( RuntimeException& )
2082 // any other error - not specified
2083 SetError( ERRCODE_IO_GENERAL );
2085 catch ( ResultSetException& )
2087 // means that the package file is broken
2088 SetError( ERRCODE_IO_BROKENPACKAGE );
2090 catch ( SQLException& )
2092 // means that the file can be broken
2093 SetError( ERRCODE_IO_WRONGFORMAT );
2095 catch ( Exception& )
2097 // any other error - not specified
2098 SetError( ERRCODE_IO_GENERAL );
2102 void UCBStorage_Impl::SetError( long nError )
2104 if ( !m_nError )
2106 m_nError = nError;
2107 if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
2111 sal_Int32 UCBStorage_Impl::GetObjectCount()
2113 sal_Int32 nCount = m_aChildrenList.Count();
2114 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2115 while ( pElement )
2117 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2118 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2119 nCount += pElement->m_xStorage->GetObjectCount();
2120 pElement = m_aChildrenList.Next();
2123 return nCount;
2126 ::rtl::OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const ::rtl::OUString& rPath )
2128 BOOL bFound = FALSE;
2129 for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
2131 const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
2132 ::rtl::OUString aType;
2134 for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
2136 const PropertyValue& rAny = rMyProps[nProps];
2137 if ( rAny.Name.equalsAscii("FullPath") )
2139 rtl::OUString aTmp;
2140 if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
2141 bFound = TRUE;
2142 if ( aType.getLength() )
2143 break;
2145 else if ( rAny.Name.equalsAscii("MediaType") )
2147 if ( ( rAny.Value >>= aType ) && aType.getLength() && bFound )
2148 break;
2152 if ( bFound )
2153 return aType;
2156 return ::rtl::OUString();
2159 void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2161 String aPath( rPath );
2162 if ( !m_bIsRoot )
2163 aPath += m_aName;
2164 aPath += '/';
2166 m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );
2168 if ( m_bIsRoot )
2169 // the "FullPath" of a child always starts without '/'
2170 aPath.Erase();
2172 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2173 while ( pElement )
2175 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2176 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2177 pElement->m_xStorage->SetProps( rSequence, aPath );
2178 else
2180 String aElementPath( aPath );
2181 aElementPath += pElement->m_aName;
2182 pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
2185 pElement = m_aChildrenList.Next();
2188 if ( m_aContentType.Len() )
2190 // get the clipboard format using the content type
2191 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2192 aDataFlavor.MimeType = m_aContentType;
2193 m_nFormat = SotExchange::GetFormat( aDataFlavor );
2195 // get the ClassId using the clipboard format ( internal table )
2196 m_aClassId = GetClassId_Impl( m_nFormat );
2198 // get human presentable name using the clipboard format
2199 SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
2200 m_aUserTypeName = aDataFlavor.HumanPresentableName;
2204 void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
2206 // first my own properties
2207 Sequence < PropertyValue > aProps(2);
2209 // first property is the "FullPath" name
2210 // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
2211 String aPath( rPath );
2212 if ( !m_bIsRoot )
2213 aPath += m_aName;
2214 aPath += '/';
2215 aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2216 aProps[0].Value <<= (::rtl::OUString ) m_aContentType;
2217 aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2218 aProps[1].Value <<= (::rtl::OUString ) aPath;
2219 rSequence[ nProps++ ] = aProps;
2221 if ( m_bIsRoot )
2222 // the "FullPath" of a child always starts without '/'
2223 aPath.Erase();
2225 // now the properties of my elements
2226 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2227 while ( pElement )
2229 DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
2230 if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
2231 // storages add there properties by themselves ( see above )
2232 pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
2233 else
2235 // properties of streams
2236 String aElementPath( aPath );
2237 aElementPath += pElement->m_aName;
2238 aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
2239 aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType();
2240 aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
2241 aProps[1].Value <<= (::rtl::OUString ) aElementPath;
2242 rSequence[ nProps++ ] = aProps;
2245 pElement = m_aChildrenList.Next();
2249 UCBStorage_Impl::~UCBStorage_Impl()
2251 if ( m_pUNOStorageHolderList )
2253 for ( UNOStorageHolderList::iterator aIter = m_pUNOStorageHolderList->begin();
2254 aIter != m_pUNOStorageHolderList->end(); aIter++ )
2255 if ( *aIter )
2257 (*aIter)->InternalDispose();
2258 (*aIter)->release();
2259 (*aIter) = NULL;
2262 m_pUNOStorageHolderList->clear();
2263 DELETEZ( m_pUNOStorageHolderList );
2266 // first delete elements!
2267 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2268 while ( pElement )
2270 delete pElement;
2271 pElement = m_aChildrenList.Next();
2274 m_aChildrenList.Clear();
2275 delete m_pContent;
2276 delete m_pTempFile;
2279 BOOL UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
2281 // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
2282 // it must be inserted with a title and a type
2283 BOOL bRet = FALSE;
2284 Reference< XContentCreator > xCreator = Reference< XContentCreator >( pContent->get(), UNO_QUERY );
2285 if ( !xCreator.is() )
2286 return sal_False;
2290 Sequence< ContentInfo > aInfo = xCreator->queryCreatableContentsInfo();
2291 sal_Int32 nCount = aInfo.getLength();
2292 if ( nCount == 0 )
2293 return sal_False;
2295 for ( sal_Int32 i = 0; i < nCount; ++i )
2297 // Simply look for the first KIND_FOLDER...
2298 const ContentInfo & rCurr = aInfo[i];
2299 if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
2301 // Make sure the only required bootstrap property is "Title",
2302 const Sequence< Property > & rProps = rCurr.Properties;
2303 if ( rProps.getLength() != 1 )
2304 continue;
2306 if ( !rProps[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
2307 continue;
2309 Sequence < ::rtl::OUString > aNames(1);
2310 ::rtl::OUString* pNames = aNames.getArray();
2311 pNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
2312 Sequence < Any > aValues(1);
2313 Any* pValues = aValues.getArray();
2314 pValues[0] = makeAny( ::rtl::OUString( m_aName ) );
2316 Content aNewFolder;
2317 if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
2318 continue;
2320 // remove old content, create an "empty" new one and initialize it with the new inserted
2321 DELETEZ( m_pContent );
2322 m_pContent = new ::ucbhelper::Content( aNewFolder );
2323 bRet = TRUE;
2327 catch ( CommandAbortedException& )
2329 // any command wasn't executed successfully - not specified
2330 SetError( ERRCODE_IO_GENERAL );
2332 catch ( RuntimeException& )
2334 // any other error - not specified
2335 SetError( ERRCODE_IO_GENERAL );
2337 catch ( Exception& )
2339 // any other error - not specified
2340 SetError( ERRCODE_IO_GENERAL );
2343 return bRet;
2346 sal_Int16 UCBStorage_Impl::Commit()
2348 // send all changes to the package
2349 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2350 sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;
2352 // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
2353 // commit command has been sent
2354 if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) )
2358 // all errors will be caught in the "catch" statement outside the loop
2359 while ( pElement && nRet )
2361 ::ucbhelper::Content* pContent = pElement->GetContent();
2362 BOOL bDeleteContent = FALSE;
2363 if ( !pContent && pElement->IsModified() )
2365 // if the element has never been opened, no content has been created until now
2366 bDeleteContent = TRUE; // remember to delete it later
2367 String aName( m_aURL );
2368 aName += '/';
2369 aName += pElement->m_aOriginalName;
2370 pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
2373 if ( pElement->m_bIsRemoved )
2375 // was it inserted, then removed (so there would be nothing to do!)
2376 if ( !pElement->m_bIsInserted )
2378 // first remove all open stream handles
2379 if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() )
2381 pContent->executeCommand( ::rtl::OUString::createFromAscii("delete"), makeAny( sal_Bool( sal_True ) ) );
2382 nRet = COMMIT_RESULT_SUCCESS;
2384 else
2385 // couldn't release stream because there are external references to it
2386 nRet = COMMIT_RESULT_FAILURE;
2389 else
2391 sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
2392 if ( pElement->m_xStorage.Is() )
2394 // element is a storage
2395 // do a commit in the following cases:
2396 // - if storage is already inserted, and changed
2397 // - storage is not in a package
2398 // - it's a new storage, try to insert and commit if successful inserted
2399 if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
2401 nLocalRet = pElement->m_xStorage->Commit();
2402 pContent = pElement->GetContent();
2405 else if ( pElement->m_xStream.Is() )
2407 // element is a stream
2408 nLocalRet = pElement->m_xStream->Commit();
2409 if ( pElement->m_xStream->m_bIsOLEStorage )
2411 // OLE storage should be stored encrytped, if the storage uses encryption
2412 pElement->m_xStream->m_aContentType = String::CreateFromAscii("application/vnd.sun.star.oleobject");
2413 Any aValue;
2414 aValue <<= (BOOL) TRUE;
2415 pElement->m_xStream->m_pContent->setPropertyValue(String::CreateFromAscii("Encrypted"), aValue );
2418 pContent = pElement->GetContent();
2421 if ( pElement->m_aName != pElement->m_aOriginalName )
2423 // name ( title ) of the element was changed
2424 nLocalRet = COMMIT_RESULT_SUCCESS;
2425 Any aAny;
2426 aAny <<= (rtl::OUString) pElement->m_aName;
2427 pContent->setPropertyValue( ::rtl::OUString::createFromAscii("Title"), aAny );
2430 if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() )
2432 // mediatype of the element was changed
2433 nLocalRet = COMMIT_RESULT_SUCCESS;
2434 Any aAny;
2435 aAny <<= (rtl::OUString) pElement->GetContentType();
2436 pContent->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
2439 if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
2440 nRet = nLocalRet;
2443 if ( bDeleteContent )
2444 // content was created inside the loop
2445 delete pContent;
2447 if ( nRet == COMMIT_RESULT_FAILURE )
2448 break;
2450 pElement = m_aChildrenList.Next();
2453 catch ( ContentCreationException& )
2455 // content could not be created
2456 SetError( ERRCODE_IO_NOTEXISTS );
2457 return COMMIT_RESULT_FAILURE;
2459 catch ( CommandAbortedException& )
2461 // any command wasn't executed successfully - not specified
2462 SetError( ERRCODE_IO_GENERAL );
2463 return COMMIT_RESULT_FAILURE;
2465 catch ( RuntimeException& )
2467 // any other error - not specified
2468 SetError( ERRCODE_IO_GENERAL );
2469 return COMMIT_RESULT_FAILURE;
2471 catch ( Exception& )
2473 // any other error - not specified
2474 SetError( ERRCODE_IO_GENERAL );
2475 return COMMIT_RESULT_FAILURE;
2478 if ( m_bIsRoot && m_pContent )
2480 // the root storage must flush the root package content
2481 if ( nRet == COMMIT_RESULT_SUCCESS )
2485 // commit the media type to the JAR file
2486 // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
2487 Any aType;
2488 aType <<= (rtl::OUString) m_aContentType;
2489 m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType );
2491 if ( m_bIsLinked )
2493 // write a manifest file
2494 // first create a subfolder "META-inf"
2495 Content aNewSubFolder;
2496 BOOL bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, String::CreateFromAscii("META-INF"), aNewSubFolder );
2497 if ( bRet )
2499 // create a stream to write the manifest file - use a temp file
2500 String aURL( aNewSubFolder.getURL() );
2501 ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL );
2503 // get the stream from the temp file and create an output stream wrapper
2504 SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE );
2505 ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
2506 com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper );
2508 // create a manifest writer object that will fill the stream
2509 Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter =
2510 Reference< ::com::sun::star::packages::manifest::XManifestWriter >
2511 ( ::comphelper::getProcessServiceFactory()->createInstance(
2512 ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestWriter" )), UNO_QUERY) ;
2513 sal_Int32 nCount = GetObjectCount() + 1;
2514 Sequence < Sequence < PropertyValue > > aProps( nCount );
2515 sal_Int32 nProps = 0;
2516 GetProps( nProps, aProps, String() );
2517 xWriter->writeManifestSequence( xOutputStream, aProps );
2519 // move the stream to its desired location
2520 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
2521 xWriter = NULL;
2522 xOutputStream = NULL;
2523 DELETEZ( pTempFile );
2524 aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE );
2527 else
2529 #if OSL_DEBUG_LEVEL > 1
2530 fprintf ( stderr, "Files: %i\n", nOpenFiles );
2531 fprintf ( stderr, "Streams: %i\n", nOpenStreams );
2532 #endif
2533 // force writing
2534 Any aAny;
2535 m_pContent->executeCommand( ::rtl::OUString::createFromAscii("flush"), aAny );
2536 if ( m_pSource != 0 )
2538 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ );
2539 m_pSource->SetStreamSize(0);
2540 // m_pSource->Seek(0);
2541 *pStream >> *m_pSource;
2542 DELETEZ( pStream );
2543 m_pSource->Seek(0);
2547 catch ( CommandAbortedException& )
2549 // how to tell the content : forget all changes ?!
2550 // or should we assume that the content does it by itself because he throwed an exception ?!
2551 // any command wasn't executed successfully - not specified
2552 SetError( ERRCODE_IO_GENERAL );
2553 return COMMIT_RESULT_FAILURE;
2555 catch ( RuntimeException& )
2557 // how to tell the content : forget all changes ?!
2558 // or should we assume that the content does it by itself because he throwed an exception ?!
2559 // any other error - not specified
2560 SetError( ERRCODE_IO_GENERAL );
2561 return COMMIT_RESULT_FAILURE;
2563 catch ( InteractiveIOException& r )
2565 if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
2566 SetError( ERRCODE_IO_ACCESSDENIED );
2567 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2568 SetError( ERRCODE_IO_NOTEXISTS );
2569 else if ( r.Code == IOErrorCode_CANT_READ )
2570 SetError( ERRCODE_IO_CANTREAD );
2571 else if ( r.Code == IOErrorCode_CANT_WRITE )
2572 SetError( ERRCODE_IO_CANTWRITE );
2573 else
2574 SetError( ERRCODE_IO_GENERAL );
2576 return COMMIT_RESULT_FAILURE;
2578 catch ( Exception& )
2580 // how to tell the content : forget all changes ?!
2581 // or should we assume that the content does it by itself because he throwed an exception ?!
2582 // any other error - not specified
2583 SetError( ERRCODE_IO_GENERAL );
2584 return COMMIT_RESULT_FAILURE;
2587 else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
2589 // how to tell the content : forget all changes ?! Should we ?!
2590 SetError( ERRCODE_IO_GENERAL );
2591 return nRet;
2594 // after successfull root commit all elements names and types are adjusted and all removed elements
2595 // are also removed from the lists
2596 UCBStorageElement_Impl* pInnerElement = m_aChildrenList.First();
2597 BOOL bRet = TRUE;
2598 while ( pInnerElement && bRet )
2600 UCBStorageElement_Impl* pNext = m_aChildrenList.Next();
2601 if ( pInnerElement->m_bIsRemoved )
2603 // is this correct use of our list class ?!
2604 m_aChildrenList.Remove( pInnerElement );
2606 else
2608 pInnerElement->m_aOriginalName = pInnerElement->m_aName;
2609 pInnerElement->m_bIsInserted = FALSE;
2612 pInnerElement = pNext;
2616 m_bCommited = FALSE;
2619 return nRet;
2622 BOOL UCBStorage_Impl::Revert()
2624 UCBStorageElement_Impl* pElement = m_aChildrenList.First();
2625 BOOL bRet = TRUE;
2626 while ( pElement && bRet )
2628 pElement->m_bIsRemoved = FALSE;
2629 if ( pElement->m_bIsInserted )
2631 m_aChildrenList.Remove( pElement ); // correct usage of list ???
2633 else
2635 if ( pElement->m_xStream.Is() )
2637 pElement->m_xStream->m_bCommited = sal_False;
2638 pElement->m_xStream->Revert();
2640 else if ( pElement->m_xStorage.Is() )
2642 pElement->m_xStorage->m_bCommited = sal_False;
2643 pElement->m_xStorage->Revert();
2646 pElement->m_aName = pElement->m_aOriginalName;
2647 pElement->m_bIsRemoved = FALSE;
2650 pElement = m_aChildrenList.Next();
2653 return bRet;
2656 const String& UCBStorage::GetName() const
2658 return pImp->m_aName; // pImp->m_aURL ?!
2661 BOOL UCBStorage::IsRoot() const
2663 return pImp->m_bIsRoot;
2666 void UCBStorage::SetDirty()
2668 pImp->m_bDirty = TRUE;
2671 void UCBStorage::SetClass( const SvGlobalName & rClass, ULONG nOriginalClipFormat, const String & rUserTypeName )
2673 pImp->m_aClassId = rClass;
2674 pImp->m_nFormat = nOriginalClipFormat;
2675 pImp->m_aUserTypeName = rUserTypeName;
2677 // in UCB storages only the content type will be stored, all other information can be reconstructed
2678 // ( see the UCBStorage_Impl::Init() method )
2679 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2680 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2681 pImp->m_aContentType = aDataFlavor.MimeType;
2684 void UCBStorage::SetClassId( const ClsId& rClsId )
2686 pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId );
2687 if ( pImp->m_aClassId == SvGlobalName() )
2688 return;
2690 // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
2691 // stored in one the substreams
2692 // UCB storages store the content type information as content type in the manifest file and so this information must be
2693 // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
2694 // the content type
2695 pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
2696 if ( pImp->m_nFormat )
2698 ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
2699 SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
2700 pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
2701 pImp->m_aContentType = aDataFlavor.MimeType;
2705 const ClsId& UCBStorage::GetClassId() const
2707 return ( const ClsId& ) pImp->m_aClassId.GetCLSID();
2710 void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, ULONG /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ )
2712 // ???
2715 BOOL UCBStorage::ShouldConvert()
2717 // ???
2718 return FALSE;
2721 SvGlobalName UCBStorage::GetClassName()
2723 return pImp->m_aClassId;
2726 ULONG UCBStorage::GetFormat()
2728 return pImp->m_nFormat;
2731 String UCBStorage::GetUserName()
2733 DBG_ERROR("UserName is not implemented in UCB storages!" );
2734 return pImp->m_aUserTypeName;
2737 void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
2739 // put information in childrenlist into StorageInfoList
2740 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2741 while ( pElement )
2743 if ( !pElement->m_bIsRemoved )
2745 // problem: what about the size of a substorage ?!
2746 ULONG nSize = pElement->m_nSize;
2747 if ( pElement->m_xStream.Is() )
2748 nSize = pElement->m_xStream->GetSize();
2749 SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
2750 pList->Append( aInfo );
2753 pElement = pImp->m_aChildrenList.Next();
2757 BOOL UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const String& rNew ) const
2759 // insert stream or storage into the list or stream of the destination storage
2760 // not into the content, this will be done on commit !
2761 // be aware of name changes !
2762 if ( !rElement.m_bIsStorage )
2764 // copy the streams data
2765 // the destination stream must not be open
2766 BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2767 BaseStorageStream* pStream = NULL;
2768 BOOL bDeleteStream = FALSE;
2770 // if stream is already open, it is allowed to copy it, so be aware of this
2771 if ( rElement.m_xStream.Is() )
2772 pStream = rElement.m_xStream->m_pAntiImpl;
2773 if ( !pStream )
2775 pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect );
2776 bDeleteStream = TRUE;
2779 pStream->CopyTo( pOtherStream );
2780 SetError( pStream->GetError() );
2781 if( pOtherStream->GetError() )
2782 pDest->SetError( pOtherStream->GetError() );
2783 else
2784 pOtherStream->Commit();
2786 if ( bDeleteStream )
2787 delete pStream;
2788 delete pOtherStream;
2790 else
2792 // copy the storage content
2793 // the destination storage must not be open
2794 BaseStorage* pStorage = NULL;
2796 // if stream is already open, it is allowed to copy it, so be aware of this
2797 BOOL bDeleteStorage = FALSE;
2798 if ( rElement.m_xStorage.Is() )
2799 pStorage = rElement.m_xStorage->m_pAntiImpl;
2800 if ( !pStorage )
2802 pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
2803 bDeleteStorage = TRUE;
2806 UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
2807 UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );
2809 BOOL bOpenUCBStorage = pUCBDest && pUCBCopy;
2810 BaseStorage* pOtherStorage = bOpenUCBStorage ?
2811 pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) :
2812 pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
2814 // For UCB storages, the class id and the format id may differ,
2815 // do passing the class id is not sufficient.
2816 if( bOpenUCBStorage )
2817 pOtherStorage->SetClass( pStorage->GetClassName(),
2818 pStorage->GetFormat(),
2819 pUCBCopy->pImp->m_aUserTypeName );
2820 else
2821 pOtherStorage->SetClassId( pStorage->GetClassId() );
2822 pStorage->CopyTo( pOtherStorage );
2823 SetError( pStorage->GetError() );
2824 if( pOtherStorage->GetError() )
2825 pDest->SetError( pOtherStorage->GetError() );
2826 else
2827 pOtherStorage->Commit();
2829 if ( bDeleteStorage )
2830 delete pStorage;
2831 delete pOtherStorage;
2834 return BOOL( Good() && pDest->Good() );
2837 UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const String& rName ) const
2839 DBG_ASSERT( rName.Len(), "Name is empty!" );
2840 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2841 while ( pElement )
2843 if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
2844 break;
2845 pElement = pImp->m_aChildrenList.Next();
2848 return pElement;
2851 BOOL UCBStorage::CopyTo( BaseStorage* pDestStg ) const
2853 DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
2854 if ( pDestStg == ((BaseStorage*)this) )
2855 return FALSE;
2857 // perhaps it's also a problem if one storage is a parent of the other ?!
2858 // or if not: could be optimized ?!
2860 // For UCB storages, the class id and the format id may differ,
2861 // do passing the class id is not sufficient.
2862 if( pDestStg->ISA( UCBStorage ) )
2863 pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
2864 pImp->m_aUserTypeName );
2865 else
2866 pDestStg->SetClassId( GetClassId() );
2867 pDestStg->SetDirty();
2869 BOOL bRet = TRUE;
2870 UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
2871 while ( pElement && bRet )
2873 if ( !pElement->m_bIsRemoved )
2874 bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
2875 pElement = pImp->m_aChildrenList.Next();
2878 if( !bRet )
2879 SetError( pDestStg->GetError() );
2880 return BOOL( Good() && pDestStg->Good() );
2883 BOOL UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew )
2885 if( !rElemName.Len() )
2886 return FALSE;
2888 if ( pDest == ((BaseStorage*) this) )
2890 // can't double an element
2891 return FALSE;
2893 else
2895 // for copying no optimization is usefull, because in every case the stream data must be copied
2896 UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
2897 if ( pElement )
2898 return CopyStorageElement_Impl( *pElement, pDest, rNew );
2899 else
2901 SetError( SVSTREAM_FILE_NOT_FOUND );
2902 return FALSE;
2907 BOOL UCBStorage::Commit()
2909 // mark this storage for sending it on root commit
2910 pImp->m_bCommited = TRUE;
2911 if ( pImp->m_bIsRoot )
2912 // the root storage coordinates commiting by sending a Commit command to its content
2913 return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
2914 else
2915 return TRUE;
2918 BOOL UCBStorage::Revert()
2920 return pImp->Revert();
2923 BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, BOOL bDirect, const ByteString* pKey )
2925 if( !rEleName.Len() )
2926 return NULL;
2928 // try to find the storage element
2929 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
2930 if ( !pElement )
2932 // element does not exist, check if creation is allowed
2933 if( ( nMode & STREAM_NOCREATE ) )
2935 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
2936 String aName( pImp->m_aURL );
2937 aName += '/';
2938 aName += rEleName;
2939 UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
2940 pStream->SetError( GetError() );
2941 pStream->pImp->m_aName = rEleName;
2942 return pStream;
2944 else
2946 // create a new UCBStorageElement and insert it into the list
2947 pElement = new UCBStorageElement_Impl( rEleName );
2948 pElement->m_bIsInserted = TRUE;
2949 pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
2953 if ( pElement && !pElement->m_bIsFolder )
2955 // check if stream is already created
2956 if ( pElement->m_xStream.Is() )
2958 // stream has already been created; if it has no external reference, it may be opened another time
2959 if ( pElement->m_xStream->m_pAntiImpl )
2961 DBG_ERROR("Stream is already open!" );
2962 SetError( SVSTREAM_ACCESS_DENIED ); // ???
2963 return NULL;
2965 else
2967 // check if stream is opened with the same keyword as before
2968 // if not, generate a new stream because it could be encrypted vs. decrypted!
2969 ByteString aKey;
2970 if ( pKey )
2971 aKey = *pKey;
2972 if ( pElement->m_xStream->m_aKey == aKey )
2974 pElement->m_xStream->PrepareCachedForReopen( nMode );
2976 // DBG_ASSERT( bDirect == pElement->m_xStream->m_bDirect, "Wrong DirectMode!" );
2977 return new UCBStorageStream( pElement->m_xStream );
2982 // stream is opened the first time
2983 pImp->OpenStream( pElement, nMode, bDirect, pKey );
2985 // if name has been changed before creating the stream: set name!
2986 pElement->m_xStream->m_aName = rEleName;
2987 return new UCBStorageStream( pElement->m_xStream );
2990 return NULL;
2993 UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, BOOL bDirect, const ByteString* pKey )
2995 String aName( m_aURL );
2996 aName += '/';
2997 aName += pElement->m_aOriginalName;
2998 pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler );
2999 return pElement->m_xStream;
3002 BaseStorage* UCBStorage::OpenUCBStorage( const String& rEleName, StreamMode nMode, BOOL bDirect )
3004 if( !rEleName.Len() )
3005 return NULL;
3007 return OpenStorage_Impl( rEleName, nMode, bDirect, TRUE );
3010 BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, BOOL bDirect )
3012 if( !rEleName.Len() )
3013 return NULL;
3015 return OpenStorage_Impl( rEleName, nMode, bDirect, FALSE );
3018 BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, BOOL bDirect )
3020 if( !rEleName.Len() )
3021 return NULL;
3023 return OpenStorage_Impl( rEleName, nMode, bDirect, TRUE );
3026 BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, BOOL bDirect, BOOL bForceUCBStorage )
3028 // try to find the storage element
3029 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3030 if ( !pElement )
3032 // element does not exist, check if creation is allowed
3033 if( ( nMode & STREAM_NOCREATE ) )
3035 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3036 String aName( pImp->m_aURL );
3037 aName += '/';
3038 aName += rEleName; // ???
3039 UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, FALSE, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3040 pStorage->pImp->m_bIsRoot = FALSE;
3041 pStorage->pImp->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3042 pStorage->SetError( GetError() );
3043 return pStorage;
3046 // create a new UCBStorageElement and insert it into the list
3047 // problem: perhaps an OLEStorage should be created ?!
3048 // Because nothing is known about the element that should be created, an external parameter is needed !
3049 pElement = new UCBStorageElement_Impl( rEleName );
3050 pElement->m_bIsInserted = TRUE;
3051 pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
3054 if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
3056 // create OLE storages on a stream ( see ctor of SotStorage )
3057 // Such a storage will be created on a UCBStorageStream; it will write into the stream
3058 // if it is opened in direct mode or when it is committed. In this case the stream will be
3059 // modified and then it MUST be treated as commited.
3060 if ( !pElement->m_xStream.Is() )
3062 BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
3063 UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr );
3064 if ( !pStream )
3066 SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
3067 return NULL;
3070 pElement->m_xStream = pStream->pImp;
3071 delete pStream;
3074 pElement->m_xStream->PrepareCachedForReopen( nMode );
3075 pElement->m_xStream->Init();
3077 pElement->m_bIsStorage = TRUE;
3078 return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode
3080 else if ( pElement->m_xStorage.Is() )
3082 // storage has already been opened; if it has no external reference, it may be opened another time
3083 if ( pElement->m_xStorage->m_pAntiImpl )
3085 DBG_ERROR("Storage is already open!" );
3086 SetError( SVSTREAM_ACCESS_DENIED ); // ???
3088 else
3090 BOOL bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0);
3091 if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 ))
3093 String aName( pImp->m_aURL );
3094 aName += '/';
3095 aName += pElement->m_aOriginalName;
3096 UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, FALSE, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
3097 pElement->m_xStorage = pStorage->pImp;
3098 return pStorage;
3100 else
3102 // DBG_ASSERT( bDirect == pElement->m_xStorage->m_bDirect, "Wrong DirectMode!" );
3103 return new UCBStorage( pElement->m_xStorage );
3107 else if ( !pElement->m_xStream.Is() )
3109 // storage is opened the first time
3110 BOOL bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 );
3111 if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
3113 // make sure that the root storage object has been created before substorages will be created
3114 INetURLObject aFolderObj( pImp->m_aURL );
3115 String aName = aFolderObj.GetName();
3116 aFolderObj.removeSegment();
3118 Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >() );
3119 pImp->m_pContent = new Content;
3120 BOOL bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
3121 if ( !bRet )
3123 SetError( SVSTREAM_CANNOT_MAKE );
3124 return NULL;
3128 UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
3129 if ( pStor )
3131 if ( pElement->m_bIsInserted )
3132 pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
3134 return new UCBStorage( pStor );
3138 return NULL;
3141 UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, BOOL bDirect )
3143 UCBStorage_Impl* pRet = NULL;
3144 String aName( m_aURL );
3145 aName += '/';
3146 aName += pElement->m_aOriginalName; // ???
3148 pElement->m_bIsStorage = pElement->m_bIsFolder = TRUE;
3150 if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
3152 Content aNewFolder;
3153 BOOL bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
3154 if ( bRet )
3155 pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, FALSE, m_bRepairPackage, m_xProgressHandler );
3157 else
3159 pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, FALSE, m_bRepairPackage, m_xProgressHandler );
3162 if ( pRet )
3164 pRet->m_bIsLinked = m_bIsLinked;
3165 pRet->m_bIsRoot = FALSE;
3167 // if name has been changed before creating the stream: set name!
3168 pRet->m_aName = pElement->m_aOriginalName;
3169 pElement->m_xStorage = pRet;
3172 if ( pRet )
3173 pRet->Init();
3175 return pRet;
3178 BOOL UCBStorage::IsStorage( const String& rEleName ) const
3180 if( !rEleName.Len() )
3181 return FALSE;
3183 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3184 return ( pElement && pElement->m_bIsStorage );
3187 BOOL UCBStorage::IsStream( const String& rEleName ) const
3189 if( !rEleName.Len() )
3190 return FALSE;
3192 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3193 return ( pElement && !pElement->m_bIsStorage );
3196 BOOL UCBStorage::IsContained( const String & rEleName ) const
3198 if( !rEleName.Len() )
3199 return FALSE;
3200 const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3201 return ( pElement != NULL );
3204 BOOL UCBStorage::Remove( const String& rEleName )
3206 if( !rEleName.Len() )
3207 return FALSE;
3209 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3210 if ( pElement )
3212 pElement->m_bIsRemoved = TRUE;
3214 else
3215 SetError( SVSTREAM_FILE_NOT_FOUND );
3217 return ( pElement != NULL );
3220 BOOL UCBStorage::Rename( const String& rEleName, const String& rNewName )
3222 if( !rEleName.Len()|| !rNewName.Len() )
3223 return FALSE;
3225 UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
3226 if ( pAlreadyExisting )
3228 SetError( SVSTREAM_ACCESS_DENIED );
3229 return FALSE; // can't change to a name that is already used
3232 UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
3233 if ( pElement )
3235 pElement->m_aName = rNewName;
3237 else
3238 SetError( SVSTREAM_FILE_NOT_FOUND );
3240 return pElement != NULL;
3243 BOOL UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName )
3245 if( !rEleName.Len() || !rNewName.Len() )
3246 return FALSE;
3248 if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
3250 return Rename( rEleName, rNewName );
3252 else
3255 if ( PTR_CAST( UCBStorage, pNewSt ) )
3257 // because the element is moved, not copied, a special optimization is possible :
3258 // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
3259 // clear original name/type of the new element
3260 // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
3261 // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
3262 // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
3263 // belong to the new content
3264 // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
3265 // stream of the destination object
3266 // Not implemented at the moment ( risky?! ), perhaps later
3269 // MoveTo is done by first copying to the new destination and then removing the old element
3270 BOOL bRet = CopyTo( rEleName, pNewSt, rNewName );
3271 if ( bRet )
3272 bRet = Remove( rEleName );
3273 return bRet;
3277 BOOL UCBStorage::ValidateFAT()
3279 // ???
3280 return TRUE;
3283 BOOL UCBStorage::Validate( BOOL bWrite ) const
3285 // ???
3286 return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
3289 BOOL UCBStorage::ValidateMode( StreamMode m ) const
3291 // ???
3292 if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
3293 return TRUE;
3294 USHORT nCurMode = 0xFFFF;
3295 if( ( m & 3 ) == STREAM_READ )
3297 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
3298 if( ( ( m & STREAM_SHARE_DENYWRITE )
3299 && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
3300 || ( ( m & STREAM_SHARE_DENYALL )
3301 && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
3302 return TRUE;
3304 else
3306 // only SHARE_DENYALL allowed
3307 // storages open in r/o mode are OK, since only
3308 // the commit may fail
3309 if( ( m & STREAM_SHARE_DENYALL )
3310 && ( nCurMode & STREAM_SHARE_DENYALL ) )
3311 return TRUE;
3314 return TRUE;
3317 const SvStream* UCBStorage::GetSvStream() const
3319 // this would cause a complete download of the file
3320 // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
3321 return pImp->m_pSource;
3324 BOOL UCBStorage::Equals( const BaseStorage& rStorage ) const
3326 // ???
3327 return ((BaseStorage*)this) == &rStorage;
3330 BOOL UCBStorage::IsStorageFile( const String& rFileName )
3332 String aFileURL = rFileName;
3333 INetURLObject aObj( aFileURL );
3334 if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
3336 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFileName, aFileURL );
3337 aObj.SetURL( aFileURL );
3338 aFileURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3341 SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_STD_READ );
3342 BOOL bRet = UCBStorage::IsStorageFile( pStm );
3343 delete pStm;
3344 return bRet;
3347 BOOL UCBStorage::IsStorageFile( SvStream* pFile )
3349 if ( !pFile )
3350 return FALSE;
3352 ULONG nPos = pFile->Tell();
3353 pFile->Seek( STREAM_SEEK_TO_END );
3354 if ( pFile->Tell() < 4 )
3355 return FALSE;
3357 pFile->Seek(0);
3358 UINT32 nBytes;
3359 *pFile >> nBytes;
3361 // search for the magic bytes
3362 BOOL bRet = ( nBytes == 0x04034b50 );
3363 if ( !bRet )
3365 // disk spanned file have an additional header in front of the usual one
3366 bRet = ( nBytes == 0x08074b50 );
3367 if ( bRet )
3369 *pFile >> nBytes;
3370 bRet = ( nBytes == 0x04034b50 );
3374 pFile->Seek( nPos );
3375 return bRet;
3378 BOOL UCBStorage::IsDiskSpannedFile( SvStream* pFile )
3380 if ( !pFile )
3381 return FALSE;
3383 ULONG nPos = pFile->Tell();
3384 pFile->Seek( STREAM_SEEK_TO_END );
3385 if ( !pFile->Tell() )
3386 return FALSE;
3388 pFile->Seek(0);
3389 UINT32 nBytes;
3390 *pFile >> nBytes;
3392 // disk spanned file have an additional header in front of the usual one
3393 BOOL bRet = ( nBytes == 0x08074b50 );
3394 if ( bRet )
3396 *pFile >> nBytes;
3397 bRet = ( nBytes == 0x04034b50 );
3400 pFile->Seek( nPos );
3401 return bRet;
3404 String UCBStorage::GetLinkedFile( SvStream &rStream )
3406 String aString;
3407 ULONG nPos = rStream.Tell();
3408 rStream.Seek( STREAM_SEEK_TO_END );
3409 if ( !rStream.Tell() )
3410 return aString;
3412 rStream.Seek(0);
3413 UINT32 nBytes;
3414 rStream >> nBytes;
3415 if( nBytes == 0x04034b50 )
3417 ByteString aTmp;
3418 rStream.ReadByteString( aTmp );
3419 if ( aTmp.CompareTo( "ContentURL=", 11 ) == COMPARE_EQUAL )
3421 aTmp.Erase( 0, 11 );
3422 aString = String( aTmp, RTL_TEXTENCODING_UTF8 );
3426 rStream.Seek( nPos );
3427 return aString;
3430 String UCBStorage::CreateLinkFile( const String& rName )
3432 // create a stream to write the link file - use a temp file, because it may be no file content
3433 INetURLObject aFolderObj( rName );
3434 String aName = aFolderObj.GetName();
3435 aFolderObj.removeSegment();
3436 String aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) );
3437 ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL );
3439 // get the stream from the temp file
3440 SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC );
3442 // write header
3443 *pStream << ( UINT32 ) 0x04034b50;
3445 // assemble a new folder name in the destination folder
3446 INetURLObject aObj( rName );
3447 String aTmpName = aObj.GetName();
3448 String aTitle = String::CreateFromAscii( "content." );
3449 aTitle += aTmpName;
3451 // create a folder and store its URL
3452 Content aFolder( aFolderURL, Reference < XCommandEnvironment >() );
3453 Content aNewFolder;
3454 BOOL bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
3455 if ( !bRet )
3457 aFolderObj.insertName( aTitle );
3458 if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3460 // Hack, because already existing files give the same CommandAbortedException as any other error !
3461 // append a number until the name can be used for a new folder
3462 aTitle += '.';
3463 for ( sal_Int32 i=0; !bRet; i++ )
3465 String aTmp( aTitle );
3466 aTmp += String::CreateFromInt32( i );
3467 bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder );
3468 if ( bRet )
3469 aTitle = aTmp;
3470 else
3472 aFolderObj.SetName( aTmp );
3473 if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
3474 // Hack, because already existing files give the same CommandAbortedException as any other error !
3475 break;
3481 if ( bRet )
3483 // get the URL
3484 aObj.SetName( aTitle );
3485 String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
3487 // store it as key/value pair
3488 String aLink = String::CreateFromAscii("ContentURL=");
3489 aLink += aURL;
3490 pStream->WriteByteString( aLink, RTL_TEXTENCODING_UTF8 );
3491 pStream->Flush();
3493 // move the stream to its desired location
3494 Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
3495 DELETEZ( pTempFile );
3496 aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE );
3497 return aURL;
3500 pTempFile->EnableKillingFile( TRUE );
3501 delete pTempFile;
3502 return String();
3505 BOOL UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
3507 if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
3508 return FALSE;
3510 if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
3512 ::rtl::OUString aTmp;
3513 rValue >>= aTmp;
3514 pImp->m_aContentType = aTmp;
3519 if ( pImp->GetContent() )
3521 pImp->m_pContent->setPropertyValue( rName, rValue );
3522 return TRUE;
3525 catch ( Exception& )
3529 return FALSE;
3532 BOOL UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
3536 if ( pImp->GetContent() )
3538 rValue = pImp->m_pContent->getPropertyValue( rName );
3539 return TRUE;
3542 catch ( Exception& )
3546 return FALSE;
3549 BOOL UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
3551 UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName );
3552 if ( !pEle )
3553 return FALSE;
3555 if ( !pEle->m_bIsFolder )
3557 if ( !pEle->m_xStream.Is() )
3558 pImp->OpenStream( pEle, pImp->m_nMode, pImp->m_bDirect );
3559 if ( pEle->m_xStream->m_nError )
3561 pEle->m_xStream.Clear();
3562 return FALSE;
3567 if ( pEle->m_xStream->m_pContent )
3569 rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName );
3570 return TRUE;
3573 catch ( Exception& )
3577 else
3579 if ( !pEle->m_xStorage.Is() )
3580 pImp->OpenStorage( pEle, pImp->m_nMode, pImp->m_bDirect );
3581 if ( pEle->m_xStorage->m_nError )
3583 pEle->m_xStorage.Clear();
3584 return FALSE;
3589 if ( pEle->m_xStorage->GetContent() )
3591 rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName );
3592 return TRUE;
3595 catch ( Exception& )
3600 return FALSE;
3603 UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList()
3605 if ( !pImp->m_pUNOStorageHolderList )
3606 pImp->m_pUNOStorageHolderList = new UNOStorageHolderList;
3608 return pImp->m_pUNOStorageHolderList;