1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ucbstorage.cxx,v $
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>
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>
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>
77 #include "storinfo.hxx"
78 #include <sot/storage.hxx>
79 #include <sot/exchange.hxx>
80 #include <sot/formats.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
95 static int nOpenFiles
=0;
96 static int nOpenStreams
=0;
99 typedef ::cppu::WeakImplHelper2
< XInputStream
, XSeekable
> FileInputStreamWrapper_Base
;
100 class FileStreamWrapper_Impl
: public FileInputStreamWrapper_Base
103 ::osl::Mutex m_aMutex
;
105 SvStream
* m_pSvStream
;
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
);
123 void checkConnected();
127 //------------------------------------------------------------------
128 FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String
& rName
)
132 // if no URL is provided the stream is empty
135 //------------------------------------------------------------------
136 FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
141 #if OSL_DEBUG_LEVEL > 1
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
)
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
);
172 // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
173 if (nRead
< (sal_uInt32
)nBytesToRead
)
174 aData
.realloc( nRead
);
179 //------------------------------------------------------------------------------
180 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
190 if (nMaxBytesToRead
< 0)
191 throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak
*>(this));
193 if (m_pSvStream
->IsEof())
199 return readBytes(aData
, nMaxBytesToRead
);
202 //------------------------------------------------------------------------------
203 void SAL_CALL
FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip
) throw( NotConnectedException
, BufferSizeExceededException
, RuntimeException
)
208 ::osl::MutexGuard
aGuard( m_aMutex
);
212 sal_uInt32 nCurrentPos
= m_pSvStream
->Tell();
215 m_pSvStream
->SeekRel(nBytesToSkip
);
219 nCurrentPos
= m_pSvStream
->Tell();
223 //------------------------------------------------------------------------------
224 sal_Int32 SAL_CALL
FileStreamWrapper_Impl::available() throw( NotConnectedException
, RuntimeException
)
229 ::osl::MutexGuard
aGuard( m_aMutex
);
232 sal_uInt32 nPos
= m_pSvStream
->Tell();
235 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
238 sal_Int32 nAvailable
= (sal_Int32
)m_pSvStream
->Tell() - nPos
;
239 m_pSvStream
->Seek(nPos
);
245 //------------------------------------------------------------------------------
246 void SAL_CALL
FileStreamWrapper_Impl::closeInput() throw( NotConnectedException
, RuntimeException
)
251 ::osl::MutexGuard
aGuard( m_aMutex
);
253 DELETEZ( m_pSvStream
);
254 #if OSL_DEBUG_LEVEL > 1
257 ::utl::UCBContentHelper::Kill( m_aURL
);
261 //------------------------------------------------------------------------------
262 void SAL_CALL
FileStreamWrapper_Impl::seek( sal_Int64 _nLocation
) throw (IllegalArgumentException
, IOException
, RuntimeException
)
267 ::osl::MutexGuard
aGuard( m_aMutex
);
270 m_pSvStream
->Seek((sal_uInt32
)_nLocation
);
274 //------------------------------------------------------------------------------
275 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getPosition( ) throw (IOException
, RuntimeException
)
280 ::osl::MutexGuard
aGuard( m_aMutex
);
283 sal_uInt32 nPos
= m_pSvStream
->Tell();
285 return (sal_Int64
)nPos
;
288 //------------------------------------------------------------------------------
289 sal_Int64 SAL_CALL
FileStreamWrapper_Impl::getLength( ) throw (IOException
, RuntimeException
)
294 ::osl::MutexGuard
aGuard( m_aMutex
);
297 sal_uInt32 nCurrentPos
= m_pSvStream
->Tell();
300 m_pSvStream
->Seek(STREAM_SEEK_TO_END
);
301 sal_uInt32 nEndPos
= m_pSvStream
->Tell();
302 m_pSvStream
->Seek(nCurrentPos
);
306 return (sal_Int64
)nEndPos
;
309 //------------------------------------------------------------------------------
310 void FileStreamWrapper_Impl::checkConnected()
313 throw NotConnectedException(::rtl::OUString(), const_cast<XWeak
*>(static_cast<const XWeak
*>(this)));
316 m_pSvStream
= ::utl::UcbStreamHelper::CreateStream( m_aURL
, STREAM_STD_READ
);
317 #if OSL_DEBUG_LEVEL > 1
323 //------------------------------------------------------------------------------
324 void FileStreamWrapper_Impl::checkError()
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
385 DBG_ERROR( "Unknown UCB storage format!" );
391 SvGlobalName
GetClassId_Impl( sal_Int32 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
);
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
{
448 class UCBStorageStream_Impl
: public SvRefBase
, public SvStream
450 ~UCBStorageStream_Impl();
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
;
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
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
>() );
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
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
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
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
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
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
; // ???
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
);
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();
569 void CreateContent();
570 ::ucbhelper::Content
* GetContent()
571 { if ( !m_pContent
) CreateContent(); return m_pContent
; }
572 UCBStorageElementList_Impl
& GetChildrenList()
574 long nError
= m_nError
;
576 if ( m_nMode
& STREAM_WRITE
)
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
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 )
610 , m_aOriginalName( rName
)
612 , m_bIsFolder( bIsFolder
)
613 , m_bIsStorage( bIsFolder
)
614 , m_bIsRemoved( FALSE
)
615 , m_bIsInserted( FALSE
)
619 ::ucbhelper::Content
* GetContent();
621 String
GetContentType();
622 void SetContentType( const String
& );
623 String
GetOriginalContentType();
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();
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
;
646 DBG_ERROR("Element not loaded!");
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
;
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
;
674 BOOL
UCBStorageElement_Impl::IsModified()
676 BOOL bModified
= m_bIsRemoved
|| m_bIsInserted
|| m_aName
!= m_aOriginalName
;
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
;
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
)
693 , m_nRepresentMode( nonset
)
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
);
714 xComEnv
= new ::ucbhelper::CommandEnvironment( Reference
< ::com::sun::star::task::XInteractionHandler
>(),
716 aTemp
+= rtl::OUString::createFromAscii("?repairpackage");
719 m_pContent
= new ::ucbhelper::Content( aTemp
, xComEnv
);
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
;
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()
753 m_rSource
= Reference
< XInputStream
>();
758 if ( m_aTempURL
.Len() )
759 ::utl::UCBContentHelper::Kill( m_aTempURL
);
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
);
779 // use wrapper around temporary stream
782 CopySourceToTemporary();
784 // owner transfer of stream to wrapper
785 aResult
= new ::utl::OInputStreamWrapper( m_pStream
, TRUE
);
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
794 m_nRepresentMode
= xinputstream
;
802 // open a new instance of XInputStream
805 aResult
= m_pContent
->openStream();
809 // usually means that stream could not be opened
813 m_nRepresentMode
= xinputstream
;
815 SetError( ERRCODE_IO_ACCESSDENIED
);
822 BOOL
UCBStorageStream_Impl::Init()
824 if( m_nRepresentMode
== xinputstream
)
826 DBG_ERROR( "XInputStream misuse!" );
827 SetError( ERRCODE_IO_ACCESSDENIED
);
833 // no temporary stream was created
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
848 DBG_ERROR( "Suspicious temporary stream creation!" );
849 SetError( SVSTREAM_CANNOT_MAKE
);
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();
867 // usually means that stream could not be opened
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
;
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 );
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!" );
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
915 Sequence
<sal_Int8
> aData(32000);
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() );
937 m_bSourceRead
= FALSE
;
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
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() );
983 ULONG
UCBStorageStream_Impl::CopySourceToTemporary()
985 // current position of the temporary stream is not changed
990 ULONG aPos
= m_pStream
->Tell();
991 m_pStream
->Seek( STREAM_SEEK_TO_END
);
992 aResult
= ReadSourceWriteTemporary();
993 m_pStream
->Seek( aPos
);
1001 ULONG
UCBStorageStream_Impl::CopySourceToTemporary( ULONG aLength
)
1003 // current position of the temporary stream is not changed
1008 ULONG aPos
= m_pStream
->Tell();
1009 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1010 aResult
= ReadSourceWriteTemporary( aLength
);
1011 m_pStream
->Seek( aPos
);
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
)
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() );
1051 catch( Exception
& )
1056 if( aResult
< nSize
)
1057 m_bSourceRead
= FALSE
;
1063 ULONG
UCBStorageStream_Impl::PutData( const void* pData
, ULONG nSize
)
1065 if ( !(m_nMode
& STREAM_WRITE
) )
1067 SetError( ERRCODE_IO_ACCESSDENIED
);
1071 if( !nSize
|| !Init() )
1074 ULONG aResult
= m_pStream
->Write( pData
, nSize
);
1076 m_bModified
= aResult
> 0;
1082 ULONG
UCBStorageStream_Impl::SeekPos( ULONG nPos
)
1089 if( nPos
== STREAM_SEEK_TO_END
)
1091 m_pStream
->Seek( STREAM_SEEK_TO_END
);
1092 ReadSourceWriteTemporary();
1093 aResult
= m_pStream
->Tell();
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
);
1109 // the temp stream pointer points to the end now
1110 aResult
= m_pStream
->Tell();
1112 if( aResult
< nPos
)
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" );
1139 void UCBStorageStream_Impl::SetSize( ULONG nSize
)
1141 if ( !(m_nMode
& STREAM_WRITE
) )
1143 SetError( ERRCODE_IO_ACCESSDENIED
);
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()
1169 CopySourceToTemporary();
1176 void UCBStorageStream_Impl::SetError( sal_uInt32 nErr
)
1181 SvStream::SetError( nErr
);
1182 if ( m_pAntiImpl
) m_pAntiImpl
->SetError( nErr
);
1186 void UCBStorageStream_Impl::ResetError()
1189 SvStream::ResetError();
1191 m_pAntiImpl
->ResetError();
1194 ULONG
UCBStorageStream_Impl::GetSize()
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
);
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 )
1236 CopySourceToTemporary();
1238 // release all stream handles
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
);
1250 InsertCommandArgument aArg
;
1251 aArg
.Data
= xStream
;
1252 aArg
.ReplaceExisting
= sal_True
;
1254 m_pContent
->executeCommand( ::rtl::OUString::createFromAscii("insert"), aAny
);
1256 // wrapper now controls lifetime of temporary file
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" !
1297 DBG_ERROR("Revert while commit is in progress!" );
1298 return FALSE
; // ???
1302 if ( m_aTempURL
.Len() )
1304 ::utl::UCBContentHelper::Kill( m_aTempURL
);
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
;
1319 m_nMode
&= ~STREAM_TRUNC
;
1320 m_bSourceRead
= TRUE
;
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!" );
1356 void UCBStorageStream_Impl::Free()
1358 #if OSL_DEBUG_LEVEL > 1
1361 if ( m_aTempURL
.Len() )
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 );
1378 // once stream was writable, never reset to readonly
1379 nMode
|= STREAM_WRITE
;
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
);
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
)
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
)
1428 pImp
->m_pAntiImpl
= NULL
;
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!" );
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()
1464 return pImp
->m_pStream
->Tell();
1467 void UCBStorageStream::Flush()
1469 // streams are never really transacted, so flush also means commit !
1473 BOOL
UCBStorageStream::SetSize( ULONG nNewSize
)
1476 if ( pImp->m_bCommited )
1478 DBG_ERROR("Changing stream size while commit is in progress!" );
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
1496 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
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
) ) )
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
) )
1521 const SvStream
* UCBStorageStream::GetSvStream() const
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
1543 return ((BaseStorageStream
*) this ) == &rStream
;
1546 BOOL
UCBStorageStream::Commit()
1548 // mark this stream for sending it on root commit
1553 BOOL
UCBStorageStream::Revert()
1555 return pImp
->Revert();
1558 BOOL
UCBStorageStream::CopyTo( BaseStorageStream
* pDestStm
)
1563 UCBStorageStream
* pStg
= PTR_CAST( UCBStorageStream
, pDestStm
);
1565 pStg
->pImp
->m_aContentType
= pImp
->m_aContentType
;
1567 pDestStm
->SetSize( 0 );
1568 Seek( STREAM_SEEK_TO_END
);
1573 if( pDestStm
->SetSize( n
) && n
)
1575 BYTE
* p
= new BYTE
[ 4096 ];
1577 pDestStm
->Seek( 0L );
1583 if( Read( p
, nn
) != nn
)
1585 if( pDestStm
->Write( p
, nn
) != nn
)
1596 BOOL
UCBStorageStream::SetProperty( const String
& rName
, const ::com::sun::star::uno::Any
& rValue
)
1598 if ( rName
.CompareToAscii("Title") == COMPARE_EQUAL
)
1601 if ( rName
.CompareToAscii("MediaType") == COMPARE_EQUAL
)
1603 ::rtl::OUString aTmp
;
1605 pImp
->m_aContentType
= aTmp
;
1610 if ( pImp
->m_pContent
)
1612 pImp
->m_pContent
->setPropertyValue( rName
, rValue
);
1616 catch ( Exception
& )
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
);
1633 catch ( Exception
& )
1640 UCBStorage::UCBStorage( SvStream
& rStrm
, BOOL bDirect
)
1642 String aURL
= GetLinkedFile( rStrm
);
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
);
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
);
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
);
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
);
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
>() );
1691 StorageBase::m_nMode
= pImp
->m_nMode
;
1694 UCBStorage::UCBStorage( UCBStorage_Impl
*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
1709 pImp
->m_pAntiImpl
= NULL
;
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
)
1718 //, m_pStream( NULL )
1721 , m_bModified( FALSE
)
1722 , m_bCommited( FALSE
)
1723 , m_bDirect( bDirect
)
1724 , m_bIsRoot( bIsRoot
)
1726 , m_bIsLinked( TRUE
)
1727 , m_bListCreated( FALSE
)
1729 , m_aClassId( SvGlobalName() )
1730 , m_bRepairPackage( bIsRepair
)
1731 , m_xProgressHandler( xProgressHandler
)
1732 , m_pUNOStorageHolderList( NULL
)
1735 String
aName( rName
);
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();
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
)
1753 //, m_pStream( NULL )
1756 , m_bModified( FALSE
)
1757 , m_bCommited( FALSE
)
1758 , m_bDirect( bDirect
)
1759 , m_bIsRoot( bIsRoot
)
1761 , m_bIsLinked( FALSE
)
1762 , m_bListCreated( FALSE
)
1764 , m_aClassId( SvGlobalName() )
1765 , m_bRepairPackage( bIsRepair
)
1766 , m_xProgressHandler( xProgressHandler
)
1767 , m_pUNOStorageHolderList( NULL
)
1769 String
aName( rName
);
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();
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
));
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 */ );
1795 // substorages are opened like streams: the URL is a "child URL" of the root package URL
1797 if ( m_aURL
.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 )
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
)
1808 , m_bModified( FALSE
)
1809 , m_bCommited( FALSE
)
1810 , m_bDirect( bDirect
)
1813 , m_bIsLinked( FALSE
)
1814 , m_bListCreated( FALSE
)
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
));
1832 // copy data into the temporary file
1833 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( m_pTempFile
->GetURL(), STREAM_STD_READWRITE
, sal_True
/* bFileExists */ );
1837 rStream
>> *pStream
;
1842 // close stream and let content access the file
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
) )
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
)
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
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
);
1901 xInputStream
= NULL
;
1902 SetProps( aProps
, String() );
1914 // get the manifest information from the package
1916 Any aAny
= m_pContent
->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
1918 if ( ( aAny
>>= aTmp
) && aTmp
.getLength() )
1919 m_aContentType
= m_aOriginalContentType
= aTmp
;
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() )
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
)
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
;
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
;
2012 // unpacked storages have to deal with the meta-inf folder by themselves
2013 if( aTitle
.equalsAscii("META-INF") )
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() );
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
);
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
;
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
)
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();
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();
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") )
2140 if ( ( rAny
.Value
>>= aTmp
) && aTmp
== rPath
)
2142 if ( aType
.getLength() )
2145 else if ( rAny
.Name
.equalsAscii("MediaType") )
2147 if ( ( rAny
.Value
>>= aType
) && aType
.getLength() && bFound
)
2156 return ::rtl::OUString();
2159 void UCBStorage_Impl::SetProps( const Sequence
< Sequence
< PropertyValue
> >& rSequence
, const String
& rPath
)
2161 String
aPath( rPath
);
2166 m_aContentType
= m_aOriginalContentType
= Find_Impl( rSequence
, aPath
);
2169 // the "FullPath" of a child always starts without '/'
2172 UCBStorageElement_Impl
* pElement
= m_aChildrenList
.First();
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
);
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
);
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
;
2222 // the "FullPath" of a child always starts without '/'
2225 // now the properties of my elements
2226 UCBStorageElement_Impl
* pElement
= m_aChildrenList
.First();
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
);
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
++ )
2257 (*aIter
)->InternalDispose();
2258 (*aIter
)->release();
2262 m_pUNOStorageHolderList
->clear();
2263 DELETEZ( m_pUNOStorageHolderList
);
2266 // first delete elements!
2267 UCBStorageElement_Impl
* pElement
= m_aChildrenList
.First();
2271 pElement
= m_aChildrenList
.Next();
2274 m_aChildrenList
.Clear();
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
2284 Reference
< XContentCreator
> xCreator
= Reference
< XContentCreator
>( pContent
->get(), UNO_QUERY
);
2285 if ( !xCreator
.is() )
2290 Sequence
< ContentInfo
> aInfo
= xCreator
->queryCreatableContentsInfo();
2291 sal_Int32 nCount
= aInfo
.getLength();
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 )
2306 if ( !rProps
[ 0 ].Name
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
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
) );
2317 if ( !pContent
->insertNewContent( rCurr
.Type
, aNames
, aValues
, aNewFolder
) )
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
);
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
);
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
);
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
;
2385 // couldn't release stream because there are external references to it
2386 nRet
= COMMIT_RESULT_FAILURE
;
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");
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
;
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
;
2435 aAny
<<= (rtl::OUString
) pElement
->GetContentType();
2436 pContent
->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny
);
2439 if ( nLocalRet
!= COMMIT_RESULT_NOTHING_TO_DO
)
2443 if ( bDeleteContent
)
2444 // content was created inside the loop
2447 if ( nRet
== COMMIT_RESULT_FAILURE
)
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
2488 aType
<<= (rtl::OUString
) m_aContentType
;
2489 m_pContent
->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType
);
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
);
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
>() );
2522 xOutputStream
= NULL
;
2523 DELETEZ( pTempFile
);
2524 aNewSubFolder
.transferContent( aSource
, InsertOperation_MOVE
, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE
);
2529 #if OSL_DEBUG_LEVEL > 1
2530 fprintf ( stderr
, "Files: %i\n", nOpenFiles
);
2531 fprintf ( stderr
, "Streams: %i\n", nOpenStreams
);
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
;
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
);
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
);
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();
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
);
2608 pInnerElement
->m_aOriginalName
= pInnerElement
->m_aName
;
2609 pInnerElement
->m_bIsInserted
= FALSE
;
2612 pInnerElement
= pNext
;
2616 m_bCommited
= FALSE
;
2622 BOOL
UCBStorage_Impl::Revert()
2624 UCBStorageElement_Impl
* pElement
= m_aChildrenList
.First();
2626 while ( pElement
&& bRet
)
2628 pElement
->m_bIsRemoved
= FALSE
;
2629 if ( pElement
->m_bIsInserted
)
2631 m_aChildrenList
.Remove( pElement
); // correct usage of list ???
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();
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() )
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
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*/ )
2715 BOOL
UCBStorage::ShouldConvert()
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();
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
;
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() );
2784 pOtherStream
->Commit();
2786 if ( bDeleteStream
)
2788 delete pOtherStream
;
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
;
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
);
2821 pOtherStorage
->SetClassId( pStorage
->GetClassId() );
2822 pStorage
->CopyTo( pOtherStorage
);
2823 SetError( pStorage
->GetError() );
2824 if( pOtherStorage
->GetError() )
2825 pDest
->SetError( pOtherStorage
->GetError() );
2827 pOtherStorage
->Commit();
2829 if ( bDeleteStorage
)
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();
2843 if ( pElement
->m_aName
== rName
&& !pElement
->m_bIsRemoved
)
2845 pElement
= pImp
->m_aChildrenList
.Next();
2851 BOOL
UCBStorage::CopyTo( BaseStorage
* pDestStg
) const
2853 DBG_ASSERT( pDestStg
!= ((BaseStorage
*)this), "Self-Copying is not possible!" );
2854 if ( pDestStg
== ((BaseStorage
*)this) )
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
);
2866 pDestStg
->SetClassId( GetClassId() );
2867 pDestStg
->SetDirty();
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();
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() )
2888 if ( pDest
== ((BaseStorage
*) this) )
2890 // can't double an element
2895 // for copying no optimization is usefull, because in every case the stream data must be copied
2896 UCBStorageElement_Impl
* pElement
= FindElement_Impl( rElemName
);
2898 return CopyStorageElement_Impl( *pElement
, pDest
, rNew
);
2901 SetError( SVSTREAM_FILE_NOT_FOUND
);
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
);
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() )
2928 // try to find the storage element
2929 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
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
);
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
;
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
); // ???
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!
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
);
2993 UCBStorageStream_Impl
* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, BOOL bDirect
, const ByteString
* pKey
)
2995 String
aName( m_aURL
);
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() )
3007 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, TRUE
);
3010 BaseStorage
* UCBStorage::OpenOLEStorage( const String
& rEleName
, StreamMode nMode
, BOOL bDirect
)
3012 if( !rEleName
.Len() )
3015 return OpenStorage_Impl( rEleName
, nMode
, bDirect
, FALSE
);
3018 BaseStorage
* UCBStorage::OpenStorage( const String
& rEleName
, StreamMode nMode
, BOOL bDirect
)
3020 if( !rEleName
.Len() )
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
);
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
);
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() );
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
);
3066 SetError( ( nMode
& STREAM_WRITE
) ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
3070 pElement
->m_xStream
= pStream
->pImp
;
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
); // ???
3090 BOOL bIsWritable
= (( pElement
->m_xStorage
->m_nMode
& STREAM_WRITE
) != 0);
3091 if ( !bIsWritable
&& (( nMode
& STREAM_WRITE
) != 0 ))
3093 String
aName( pImp
->m_aURL
);
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
;
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
);
3123 SetError( SVSTREAM_CANNOT_MAKE
);
3128 UCBStorage_Impl
* pStor
= pImp
->OpenStorage( pElement
, nMode
, bDirect
);
3131 if ( pElement
->m_bIsInserted
)
3132 pStor
->m_bListCreated
= sal_True
; // the storage is pretty new, nothing to read
3134 return new UCBStorage( pStor
);
3141 UCBStorage_Impl
* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl
* pElement
, StreamMode nMode
, BOOL bDirect
)
3143 UCBStorage_Impl
* pRet
= NULL
;
3144 String
aName( m_aURL
);
3146 aName
+= pElement
->m_aOriginalName
; // ???
3148 pElement
->m_bIsStorage
= pElement
->m_bIsFolder
= TRUE
;
3150 if ( m_bIsLinked
&& !::utl::UCBContentHelper::Exists( aName
) )
3153 BOOL bRet
= ::utl::UCBContentHelper::MakeFolder( *m_pContent
, pElement
->m_aOriginalName
, aNewFolder
);
3155 pRet
= new UCBStorage_Impl( aNewFolder
, aName
, nMode
, NULL
, bDirect
, FALSE
, m_bRepairPackage
, m_xProgressHandler
);
3159 pRet
= new UCBStorage_Impl( aName
, nMode
, NULL
, bDirect
, FALSE
, m_bRepairPackage
, m_xProgressHandler
);
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
;
3178 BOOL
UCBStorage::IsStorage( const String
& rEleName
) const
3180 if( !rEleName
.Len() )
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() )
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() )
3200 const UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
3201 return ( pElement
!= NULL
);
3204 BOOL
UCBStorage::Remove( const String
& rEleName
)
3206 if( !rEleName
.Len() )
3209 UCBStorageElement_Impl
*pElement
= FindElement_Impl( rEleName
);
3212 pElement
->m_bIsRemoved
= TRUE
;
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() )
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
);
3235 pElement
->m_aName
= rNewName
;
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() )
3248 if ( pNewSt
== ((BaseStorage
*) this) && !FindElement_Impl( rNewName
) )
3250 return Rename( rEleName
, rNewName
);
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
);
3272 bRet
= Remove( rEleName
);
3277 BOOL
UCBStorage::ValidateFAT()
3283 BOOL
UCBStorage::Validate( BOOL bWrite
) const
3286 return ( !bWrite
|| ( pImp
->m_nMode
& STREAM_WRITE
) );
3289 BOOL
UCBStorage::ValidateMode( StreamMode m
) const
3292 if( m
== ( STREAM_READ
| STREAM_TRUNC
) ) // from stg.cxx
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
) ) )
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
) )
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
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
);
3347 BOOL
UCBStorage::IsStorageFile( SvStream
* pFile
)
3352 ULONG nPos
= pFile
->Tell();
3353 pFile
->Seek( STREAM_SEEK_TO_END
);
3354 if ( pFile
->Tell() < 4 )
3361 // search for the magic bytes
3362 BOOL bRet
= ( nBytes
== 0x04034b50 );
3365 // disk spanned file have an additional header in front of the usual one
3366 bRet
= ( nBytes
== 0x08074b50 );
3370 bRet
= ( nBytes
== 0x04034b50 );
3374 pFile
->Seek( nPos
);
3378 BOOL
UCBStorage::IsDiskSpannedFile( SvStream
* pFile
)
3383 ULONG nPos
= pFile
->Tell();
3384 pFile
->Seek( STREAM_SEEK_TO_END
);
3385 if ( !pFile
->Tell() )
3392 // disk spanned file have an additional header in front of the usual one
3393 BOOL bRet
= ( nBytes
== 0x08074b50 );
3397 bRet
= ( nBytes
== 0x04034b50 );
3400 pFile
->Seek( nPos
);
3404 String
UCBStorage::GetLinkedFile( SvStream
&rStream
)
3407 ULONG nPos
= rStream
.Tell();
3408 rStream
.Seek( STREAM_SEEK_TO_END
);
3409 if ( !rStream
.Tell() )
3415 if( nBytes
== 0x04034b50 )
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
);
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
);
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." );
3451 // create a folder and store its URL
3452 Content
aFolder( aFolderURL
, Reference
< XCommandEnvironment
>() );
3454 BOOL bRet
= ::utl::UCBContentHelper::MakeFolder( aFolder
, aTitle
, aNewFolder
);
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
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
);
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 !
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=");
3490 pStream
->WriteByteString( aLink
, RTL_TEXTENCODING_UTF8
);
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
);
3500 pTempFile
->EnableKillingFile( TRUE
);
3505 BOOL
UCBStorage::SetProperty( const String
& rName
, const ::com::sun::star::uno::Any
& rValue
)
3507 if ( rName
.CompareToAscii("Title") == COMPARE_EQUAL
)
3510 if ( rName
.CompareToAscii("MediaType") == COMPARE_EQUAL
)
3512 ::rtl::OUString aTmp
;
3514 pImp
->m_aContentType
= aTmp
;
3519 if ( pImp
->GetContent() )
3521 pImp
->m_pContent
->setPropertyValue( rName
, rValue
);
3525 catch ( Exception
& )
3532 BOOL
UCBStorage::GetProperty( const String
& rName
, ::com::sun::star::uno::Any
& rValue
)
3536 if ( pImp
->GetContent() )
3538 rValue
= pImp
->m_pContent
->getPropertyValue( rName
);
3542 catch ( Exception
& )
3549 BOOL
UCBStorage::GetProperty( const String
& rEleName
, const String
& rName
, ::com::sun::star::uno::Any
& rValue
)
3551 UCBStorageElement_Impl
*pEle
= FindElement_Impl( rEleName
);
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();
3567 if ( pEle
->m_xStream
->m_pContent
)
3569 rValue
= pEle
->m_xStream
->m_pContent
->getPropertyValue( rName
);
3573 catch ( Exception
& )
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();
3589 if ( pEle
->m_xStorage
->GetContent() )
3591 rValue
= pEle
->m_xStorage
->m_pContent
->getPropertyValue( rName
);
3595 catch ( Exception
& )
3603 UNOStorageHolderList
* UCBStorage::GetUNOStorageHolderList()
3605 if ( !pImp
->m_pUNOStorageHolderList
)
3606 pImp
->m_pUNOStorageHolderList
= new UNOStorageHolderList
;
3608 return pImp
->m_pUNOStorageHolderList
;