/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sot.hxx"
#include <com/sun/star/io/NotConnectedException.hpp>
#include <com/sun/star/io/BufferSizeExceededException.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <ucbhelper/content.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <unotools/tempfile.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
#include <com/sun/star/ucb/ResultSetException.hpp>
#include <com/sun/star/uno/Sequence.h>
#include <com/sun/star/sdbc/XResultSet.hdl>
#include <com/sun/star/ucb/XContentAccess.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
#include <com/sun/star/datatransfer/DataFlavor.hpp>
#include <com/sun/star/ucb/ContentInfo.hpp>
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
#include <com/sun/star/beans/Property.hpp>
#include <com/sun/star/packages/manifest/XManifestWriter.hpp>
#include <com/sun/star/packages/manifest/XManifestReader.hpp>
#include <com/sun/star/ucb/InteractiveIOException.hpp>

#include <rtl/digest.h>
#include <tools/ref.hxx>
#include <tools/debug.hxx>
#include <unotools/streamhelper.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbhelper.hxx>
#include <unotools/localfilehelper.hxx>
#include <tools/list.hxx>
#include <tools/urlobj.hxx>
#include <unotools/streamwrap.hxx>
#include <comphelper/processfactory.hxx>
#include <cppuhelper/implbase2.hxx>
#include <ucbhelper/commandenvironment.hxx>

#include "sot/stg.hxx"
#include "sot/storinfo.hxx"
#include <sot/storage.hxx>
#include <sot/exchange.hxx>
#include <sot/formats.hxx>
#include "sot/clsids.hxx"

#include "unostorageholder.hxx"

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::sdbc;
using namespace ::ucbhelper;

#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
static int nOpenFiles=0;
static int nOpenStreams=0;
#endif

typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base;
class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base
{
protected:
    ::osl::Mutex    m_aMutex;
    String          m_aURL;
    SvStream*       m_pSvStream;

public:
    FileStreamWrapper_Impl( const String& rName );
    virtual ~FileStreamWrapper_Impl();

    //DECLARE_UNO3_AGG_DEFAULTS( FileStreamWrapper_Impl, FileInputStreamWrapper_Base);

    virtual void SAL_CALL seek( sal_Int64 _nLocation ) throw ( IllegalArgumentException, IOException, RuntimeException);
    virtual sal_Int64 SAL_CALL getPosition(  ) throw ( IOException, RuntimeException);
    virtual sal_Int64 SAL_CALL getLength(  ) throw ( IOException, RuntimeException);
    virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
    virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException );
    virtual void      SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException);
    virtual sal_Int32 SAL_CALL available() throw( NotConnectedException, RuntimeException );
    virtual void      SAL_CALL closeInput() throw( NotConnectedException, RuntimeException );

protected:
    void checkConnected();
    void checkError();
};

//------------------------------------------------------------------
FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String& rName )
    : m_aURL( rName )
    , m_pSvStream(0)
{
    // if no URL is provided the stream is empty
}

//------------------------------------------------------------------
FileStreamWrapper_Impl::~FileStreamWrapper_Impl()
{
    if ( m_pSvStream )
    {
        delete m_pSvStream;
#if OSL_DEBUG_LEVEL > 1
        --nOpenFiles;
#endif
    }

    if ( m_aURL.Len() )
        ::utl::UCBContentHelper::Kill( m_aURL );
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
                throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
{
    if ( !m_aURL.Len() )
    {
        aData.realloc( 0 );
        return 0;
    }

    checkConnected();

    if (nBytesToRead < 0)
        throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));

    ::osl::MutexGuard aGuard( m_aMutex );

    aData.realloc(nBytesToRead);

    sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead);
    checkError();

    // Wenn gelesene Zeichen < MaxLength, Sequence anpassen
    if (nRead < (sal_uInt32)nBytesToRead)
        aData.realloc( nRead );

    return nRead;
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
{
    if ( !m_aURL.Len() )
    {
        aData.realloc( 0 );
        return 0;
    }

    checkError();

    if (nMaxBytesToRead < 0)
        throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this));

    if (m_pSvStream->IsEof())
    {
        aData.realloc(0);
        return 0;
    }
    else
        return readBytes(aData, nMaxBytesToRead);
}

//------------------------------------------------------------------------------
void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException )
{
    if ( !m_aURL.Len() )
        return;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkError();

#ifdef DBG_UTIL
    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
#endif

    m_pSvStream->SeekRel(nBytesToSkip);
    checkError();

#ifdef DBG_UTIL
    nCurrentPos = m_pSvStream->Tell();
#endif
}

//------------------------------------------------------------------------------
sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException )
{
    if ( !m_aURL.Len() )
        return 0;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    checkError();

    sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos;
    m_pSvStream->Seek(nPos);
    checkError();

    return nAvailable;
}

//------------------------------------------------------------------------------
void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException )
{
    if ( !m_aURL.Len() )
        return;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();
    DELETEZ( m_pSvStream );
#if OSL_DEBUG_LEVEL > 1
    --nOpenFiles;
#endif
    ::utl::UCBContentHelper::Kill( m_aURL );
    m_aURL.Erase();
}

//------------------------------------------------------------------------------
void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException)
{
    if ( !m_aURL.Len() )
        return;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    m_pSvStream->Seek((sal_uInt32)_nLocation);
    checkError();
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition(  ) throw (IOException, RuntimeException)
{
    if ( !m_aURL.Len() )
        return 0;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nPos = m_pSvStream->Tell();
    checkError();
    return (sal_Int64)nPos;
}

//------------------------------------------------------------------------------
sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength(  ) throw (IOException, RuntimeException)
{
    if ( !m_aURL.Len() )
        return 0;

    ::osl::MutexGuard aGuard( m_aMutex );
    checkConnected();

    sal_uInt32 nCurrentPos = m_pSvStream->Tell();
    checkError();

    m_pSvStream->Seek(STREAM_SEEK_TO_END);
    sal_uInt32 nEndPos = m_pSvStream->Tell();
    m_pSvStream->Seek(nCurrentPos);

    checkError();

    return (sal_Int64)nEndPos;
}

//------------------------------------------------------------------------------
void FileStreamWrapper_Impl::checkConnected()
{
    if ( !m_aURL.Len() )
        throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
    if ( !m_pSvStream )
    {
        m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ );
#if OSL_DEBUG_LEVEL > 1
        ++nOpenFiles;
#endif
    }
}

//------------------------------------------------------------------------------
void FileStreamWrapper_Impl::checkError()
{
    checkConnected();

    if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE)
        // TODO: really evaluate the error
        throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this)));
}

TYPEINIT1( UCBStorageStream, BaseStorageStream );
TYPEINIT1( UCBStorage, BaseStorage );

#define COMMIT_RESULT_FAILURE           0
#define COMMIT_RESULT_NOTHING_TO_DO     1
#define COMMIT_RESULT_SUCCESS           2

#define min( x, y ) (( x < y ) ? x : y)
#define max( x, y ) (( x > y ) ? x : y)

sal_Int32 GetFormatId_Impl( SvGlobalName aName )
{
//    if ( aName == SvGlobalName( SO3_SW_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARWRITER_8;
//    if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARWRITERWEB_8;
//    if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARWRITERGLOB_8;
//    if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARDRAW_8;
//    if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARIMPRESS_8;
//    if ( aName == SvGlobalName( SO3_SC_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARCALC_8;
//    if ( aName == SvGlobalName( SO3_SCH_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARCHART_8;
//    if ( aName == SvGlobalName( SO3_SM_CLASSID_8 ) )
//        return SOT_FORMATSTR_ID_STARMATH_8;
    if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARWRITER_60;
    if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARWRITERWEB_60;
    if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARWRITERGLOB_60;
    if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARDRAW_60;
    if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARIMPRESS_60;
    if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARCALC_60;
    if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARCHART_60;
    if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) )
        return SOT_FORMATSTR_ID_STARMATH_60;
    if ( aName == SvGlobalName( SO3_OUT_CLASSID ) ||
         aName == SvGlobalName( SO3_APPLET_CLASSID ) ||
         aName == SvGlobalName( SO3_PLUGIN_CLASSID ) ||
         aName == SvGlobalName( SO3_IFRAME_CLASSID ) )
        // allowed, but not supported
        return 0;
    else
    {
        DBG_ERROR( "Unknown UCB storage format!" );
        return 0;
    }
}


SvGlobalName GetClassId_Impl( sal_Int32 nFormat )
{
    switch ( nFormat )
    {
        case SOT_FORMATSTR_ID_STARWRITER_8 :
        case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE :
            return SvGlobalName( SO3_SW_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARWRITERWEB_8 :
            return SvGlobalName( SO3_SWWEB_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARWRITERGLOB_8 :
            return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARDRAW_8 :
        case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE :
            return SvGlobalName( SO3_SDRAW_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARIMPRESS_8 :
        case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE :
            return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARCALC_8 :
        case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE :
            return SvGlobalName( SO3_SC_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARCHART_8 :
        case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE :
            return SvGlobalName( SO3_SCH_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARMATH_8 :
        case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE :
            return SvGlobalName( SO3_SM_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARWRITER_60 :
            return SvGlobalName( SO3_SW_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARWRITERWEB_60 :
            return SvGlobalName( SO3_SWWEB_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARWRITERGLOB_60 :
            return SvGlobalName( SO3_SWGLOB_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARDRAW_60 :
            return SvGlobalName( SO3_SDRAW_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARIMPRESS_60 :
            return SvGlobalName( SO3_SIMPRESS_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARCALC_60 :
            return SvGlobalName( SO3_SC_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARCHART_60 :
            return SvGlobalName( SO3_SCH_CLASSID_60 );
        case SOT_FORMATSTR_ID_STARMATH_60 :
            return SvGlobalName( SO3_SM_CLASSID_60 );
        default :
            //DBG_ERROR( "Unknown UCB storage format!" );
            return SvGlobalName();
    }
}

// All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle
// class, that uses the refcounted object as impl-class.

enum RepresentModes {
        nonset,
        svstream,
        xinputstream
};

class UCBStorageStream_Impl : public SvRefBase, public SvStream
{
                                ~UCBStorageStream_Impl();
public:

    virtual sal_uLong               GetData( void* pData, sal_uLong nSize );
    virtual sal_uLong               PutData( const void* pData, sal_uLong nSize );
    virtual sal_uLong               SeekPos( sal_uLong nPos );
    virtual void                SetSize( sal_uLong nSize );
    virtual void                FlushData();
    virtual void                ResetError();

    UCBStorageStream*           m_pAntiImpl;    // only valid if an external reference exists

    String                      m_aOriginalName;// the original name before accessing the stream
    String                      m_aName;        // the actual name ( changed with a Rename command at the parent )
    String                      m_aURL;         // the full path name to create the content
    String                      m_aContentType;
    String                      m_aOriginalContentType;
    ByteString                  m_aKey;
    ::ucbhelper::Content*       m_pContent;     // the content that provides the data
    Reference<XInputStream>     m_rSource;      // the stream covering the original data of the content
    SvStream*                   m_pStream;      // the stream worked on; for readonly streams it is the original stream of the content
                                                // for read/write streams it's a copy into a temporary file
    String                      m_aTempURL;     // URL of this temporary stream
    RepresentModes              m_nRepresentMode; // should it be used as XInputStream or as SvStream
    long                        m_nError;
    StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
    sal_Bool                        m_bSourceRead;  // Source still contains useful information
    sal_Bool                        m_bModified;    // only modified streams will be sent to the original content
    sal_Bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
    sal_Bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
                                                // this means that the root storage does an autocommit when its external
                                                // reference is destroyed
    sal_Bool                        m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream

                                UCBStorageStream_Impl( const String&, StreamMode, UCBStorageStream*, sal_Bool, const ByteString* pKey=0, sal_Bool bRepair = sal_False, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() );

    void                        Free();
    sal_Bool                        Init();
    sal_Bool                        Clear();
    sal_Int16                   Commit();       // if modified and commited: transfer an XInputStream to the content
    sal_Bool                        Revert();       // discard all changes
    BaseStorage*                CreateStorage();// create an OLE Storage on the UCBStorageStream
    sal_uLong                       GetSize();

    sal_uLong                       ReadSourceWriteTemporary( sal_uLong aLength ); // read aLength from source and copy to temporary,
                                                                           // no seeking is produced
    sal_uLong                       ReadSourceWriteTemporary();                // read source till the end and copy to temporary,
                                                                           // no seeking is produced
#if 0
    sal_uLong                       CopySourceToTemporary( sal_uLong aLength ); // same as ReadSourceWriteToTemporary( aLength )
                                                                        // but the writing is done at the end of temporary
                                                                        // pointer position is not changed
#endif

    sal_uLong                       CopySourceToTemporary();                // same as ReadSourceWriteToTemporary()
                                                                        // but the writing is done at the end of temporary
                                                                        // pointer position is not changed
    Reference<XInputStream>     GetXInputStream();                      // return XInputStream, after that
                                                                        // this class is close to be unusable
                                                                        // since it can not read and write
    using SvStream::SetError;
    void                        SetError( sal_uInt32 nError );
    void                        PrepareCachedForReopen( StreamMode nMode );
};

SV_DECL_IMPL_REF( UCBStorageStream_Impl );

struct UCBStorageElement_Impl;
DECLARE_LIST( UCBStorageElementList_Impl, UCBStorageElement_Impl* )

class UCBStorage_Impl : public SvRefBase
{
                                ~UCBStorage_Impl();
public:
    UCBStorage*                 m_pAntiImpl;    // only valid if external references exists

    String                      m_aOriginalName;// the original name before accessing the storage
    String                      m_aName;        // the actual name ( changed with a Rename command at the parent )
    String                      m_aURL;         // the full path name to create the content
    String                      m_aContentType;
    String                      m_aOriginalContentType;
    ::ucbhelper::Content*       m_pContent;     // the content that provides the storage elements
    ::utl::TempFile*            m_pTempFile;    // temporary file, only for storages on stream
    SvStream*                   m_pSource;      // original stream, only for storages on a stream
    //SvStream*                   m_pStream;      // the corresponding editable stream, only for storage on a stream
    long                        m_nError;
    StreamMode                  m_nMode;        // open mode ( read/write/trunc/nocreate/sharing )
    sal_Bool                        m_bModified;    // only modified elements will be sent to the original content
    sal_Bool                        m_bCommited;    // sending the streams is coordinated by the root storage of the package
    sal_Bool                        m_bDirect;      // the storage and its streams are opened in direct mode; for UCBStorages
                                                // this means that the root storage does an autocommit when its external
                                                // reference is destroyed
    sal_Bool                        m_bIsRoot;      // marks this storage as root storages that manages all oommits and reverts
    sal_Bool                        m_bDirty;           // ???
    sal_Bool                        m_bIsLinked;
    sal_Bool                        m_bListCreated;
    sal_uLong                       m_nFormat;
    String                      m_aUserTypeName;
    SvGlobalName                m_aClassId;

    UCBStorageElementList_Impl  m_aChildrenList;

    sal_Bool                        m_bRepairPackage;
    Reference< XProgressHandler > m_xProgressHandler;

    UNOStorageHolderList*       m_pUNOStorageHolderList;
                                UCBStorage_Impl( const ::ucbhelper::Content&, const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() );
                                UCBStorage_Impl( const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() );
                                UCBStorage_Impl( SvStream&, UCBStorage*, sal_Bool );
    void                        Init();
    sal_Int16                   Commit();
    sal_Bool                        Revert();
    sal_Bool                        Insert( ::ucbhelper::Content *pContent );
    UCBStorage_Impl*            OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect );
    UCBStorageStream_Impl*      OpenStream( UCBStorageElement_Impl*, StreamMode, sal_Bool, const ByteString* pKey=0 );
    void                        SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& );
    void                        GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const String& );
    sal_Int32                   GetObjectCount();
    void                        ReadContent();
    void                        CreateContent();
    ::ucbhelper::Content*       GetContent()
                                { if ( !m_pContent ) CreateContent(); return m_pContent; }
    UCBStorageElementList_Impl& GetChildrenList()
                                {
                                  long nError = m_nError;
                                  ReadContent();
                                  if ( m_nMode & STREAM_WRITE )
                                  {
                                    m_nError = nError;
                                    if ( m_pAntiImpl )
                                    {
                                        m_pAntiImpl->ResetError();
                                        m_pAntiImpl->SetError( nError );
                                    }
                                  }

                                  return m_aChildrenList;
                                }

    void                        SetError( long nError );
};

SV_DECL_IMPL_REF( UCBStorage_Impl );

// this struct contains all necessary information on an element inside a UCBStorage
struct UCBStorageElement_Impl
{
    String                      m_aName;        // the actual URL relative to the root "folder"
    String                      m_aOriginalName;// the original name in the content
    sal_uLong                       m_nSize;
    sal_Bool                        m_bIsFolder;    // Only sal_True when it is a UCBStorage !
    sal_Bool                        m_bIsStorage;   // Also sal_True when it is an OLEStorage !
    sal_Bool                        m_bIsRemoved;   // element will be removed on commit
    sal_Bool                        m_bIsInserted;  // element will be removed on revert
    UCBStorage_ImplRef          m_xStorage;     // reference to the "real" storage
    UCBStorageStream_ImplRef    m_xStream;      // reference to the "real" stream

                                UCBStorageElement_Impl( const ::rtl::OUString& rName,
                                            sal_Bool bIsFolder = sal_False, sal_uLong nSize = 0 )
                                    : m_aName( rName )
                                    , m_aOriginalName( rName )
                                    , m_nSize( nSize )
                                    , m_bIsFolder( bIsFolder )
                                    , m_bIsStorage( bIsFolder )
                                    , m_bIsRemoved( sal_False )
                                    , m_bIsInserted( sal_False )
                                {
                                }

    ::ucbhelper::Content*       GetContent();
    sal_Bool                        IsModified();
    String                      GetContentType();
    void                        SetContentType( const String& );
    String                      GetOriginalContentType();
    sal_Bool                        IsLoaded()
                                { return m_xStream.Is() || m_xStorage.Is(); }
};

::ucbhelper::Content* UCBStorageElement_Impl::GetContent()
{
    if ( m_xStream.Is() )
        return m_xStream->m_pContent;
    else if ( m_xStorage.Is() )
        return m_xStorage->GetContent();
    else
        return NULL;
}

String UCBStorageElement_Impl::GetContentType()
{
    if ( m_xStream.Is() )
        return m_xStream->m_aContentType;
    else if ( m_xStorage.Is() )
        return m_xStorage->m_aContentType;
    else
    {
        DBG_ERROR("Element not loaded!");
        return String();
    }
}

void UCBStorageElement_Impl::SetContentType( const String& rType )
{
    if ( m_xStream.Is() ) {
        m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType;
    }
    else if ( m_xStorage.Is() ) {
        m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType;
    }
    else {
        DBG_ERROR("Element not loaded!");
    }
}

String UCBStorageElement_Impl::GetOriginalContentType()
{
    if ( m_xStream.Is() )
        return m_xStream->m_aOriginalContentType;
    else if ( m_xStorage.Is() )
        return m_xStorage->m_aOriginalContentType;
    else
        return String();
}

sal_Bool UCBStorageElement_Impl::IsModified()
{
    sal_Bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName;
    if ( bModified )
    {
        if ( m_xStream.Is() )
            bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType;
        else if ( m_xStorage.Is() )
            bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType;
    }

    return bModified;
}

UCBStorageStream_Impl::UCBStorageStream_Impl( const String& rName, StreamMode nMode, UCBStorageStream* pStream, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress  )
    : m_pAntiImpl( pStream )
    , m_aURL( rName )
    , m_pContent( NULL )
    , m_pStream( NULL )
    , m_nRepresentMode( nonset )
    , m_nError( 0 )
    , m_nMode( nMode )
    , m_bSourceRead( !( nMode & STREAM_TRUNC ) )
    , m_bModified( sal_False )
    , m_bCommited( sal_False )
    , m_bDirect( bDirect )
    , m_bIsOLEStorage( sal_False )
{
    // name is last segment in URL
    INetURLObject aObj( rName );
    m_aName = m_aOriginalName = aObj.GetLastName();
    try
    {
        // create the content
        Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;

        ::rtl::OUString aTemp( rName );

        if ( bRepair )
        {
            xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
                                                     xProgress );
            aTemp += rtl::OUString::createFromAscii("?repairpackage");
        }

        m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );

        if ( pKey )
        {
            m_aKey = *pKey;

            // stream is encrypted and should be decrypted (without setting the key we'll get the raw data)
            sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1];
            rtlDigestError nErr = rtl_digest_SHA1( pKey->GetBuffer(), pKey->Len(), aBuffer, RTL_DIGEST_LENGTH_SHA1 );
            if ( nErr == rtl_Digest_E_None )
            {
                sal_uInt8* pBuffer = aBuffer;
                ::com::sun::star::uno::Sequence < sal_Int8 > aSequ( (sal_Int8*) pBuffer, RTL_DIGEST_LENGTH_SHA1 );
                ::com::sun::star::uno::Any aAny;
                aAny <<= aSequ;
                m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii("EncryptionKey"), aAny );
            }
        }
    }
    catch ( ContentCreationException& )
    {
        // content could not be created
        SetError( SVSTREAM_CANNOT_MAKE );
    }
    catch ( RuntimeException& )
    {
        // any other error - not specified
        SetError( ERRCODE_IO_GENERAL );
    }
}

UCBStorageStream_Impl::~UCBStorageStream_Impl()
{
    if( m_rSource.is() )
        m_rSource = Reference< XInputStream >();

    if( m_pStream )
        delete m_pStream;

    if ( m_aTempURL.Len() )
        ::utl::UCBContentHelper::Kill( m_aTempURL );

    if( m_pContent )
        delete m_pContent;
}


Reference<XInputStream> UCBStorageStream_Impl::GetXInputStream()
{
    Reference< XInputStream > aResult;

    if( m_pAntiImpl && m_nRepresentMode != nonset )
    {
        DBG_ERROR( "Misuse of the XInputstream!" );
        SetError( ERRCODE_IO_ACCESSDENIED );
    }
    else
    {
        if( m_bModified )
        {
            // use wrapper around temporary stream
            if( Init() )
            {
                CopySourceToTemporary();

                // owner transfer of stream to wrapper
                aResult = new ::utl::OInputStreamWrapper( m_pStream, sal_True );
                m_pStream->Seek(0);

                if( aResult.is() )
                {
                    // temporary stream can not be used here any more
                    // and can not be opened until wrapper is closed
                    // stream is deleted by wrapper after use
                    m_pStream = NULL;
                    m_nRepresentMode = xinputstream;
                }
            }
        }
        else
        {
            Free();

            // open a new instance of XInputStream
            try
            {
                aResult = m_pContent->openStream();
            }
            catch ( Exception& )
            {
                // usually means that stream could not be opened
            }

            if( aResult.is() )
                m_nRepresentMode = xinputstream;
            else
                SetError( ERRCODE_IO_ACCESSDENIED );
        }
    }

    return aResult;
}

sal_Bool UCBStorageStream_Impl::Init()
{
    if( m_nRepresentMode == xinputstream )
    {
        DBG_ERROR( "XInputStream misuse!" );
        SetError( ERRCODE_IO_ACCESSDENIED );
        return sal_False;
    }

    if( !m_pStream )
    {
        // no temporary stream was created
        // create one

        m_nRepresentMode = svstream; // can not be used as XInputStream

        if ( !m_aTempURL.Len() )
            m_aTempURL = ::utl::TempFile().GetURL();

        m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, STREAM_STD_READWRITE, sal_True /* bFileExists */ );
#if OSL_DEBUG_LEVEL > 1
        ++nOpenFiles;
#endif

        if( !m_pStream )
        {
            DBG_ERROR( "Suspicious temporary stream creation!" );
            SetError( SVSTREAM_CANNOT_MAKE );
            return sal_False;
        }

        SetError( m_pStream->GetError() );
    }

    if( m_bSourceRead && !m_rSource.is() )
    {
        // source file contain useful information and is not opened
        // open it from the point of noncopied data

        try
        {
            m_rSource = m_pContent->openStream();
        }
        catch ( Exception& )
        {
            // usually means that stream could not be opened
        }

            if( m_rSource.is() )
        {
            m_pStream->Seek( STREAM_SEEK_TO_END );

            try
            {
                m_rSource->skipBytes( m_pStream->Tell() );
            }
            catch( BufferSizeExceededException& )
            {
                // the temporary stream already contain all the data
                m_bSourceRead = sal_False;
            }
            catch( Exception& )
            {
                // something is really wrong
                m_bSourceRead = sal_False;
                DBG_ERROR( "Can not operate original stream!" );
                SetError( SVSTREAM_CANNOT_MAKE );
            }

            m_pStream->Seek( 0 );
        }
        else
        {
            // if the new file is edited than no source exist
            m_bSourceRead = sal_False;
                //SetError( SVSTREAM_CANNOT_MAKE );
        }
    }

    DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );

    return sal_True;
}

sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary()
{
    // read source stream till the end and copy all the data to
    // the current position of the temporary stream

    sal_uLong aResult = 0;

    if( m_bSourceRead )
    {
        Sequence<sal_Int8> aData(32000);

        try
        {
            sal_uLong aReaded;
            do
            {
                aReaded = m_rSource->readBytes( aData, 32000 );
                aResult += m_pStream->Write( aData.getArray(), aReaded );
            } while( aReaded == 32000 );
        }
#if OSL_DEBUG_LEVEL > 1
        catch( Exception & e )
        {
            OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
#else
        catch( Exception & )
        {
#endif
        }
    }

    m_bSourceRead = sal_False;

    return aResult;

}

sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength )
{
    // read aLength bite from the source stream and copy them to the current
    // position of the temporary stream

    sal_uLong aResult = 0;

    if( m_bSourceRead )
    {
        Sequence<sal_Int8> aData(32000);

        try
        {

            sal_uLong aReaded = 32000;

            for( sal_uLong pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 )
            {
                sal_uLong aToCopy = min( aLength - pInd, 32000 );
                aReaded = m_rSource->readBytes( aData, aToCopy );
                aResult += m_pStream->Write( aData.getArray(), aReaded );
            }

            if( aResult < aLength )
                m_bSourceRead = sal_False;
        }
#if OSL_DEBUG_LEVEL > 1
        catch( Exception & e )
        {
            OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
#else
        catch( Exception & )
        {
#endif
        }
    }

    return aResult;
}

sal_uLong UCBStorageStream_Impl::CopySourceToTemporary()
{
    // current position of the temporary stream is not changed
    sal_uLong aResult = 0;

    if( m_bSourceRead )
    {
        sal_uLong aPos = m_pStream->Tell();
        m_pStream->Seek( STREAM_SEEK_TO_END );
        aResult = ReadSourceWriteTemporary();
        m_pStream->Seek( aPos );
    }

    return aResult;

}

#if 0
sal_uLong UCBStorageStream_Impl::CopySourceToTemporary( sal_uLong aLength )
{
    // current position of the temporary stream is not changed
    sal_uLong aResult = 0;

    if( m_bSourceRead )
    {
        sal_uLong aPos = m_pStream->Tell();
        m_pStream->Seek( STREAM_SEEK_TO_END );
        aResult = ReadSourceWriteTemporary( aLength );
        m_pStream->Seek( aPos );
    }

    return aResult;

}
#endif

// UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream
// of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified
sal_uLong UCBStorageStream_Impl::GetData( void* pData, sal_uLong nSize )
{
    sal_uLong aResult = 0;

    if( !Init() )
        return 0;


    // read data that is in temporary stream
    aResult = m_pStream->Read( pData, nSize );
    if( m_bSourceRead && aResult < nSize )
    {
        // read the tail of the data from original stream
        // copy this tail to the temporary stream

        sal_uLong aToRead = nSize - aResult;
        pData = (void*)( (char*)pData + aResult );

        try
        {
            Sequence<sal_Int8> aData( aToRead );
            sal_uLong aReaded = m_rSource->readBytes( aData, aToRead );
            aResult += m_pStream->Write( (void*)aData.getArray(), aReaded );
            memcpy( pData, aData.getArray(), aReaded );
        }
#if OSL_DEBUG_LEVEL > 1
        catch( Exception & e )
        {
            OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
#else
        catch( Exception & )
        {
#endif
        }

        if( aResult < nSize )
            m_bSourceRead = sal_False;
    }

    return aResult;
}

sal_uLong UCBStorageStream_Impl::PutData( const void* pData, sal_uLong nSize )
{
    if ( !(m_nMode & STREAM_WRITE) )
    {
        SetError( ERRCODE_IO_ACCESSDENIED );
        return 0; // ?mav?
    }

    if( !nSize || !Init() )
        return 0;

    sal_uLong aResult = m_pStream->Write( pData, nSize );

    m_bModified = aResult > 0;

    return aResult;

}

sal_uLong UCBStorageStream_Impl::SeekPos( sal_uLong nPos )
{
    if( !Init() )
        return 0;

    sal_uLong aResult;

    if( nPos == STREAM_SEEK_TO_END )
    {
        m_pStream->Seek( STREAM_SEEK_TO_END );
        ReadSourceWriteTemporary();
        aResult = m_pStream->Tell();
    }
    else
    {
        // the problem is that even if nPos is larger the the length
        // of the stream the stream pointer will be moved to this position
        // so we have to check if temporary stream does not contain required position

        if( m_pStream->Tell() > nPos
            || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos )
        {
            // no copiing is required
            aResult = m_pStream->Seek( nPos );
        }
        else
        {
            // the temp stream pointer points to the end now
            aResult = m_pStream->Tell();

            if( aResult < nPos )
            {
                if( m_bSourceRead )
                {
                    aResult += ReadSourceWriteTemporary( nPos - aResult );
                    if( aResult < nPos )
                        m_bSourceRead = sal_False;

                    DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" );
                }

                if( (m_nMode & STREAM_WRITE) && !m_bSourceRead && aResult < nPos )
                {
                    // it means that all the Source stream was copied already
                    // but the required position still was not reached
                    // for writable streams it should be done
                    m_pStream->SetStreamSize( nPos );
                    aResult = m_pStream->Seek( STREAM_SEEK_TO_END );
                    DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" );
                }
            }
        }
    }

    return aResult;
}

void  UCBStorageStream_Impl::SetSize( sal_uLong nSize )
{
    if ( !(m_nMode & STREAM_WRITE) )
    {
        SetError( ERRCODE_IO_ACCESSDENIED );
        return;
    }

    if( !Init() )
        return;

    m_bModified = sal_True;

    if( m_bSourceRead )
    {
        sal_uLong aPos = m_pStream->Tell();
        m_pStream->Seek( STREAM_SEEK_TO_END );
        if( m_pStream->Tell() < nSize )
            ReadSourceWriteTemporary( nSize - m_pStream->Tell() );
        m_pStream->Seek( aPos );
    }

    m_pStream->SetStreamSize( nSize );
    m_bSourceRead = sal_False;
}

void  UCBStorageStream_Impl::FlushData()
{
    if( m_pStream )
    {
        CopySourceToTemporary();
        m_pStream->Flush();
    }

    m_bCommited = sal_True;
}

void UCBStorageStream_Impl::SetError( sal_uInt32 nErr )
{
    if ( !m_nError )
    {
        m_nError = nErr;
        SvStream::SetError( nErr );
        if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr );
    }
}

void  UCBStorageStream_Impl::ResetError()
{
    m_nError = 0;
    SvStream::ResetError();
    if ( m_pAntiImpl )
        m_pAntiImpl->ResetError();
}

sal_uLong UCBStorageStream_Impl::GetSize()
{
    if( !Init() )
        return 0;

    sal_uLong nPos = m_pStream->Tell();
    m_pStream->Seek( STREAM_SEEK_TO_END );
    ReadSourceWriteTemporary();
    sal_uLong nRet = m_pStream->Tell();
    m_pStream->Seek( nPos );

    return nRet;
}

BaseStorage* UCBStorageStream_Impl::CreateStorage()
{
    // create an OLEStorage on a SvStream ( = this )
    // it gets the root attribute because otherwise it would probably not write before my root is commited
    UCBStorageStream* pNewStorageStream = new UCBStorageStream( this );
    Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect );

    // GetError() call cleares error code for OLE storages, must be changed in future
    long nTmpErr = pStorage->GetError();
    pStorage->SetError( nTmpErr );

    m_bIsOLEStorage = !nTmpErr;
    return static_cast< BaseStorage* > ( pStorage );
}

sal_Int16 UCBStorageStream_Impl::Commit()
{
    // send stream to the original content
    // the  parent storage is responsible for the correct handling of deleted contents
    if ( m_bCommited || m_bIsOLEStorage || m_bDirect )
    {
        // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage
        // was commited as well ( if not opened in direct mode )

        if ( m_bModified )
        {
            try
            {
                CopySourceToTemporary();

                // release all stream handles
                Free();

                // the temporary file does not exist only for truncated streams
                DBG_ASSERT( m_aTempURL.Len() || ( m_nMode & STREAM_TRUNC ), "No temporary file to read from!");
                if ( !m_aTempURL.Len() && !( m_nMode & STREAM_TRUNC ) )
                    throw RuntimeException();

                // create wrapper to stream that is only used while reading inside package component
                Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL );

                Any aAny;
                InsertCommandArgument aArg;
                aArg.Data = xStream;
                aArg.ReplaceExisting = sal_True;
                aAny <<= aArg;
                m_pContent->executeCommand( ::rtl::OUString::createFromAscii("insert"), aAny );

                // wrapper now controls lifetime of temporary file
                m_aTempURL.Erase();

                INetURLObject aObj( m_aURL );
                aObj.SetName( m_aName );
                m_aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
                m_bModified = sal_False;
                m_bSourceRead = sal_True;
            }
            catch ( CommandAbortedException& )
            {
                // any command wasn't executed successfully - not specified
                SetError( ERRCODE_IO_GENERAL );
                return COMMIT_RESULT_FAILURE;
            }
            catch ( RuntimeException& )
            {
                // any other error - not specified
                SetError( ERRCODE_IO_GENERAL );
                return COMMIT_RESULT_FAILURE;
            }
            catch ( Exception& )
            {
                // any other error - not specified
                SetError( ERRCODE_IO_GENERAL );
                return COMMIT_RESULT_FAILURE;
            }

            m_bCommited = sal_False;
            return COMMIT_RESULT_SUCCESS;
        }
    }

    return COMMIT_RESULT_NOTHING_TO_DO;
}

sal_Bool UCBStorageStream_Impl::Revert()
{
    // if an OLEStorage is created on this stream, no "revert" is necessary because OLEStorages do nothing on "Revert" !
    if ( m_bCommited )
    {
        DBG_ERROR("Revert while commit is in progress!" );
        return sal_False;                   //  ???
    }

    Free();
    if ( m_aTempURL.Len() )
    {
        ::utl::UCBContentHelper::Kill( m_aTempURL );
        m_aTempURL.Erase();
    }

    m_bSourceRead = sal_False;
    try
    {
        m_rSource = m_pContent->openStream();
        if( m_rSource.is() )
        {
            if ( m_pAntiImpl && ( m_nMode & STREAM_TRUNC ) )
                // stream is in use and should be truncated
                m_bSourceRead = sal_False;
            else
            {
                m_nMode &= ~STREAM_TRUNC;
                m_bSourceRead = sal_True;
            }
        }
        else
            SetError( SVSTREAM_CANNOT_MAKE );
    }
    catch ( ContentCreationException& )
    {
        SetError( ERRCODE_IO_GENERAL );
    }
    catch ( RuntimeException& )
    {
        SetError( ERRCODE_IO_GENERAL );
    }
    catch ( Exception& )
    {
    }

    m_bModified = sal_False;
    m_aName = m_aOriginalName;
    m_aContentType = m_aOriginalContentType;
    return ( GetError() == ERRCODE_NONE );
}

sal_Bool UCBStorageStream_Impl::Clear()
{
    sal_Bool bRet = ( m_pAntiImpl == NULL );
    DBG_ASSERT( bRet, "Removing used stream!" );
    if( bRet )
    {
        Free();
    }

    return bRet;
}

void UCBStorageStream_Impl::Free()
{
#if OSL_DEBUG_LEVEL > 1
    if ( m_pStream )
    {
        if ( m_aTempURL.Len() )
            --nOpenFiles;
        else
            --nOpenStreams;
    }
#endif

    m_nRepresentMode = nonset;
    m_rSource = Reference< XInputStream >();
    DELETEZ( m_pStream );
}

void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode )
{
    sal_Bool isWritable = (( m_nMode & STREAM_WRITE ) != 0 );
    if ( isWritable )
    {
        // once stream was writable, never reset to readonly
        nMode |= STREAM_WRITE;
    }

    m_nMode = nMode;
    Free();

    if ( nMode & STREAM_TRUNC )
    {
        m_bSourceRead = 0; // usually it should be 0 already but just in case...

        if ( m_aTempURL.Len() )
        {
            ::utl::UCBContentHelper::Kill( m_aTempURL );
            m_aTempURL.Erase();
        }
    }
}

UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
{
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
    // to class UCBStorageStream !
    pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey );
    pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress )
{
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
    // to class UCBStorageStream !
    pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey, bRepair, xProgress );
    pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl )
    : pImp( pImpl )
{
    pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
    pImp->m_pAntiImpl = this;
    SetError( pImp->m_nError );
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorageStream::~UCBStorageStream()
{
    if ( pImp->m_nMode & STREAM_WRITE )
        pImp->Flush();
    pImp->m_pAntiImpl = NULL;
    pImp->Free();
    pImp->ReleaseRef();
}

sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize )
{
    //return pImp->m_pStream->Read( pData, nSize );
    return pImp->GetData( pData, nSize );
}

sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize )
{
/*
    // mba: does occur in writer !
    if ( pImp->m_bCommited )
    {
        DBG_ERROR("Writing while commit is in progress!" );
        return 0;
    }
*/
    // pImp->m_bModified = sal_True;
    //return pImp->m_pStream->Write( pData, nSize );
    return pImp->PutData( pData, nSize );
}

sal_uLong UCBStorageStream::Seek( sal_uLong nPos )
{
    //return pImp->m_pStream->Seek( nPos );
    return pImp->Seek( nPos );
}

sal_uLong UCBStorageStream::Tell()
{
    if( !pImp->Init() )
        return 0;
    return pImp->m_pStream->Tell();
}

void UCBStorageStream::Flush()
{
    // streams are never really transacted, so flush also means commit !
    Commit();
}

sal_Bool UCBStorageStream::SetSize( sal_uLong nNewSize )
{
/*
    if ( pImp->m_bCommited )
    {
        DBG_ERROR("Changing stream size while commit is in progress!" );
        return sal_False;
    }
*/
    // pImp->m_bModified = sal_True;
    //return pImp->m_pStream->SetStreamSize( nNewSize );
    pImp->SetSize( nNewSize );
    return !pImp->GetError();
}

sal_Bool UCBStorageStream::Validate( sal_Bool bWrite ) const
{
    return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
}

sal_Bool UCBStorageStream::ValidateMode( StreamMode m ) const
{
    // ???
    if( m == ( STREAM_READ | STREAM_TRUNC ) )  // from stg.cxx
        return sal_True;
    sal_uInt16 nCurMode = 0xFFFF;
    if( ( m & 3 ) == STREAM_READ )
    {
        // only SHARE_DENYWRITE or SHARE_DENYALL allowed
        if( ( ( m & STREAM_SHARE_DENYWRITE )
           && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
         || ( ( m & STREAM_SHARE_DENYALL )
           && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
            return sal_True;
    }
    else
    {
        // only SHARE_DENYALL allowed
        // storages open in r/o mode are OK, since only
        // the commit may fail
        if( ( m & STREAM_SHARE_DENYALL )
         && ( nCurMode & STREAM_SHARE_DENYALL ) )
            return sal_True;
    }

    return sal_True;
}

const SvStream* UCBStorageStream::GetSvStream() const
{
    if( !pImp->Init() )
        return NULL;

    pImp->CopySourceToTemporary();
    return pImp->m_pStream; // should not live longer then pImp!!!
}

SvStream* UCBStorageStream::GetModifySvStream()
{
    return (SvStream*)pImp;
}

Reference< XInputStream > UCBStorageStream::GetXInputStream() const
{
    return pImp->GetXInputStream();
}

sal_Bool  UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
{
    // ???
    return ((BaseStorageStream*) this ) == &rStream;
}

sal_Bool UCBStorageStream::Commit()
{
    // mark this stream for sending it on root commit
    pImp->FlushData();
    return sal_True;
}

sal_Bool UCBStorageStream::Revert()
{
    return pImp->Revert();
}

sal_Bool UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
{
    if( !pImp->Init() )
        return sal_False;

    UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
    if ( pStg )
        pStg->pImp->m_aContentType = pImp->m_aContentType;

    pDestStm->SetSize( 0 );
    Seek( STREAM_SEEK_TO_END );
    sal_Int32 n = Tell();
    if( n < 0 )
        return sal_False;

    if( pDestStm->SetSize( n ) && n )
    {
        sal_uInt8* p = new sal_uInt8[ 4096 ];
        Seek( 0L );
        pDestStm->Seek( 0L );
        while( n )
        {
            sal_uInt32 nn = n;
            if( nn > 4096 )
                nn = 4096;
            if( Read( p, nn ) != nn )
                break;
            if( pDestStm->Write( p, nn ) != nn )
                break;
            n -= nn;
        }

        delete[] p;
    }

    return sal_True;
}

sal_Bool UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
{
    if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
        return sal_False;

    if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
    {
        ::rtl::OUString aTmp;
        rValue >>= aTmp;
        pImp->m_aContentType = aTmp;
    }

    try
    {
        if ( pImp->m_pContent )
        {
            pImp->m_pContent->setPropertyValue( rName, rValue );
            return sal_True;
        }
    }
    catch ( Exception& )
    {
    }

    return sal_False;
}

sal_Bool UCBStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
{
    try
    {
        if ( pImp->m_pContent )
        {
            rValue = pImp->m_pContent->getPropertyValue( rName );
            return sal_True;
        }
    }
    catch ( Exception& )
    {
    }

    return sal_False;
}

UCBStorage::UCBStorage( SvStream& rStrm, sal_Bool bDirect )
{
    String aURL = GetLinkedFile( rStrm );
    if ( aURL.Len() )
    {
        StreamMode nMode = STREAM_READ;
        if( rStrm.IsWritable() )
            nMode = STREAM_READ | STREAM_WRITE;

        ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >() );
        pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, sal_True );
    }
    else
    {
        // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
        // to class UCBStorage !
        pImp = new UCBStorage_Impl( rStrm, this, bDirect );
    }

    pImp->AddRef();
    pImp->Init();
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot )
{
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
    // to class UCBStorage !
    pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot );
    pImp->AddRef();
    pImp->Init();
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
{
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
    // to class UCBStorage !
    pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler );
    pImp->AddRef();
    pImp->Init();
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot )
{
    // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized
    // to class UCBStorage !
    pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, sal_False, Reference< XProgressHandler >() );
    pImp->AddRef();
    pImp->Init();
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorage::UCBStorage( UCBStorage_Impl *pImpl )
    : pImp( pImpl )
{
    pImp->m_pAntiImpl = this;
    SetError( pImp->m_nError );
    pImp->AddRef();             // use direct refcounting because in header file only a pointer should be used
    StorageBase::m_nMode = pImp->m_nMode;
}

UCBStorage::~UCBStorage()
{
    if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) )
        // DirectMode is simulated with an AutoCommit
        Commit();

    pImp->m_pAntiImpl = NULL;
    pImp->ReleaseRef();
}

UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler  )
    : m_pAntiImpl( pStorage )
    , m_pContent( new ::ucbhelper::Content( rContent ) )
    , m_pTempFile( NULL )
    , m_pSource( NULL )
    //, m_pStream( NULL )
    , m_nError( 0 )
    , m_nMode( nMode )
    , m_bModified( sal_False )
    , m_bCommited( sal_False )
    , m_bDirect( bDirect )
    , m_bIsRoot( bIsRoot )
    , m_bDirty( sal_False )
    , m_bIsLinked( sal_True )
    , m_bListCreated( sal_False )
    , m_nFormat( 0 )
    , m_aClassId( SvGlobalName() )
    , m_bRepairPackage( bIsRepair )
    , m_xProgressHandler( xProgressHandler )
    , m_pUNOStorageHolderList( NULL )

{
    String aName( rName );
    if( !aName.Len() )
    {
        // no name given = use temporary name!
        DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
        m_pTempFile = new ::utl::TempFile;
        m_pTempFile->EnableKillingFile( sal_True );
        m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
    }

    m_aURL = rName;
}

UCBStorage_Impl::UCBStorage_Impl( const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler )
    : m_pAntiImpl( pStorage )
    , m_pContent( NULL )
    , m_pTempFile( NULL )
    , m_pSource( NULL )
    //, m_pStream( NULL )
    , m_nError( 0 )
    , m_nMode( nMode )
    , m_bModified( sal_False )
    , m_bCommited( sal_False )
    , m_bDirect( bDirect )
    , m_bIsRoot( bIsRoot )
    , m_bDirty( sal_False )
    , m_bIsLinked( sal_False )
    , m_bListCreated( sal_False )
    , m_nFormat( 0 )
    , m_aClassId( SvGlobalName() )
    , m_bRepairPackage( bIsRepair )
    , m_xProgressHandler( xProgressHandler )
    , m_pUNOStorageHolderList( NULL )
{
    String aName( rName );
    if( !aName.Len() )
    {
        // no name given = use temporary name!
        DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" );
        m_pTempFile = new ::utl::TempFile;
        m_pTempFile->EnableKillingFile( sal_True );
        m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
    }

    if ( m_bIsRoot )
    {
        // create the special package URL for the package content
        String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
        aTemp += String(INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
        m_aURL = aTemp;

        if ( m_nMode & STREAM_WRITE )
        {
            // the root storage opens the package, so make sure that there is any
            SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READWRITE, m_pTempFile != 0 /* bFileExists */ );
            delete pStream;
        }
    }
    else
    {
        // substorages are opened like streams: the URL is a "child URL" of the root package URL
        m_aURL = rName;
        if ( m_aURL.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 )
            m_bIsLinked = sal_True;
    }
}

UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, sal_Bool bDirect )
    : m_pAntiImpl( pStorage )
    , m_pContent( NULL )
    , m_pTempFile( new ::utl::TempFile )
    , m_pSource( &rStream )
    , m_nError( 0 )
    , m_bModified( sal_False )
    , m_bCommited( sal_False )
    , m_bDirect( bDirect )
    , m_bIsRoot( sal_True )
    , m_bDirty( sal_False )
    , m_bIsLinked( sal_False )
    , m_bListCreated( sal_False )
    , m_nFormat( 0 )
    , m_aClassId( SvGlobalName() )
    , m_bRepairPackage( sal_False )
    , m_pUNOStorageHolderList( NULL )
{
    // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call,
    // which will be called in the storages' dtor
    m_pTempFile->EnableKillingFile( sal_True );
    DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" );

    // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only
    // accessed readonly
    // the root storage opens the package; create the special package URL for the package content
    String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://");
    aTemp += String(INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL ));
    m_aURL = aTemp;

    // copy data into the temporary file
    SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, sal_True /* bFileExists */ );
    if ( pStream )
    {
        rStream.Seek(0);
        rStream >> *pStream;
        pStream->Flush();
        DELETEZ( pStream );
    }

    // close stream and let content access the file
    m_pSource->Seek(0);

    // check opening mode
    m_nMode = STREAM_READ;
    if( rStream.IsWritable() )
        m_nMode = STREAM_READ | STREAM_WRITE;
}

void UCBStorage_Impl::Init()
{
    // name is last segment in URL
    INetURLObject aObj( m_aURL );
    if ( !m_aName.Len() )
        // if the name was not already set to a temp name
        m_aName = m_aOriginalName = aObj.GetLastName();

    // don't create the content for disk spanned files, avoid too early access to directory and/or manifest
    if ( !m_pContent && !( m_nMode & STORAGE_DISKSPANNED_MODE ) )
        CreateContent();

    if ( m_nMode & STORAGE_DISKSPANNED_MODE )
    {
        // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a
        // disk spanned file
        m_aContentType = m_aOriginalContentType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.xml.impress") );
    }
    else if ( m_pContent )
    {
        if ( m_bIsLinked )
        {
            if( m_bIsRoot )
            {
                ReadContent();
                if ( m_nError == ERRCODE_NONE )
                {
                    // read the manifest.xml file
                    aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("META-INF") ) );
                    aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("manifest.xml") ) );

                    // create input stream
                    SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
                    // no stream means no manifest.xml
                    if ( pStream )
                    {
                        if ( !pStream->GetError() )
                        {
                            ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream );
                            com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xInputStream( pHelper );

                            // create a manifest reader object that will read in the manifest from the stream
                            Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader =
                                Reference< ::com::sun::star::packages::manifest::XManifestReader >
                                    ( ::comphelper::getProcessServiceFactory()->createInstance(
                                        ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestReader" )), UNO_QUERY) ;
                            Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream );

                            // cleanup
                            xReader = NULL;
                            xInputStream = NULL;
                            SetProps( aProps, String() );
                        }

                        delete pStream;
                    }
                }
            }
            else
                ReadContent();
        }
        else
        {
            // get the manifest information from the package
            try {
                Any aAny = m_pContent->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
                rtl::OUString aTmp;
                if ( ( aAny >>= aTmp ) && aTmp.getLength() )
                    m_aContentType = m_aOriginalContentType = aTmp;
            }
            catch( Exception& )
            {
                DBG_ASSERT( sal_False,
                            "getPropertyValue has thrown an exception! Please let developers know the scenario!" );
            }
        }
    }

    if ( m_aContentType.Len() )
    {
        // get the clipboard format using the content type
        ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
        aDataFlavor.MimeType = m_aContentType;
        m_nFormat = SotExchange::GetFormat( aDataFlavor );

        // get the ClassId using the clipboard format ( internal table )
        m_aClassId = GetClassId_Impl( m_nFormat );

        // get human presentable name using the clipboard format
        SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
        m_aUserTypeName = aDataFlavor.HumanPresentableName;

        if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() )
            ReadContent();
    }
}

void UCBStorage_Impl::CreateContent()
{
    try
    {
        // create content; where to put StreamMode ?! ( already done when opening the file of the package ? )
        Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;

        ::rtl::OUString aTemp( m_aURL );

        if ( m_bRepairPackage )
        {
            xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
                                                     m_xProgressHandler );
            aTemp += rtl::OUString::createFromAscii("?repairpackage");
        }

        m_pContent = new ::ucbhelper::Content( aTemp, xComEnv );
    }
    catch ( ContentCreationException& )
    {
        // content could not be created
        SetError( SVSTREAM_CANNOT_MAKE );
    }
    catch ( RuntimeException& )
    {
        // any other error - not specified
        SetError( SVSTREAM_CANNOT_MAKE );
    }
}

void UCBStorage_Impl::ReadContent()
{
   if ( m_bListCreated )
        return;

    m_bListCreated = sal_True;

    // create cursor for access to children
    Sequence< ::rtl::OUString > aProps(4);
    ::rtl::OUString* pProps = aProps.getArray();
    pProps[0] = ::rtl::OUString::createFromAscii( "Title" );
    pProps[1] = ::rtl::OUString::createFromAscii( "IsFolder" );
    pProps[2] = ::rtl::OUString::createFromAscii( "MediaType" );
    pProps[3] = ::rtl::OUString::createFromAscii( "Size" );
    ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS;

    try
    {
        GetContent();
        if ( !m_pContent )
            return;

        Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude );
        Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
        Reference< XRow > xRow( xResultSet, UNO_QUERY );
        if ( xResultSet.is() )
        {
            while ( xResultSet->next() )
            {
                // insert all into the children list
                ::rtl::OUString aTitle( xRow->getString(1) );
                ::rtl::OUString aContentType;
                if ( m_bIsLinked )
                {
                    // unpacked storages have to deal with the meta-inf folder by themselves
                    if( aTitle.equalsAscii("META-INF") )
                        continue;
                }
                else
                {
                    aContentType = xRow->getString(3);
                }

                sal_Bool bIsFolder( xRow->getBoolean(2) );
                sal_Int64 nSize = xRow->getLong(4);
                UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (sal_uLong) nSize );
                m_aChildrenList.Insert( pElement, LIST_APPEND );

                sal_Bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() );
                if ( bIsFolder )
                {
                    if ( m_bIsLinked )
                        OpenStorage( pElement, m_nMode, m_bDirect );
                    if ( pElement->m_xStorage.Is() )
                        pElement->m_xStorage->Init();
                }
                else if ( bIsOfficeDocument )
                {
                    // streams can be external OLE objects, so they are now folders, but storages!
                    String aName( m_aURL );
                    aName += '/';
                    aName += String( xRow->getString(1) );

                    Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv;
                    if ( m_bRepairPackage )
                    {
                        xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(),
                                                                m_xProgressHandler );
                            aName += String( RTL_CONSTASCII_USTRINGPARAM( "?repairpackage" ) );
                    }

                    ::ucbhelper::Content aContent( aName, xComEnv );

                    ::rtl::OUString aMediaType;
                    Any aAny = aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) );
                    if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
                        pElement->m_bIsStorage = sal_True;
                    else if ( !aMediaType.getLength() )
                    {
                        // older files didn't have that special content type, so they must be detected
                        OpenStream( pElement, STREAM_STD_READ, m_bDirect );
                        if ( Storage::IsStorageFile( pElement->m_xStream ) )
                            pElement->m_bIsStorage = sal_True;
                        else
                            pElement->m_xStream->Free();
                    }
                }
            }
        }
    }
    catch ( InteractiveIOException& r )
    {
        if ( r.Code != IOErrorCode_NOT_EXISTING )
            SetError( ERRCODE_IO_GENERAL );
    }
    catch ( CommandAbortedException& )
    {
        // any command wasn't executed successfully - not specified
        if ( !( m_nMode & STREAM_WRITE ) )
            // if the folder was just inserted and not already commited, this is not an error!
            SetError( ERRCODE_IO_GENERAL );
    }
    catch ( RuntimeException& )
    {
        // any other error - not specified
        SetError( ERRCODE_IO_GENERAL );
    }
    catch ( ResultSetException& )
    {
        // means that the package file is broken
        SetError( ERRCODE_IO_BROKENPACKAGE );
    }
    catch ( SQLException& )
    {
        // means that the file can be broken
        SetError( ERRCODE_IO_WRONGFORMAT );
    }
    catch ( Exception& )
    {
        // any other error - not specified
        SetError( ERRCODE_IO_GENERAL );
    }
}

void UCBStorage_Impl::SetError( long nError )
{
    if ( !m_nError )
    {
        m_nError = nError;
        if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError );
    }
}

sal_Int32 UCBStorage_Impl::GetObjectCount()
{
    sal_Int32 nCount = m_aChildrenList.Count();
    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    while ( pElement )
    {
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
        if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
            nCount += pElement->m_xStorage->GetObjectCount();
        pElement = m_aChildrenList.Next();
    }

    return nCount;
}

::rtl::OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const ::rtl::OUString& rPath )
{
    sal_Bool bFound = sal_False;
    for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ )
    {
        const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs];
        ::rtl::OUString aType;

        for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ )
        {
            const PropertyValue& rAny = rMyProps[nProps];
            if ( rAny.Name.equalsAscii("FullPath") )
            {
                rtl::OUString aTmp;
                if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
                    bFound = sal_True;
                if ( aType.getLength() )
                    break;
            }
            else if ( rAny.Name.equalsAscii("MediaType") )
            {
                if ( ( rAny.Value >>= aType ) && aType.getLength() && bFound )
                    break;
            }
        }

        if ( bFound )
            return aType;
    }

    return ::rtl::OUString();
}

void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
{
    String aPath( rPath );
    if ( !m_bIsRoot )
        aPath += m_aName;
    aPath += '/';

    m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath );

    if ( m_bIsRoot )
        // the "FullPath" of a child always starts without '/'
        aPath.Erase();

    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    while ( pElement )
    {
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
        if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
            pElement->m_xStorage->SetProps( rSequence, aPath );
        else
        {
            String aElementPath( aPath );
            aElementPath += pElement->m_aName;
            pElement->SetContentType( Find_Impl( rSequence, aElementPath ) );
        }

        pElement = m_aChildrenList.Next();
    }

    if ( m_aContentType.Len() )
    {
        // get the clipboard format using the content type
        ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
        aDataFlavor.MimeType = m_aContentType;
        m_nFormat = SotExchange::GetFormat( aDataFlavor );

        // get the ClassId using the clipboard format ( internal table )
        m_aClassId = GetClassId_Impl( m_nFormat );

        // get human presentable name using the clipboard format
        SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor );
        m_aUserTypeName = aDataFlavor.HumanPresentableName;
    }
}

void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath )
{
    // first my own properties
    Sequence < PropertyValue > aProps(2);

    // first property is the "FullPath" name
    // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder
    String aPath( rPath );
    if ( !m_bIsRoot )
        aPath += m_aName;
    aPath += '/';
    aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
    aProps[0].Value <<= (::rtl::OUString ) m_aContentType;
    aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
    aProps[1].Value <<= (::rtl::OUString ) aPath;
    rSequence[ nProps++ ] = aProps;

    if ( m_bIsRoot )
        // the "FullPath" of a child always starts without '/'
        aPath.Erase();

    // now the properties of my elements
    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    while ( pElement )
    {
        DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" );
        if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() )
            // storages add there properties by themselves ( see above )
            pElement->m_xStorage->GetProps( nProps, rSequence, aPath );
        else
        {
            // properties of streams
            String aElementPath( aPath );
            aElementPath += pElement->m_aName;
            aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType");
            aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType();
            aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath");
            aProps[1].Value <<= (::rtl::OUString ) aElementPath;
            rSequence[ nProps++ ] = aProps;
        }

        pElement = m_aChildrenList.Next();
    }
}

UCBStorage_Impl::~UCBStorage_Impl()
{
    if ( m_pUNOStorageHolderList )
    {
        for ( UNOStorageHolderList::iterator aIter = m_pUNOStorageHolderList->begin();
              aIter != m_pUNOStorageHolderList->end(); aIter++ )
            if ( *aIter )
            {
                (*aIter)->InternalDispose();
                (*aIter)->release();
                (*aIter) = NULL;
            }

        m_pUNOStorageHolderList->clear();
        DELETEZ( m_pUNOStorageHolderList );
    }

    // first delete elements!
    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    while ( pElement )
    {
        delete pElement;
        pElement = m_aChildrenList.Next();
    }

    m_aChildrenList.Clear();
    delete m_pContent;
    delete m_pTempFile;
}

sal_Bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent )
{
    // a new substorage is inserted into a UCBStorage ( given by the parameter pContent )
    // it must be inserted with a title and a type
    sal_Bool bRet = sal_False;

    try
    {
        Sequence< ContentInfo > aInfo = pContent->queryCreatableContentsInfo();
        sal_Int32 nCount = aInfo.getLength();
        if ( nCount == 0 )
            return sal_False;

        for ( sal_Int32 i = 0; i < nCount; ++i )
        {
            // Simply look for the first KIND_FOLDER...
            const ContentInfo & rCurr = aInfo[i];
            if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
            {
                // Make sure the only required bootstrap property is "Title",
                const Sequence< Property > & rProps = rCurr.Properties;
                if ( rProps.getLength() != 1 )
                    continue;

                if ( !rProps[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
                    continue;

                Sequence < ::rtl::OUString > aNames(1);
                ::rtl::OUString* pNames = aNames.getArray();
                pNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
                Sequence < Any > aValues(1);
                Any* pValues = aValues.getArray();
                pValues[0] = makeAny( ::rtl::OUString( m_aName ) );

                Content aNewFolder;
                if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) )
                    continue;

                // remove old content, create an "empty" new one and initialize it with the new inserted
                DELETEZ( m_pContent );
                m_pContent = new ::ucbhelper::Content( aNewFolder );
                bRet = sal_True;
            }
        }
    }
    catch ( CommandAbortedException& )
    {
        // any command wasn't executed successfully - not specified
        SetError( ERRCODE_IO_GENERAL );
    }
    catch ( RuntimeException& )
    {
        // any other error - not specified
        SetError( ERRCODE_IO_GENERAL );
    }
    catch ( Exception& )
    {
        // any other error - not specified
        SetError( ERRCODE_IO_GENERAL );
    }

    return bRet;
}

sal_Int16 UCBStorage_Impl::Commit()
{
    // send all changes to the package
    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO;

    // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no
    // commit command has been sent
    if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) )
    {
        try
        {
            // all errors will be caught in the "catch" statement outside the loop
            while ( pElement && nRet )
            {
                ::ucbhelper::Content* pContent = pElement->GetContent();
                sal_Bool bDeleteContent = sal_False;
                if ( !pContent && pElement->IsModified() )
                {
                    // if the element has never been opened, no content has been created until now
                    bDeleteContent = sal_True;  // remember to delete it later
                    String aName( m_aURL );
                    aName += '/';
                    aName += pElement->m_aOriginalName;
                    pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
                }

                if ( pElement->m_bIsRemoved )
                {
                    // was it inserted, then removed (so there would be nothing to do!)
                    if ( !pElement->m_bIsInserted )
                    {
                        // first remove all open stream handles
                        if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() )
                        {
                            pContent->executeCommand( ::rtl::OUString::createFromAscii("delete"), makeAny( sal_Bool( sal_True ) ) );
                            nRet = COMMIT_RESULT_SUCCESS;
                        }
                        else
                            // couldn't release stream because there are external references to it
                            nRet = COMMIT_RESULT_FAILURE;
                    }
                }
                else
                {
                    sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO;
                    if ( pElement->m_xStorage.Is() )
                    {
                        // element is a storage
                        // do a commit in the following cases:
                        //  - if storage is already inserted, and changed
                        //  - storage is not in a package
                        //  - it's a new storage, try to insert and commit if successful inserted
                        if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) )
                        {
                            nLocalRet = pElement->m_xStorage->Commit();
                            pContent = pElement->GetContent();
                        }
                    }
                    else if ( pElement->m_xStream.Is() )
                    {
                        // element is a stream
                        nLocalRet = pElement->m_xStream->Commit();
                        if ( pElement->m_xStream->m_bIsOLEStorage )
                        {
                            // OLE storage should be stored encrytped, if the storage uses encryption
                            pElement->m_xStream->m_aContentType = String::CreateFromAscii("application/vnd.sun.star.oleobject");
                            Any aValue;
                            aValue <<= (sal_Bool) sal_True;
                            pElement->m_xStream->m_pContent->setPropertyValue(String::CreateFromAscii("Encrypted"), aValue );
                        }

                        pContent = pElement->GetContent();
                    }

                    if ( pElement->m_aName != pElement->m_aOriginalName )
                    {
                        // name ( title ) of the element was changed
                        nLocalRet = COMMIT_RESULT_SUCCESS;
                        Any aAny;
                        aAny <<= (rtl::OUString) pElement->m_aName;
                        pContent->setPropertyValue( ::rtl::OUString::createFromAscii("Title"), aAny );
                    }

                    if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() )
                    {
                        // mediatype of the element was changed
                        nLocalRet = COMMIT_RESULT_SUCCESS;
                        Any aAny;
                        aAny <<= (rtl::OUString) pElement->GetContentType();
                        pContent->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny );
                    }

                    if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO )
                        nRet = nLocalRet;
                }

                if ( bDeleteContent )
                    // content was created inside the loop
                    delete pContent;

                if ( nRet == COMMIT_RESULT_FAILURE )
                    break;

                pElement = m_aChildrenList.Next();
            }
        }
        catch ( ContentCreationException& )
        {
            // content could not be created
            SetError( ERRCODE_IO_NOTEXISTS );
            return COMMIT_RESULT_FAILURE;
        }
        catch ( CommandAbortedException& )
        {
            // any command wasn't executed successfully - not specified
            SetError( ERRCODE_IO_GENERAL );
            return COMMIT_RESULT_FAILURE;
        }
        catch ( RuntimeException& )
        {
            // any other error - not specified
            SetError( ERRCODE_IO_GENERAL );
            return COMMIT_RESULT_FAILURE;
        }
        catch ( Exception& )
        {
            // any other error - not specified
            SetError( ERRCODE_IO_GENERAL );
            return COMMIT_RESULT_FAILURE;
        }

        if ( m_bIsRoot && m_pContent )
        {
            // the root storage must flush the root package content
            if ( nRet == COMMIT_RESULT_SUCCESS )
            {
                try
                {
                    // commit the media type to the JAR file
                    // clipboard format and ClassId will be retrieved from the media type when the file is loaded again
                    Any aType;
                    aType <<= (rtl::OUString) m_aContentType;
                    m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType );

                    if (  m_bIsLinked )
                    {
                        // write a manifest file
                        // first create a subfolder "META-inf"
                        Content aNewSubFolder;
                        sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, String::CreateFromAscii("META-INF"), aNewSubFolder );
                        if ( bRet )
                        {
                            // create a stream to write the manifest file - use a temp file
                            String aURL( aNewSubFolder.getURL() );
                            ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL );

                            // get the stream from the temp file and create an output stream wrapper
                            SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE );
                            ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream );
                            com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper );

                            // create a manifest writer object that will fill the stream
                            Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter =
                                Reference< ::com::sun::star::packages::manifest::XManifestWriter >
                                    ( ::comphelper::getProcessServiceFactory()->createInstance(
                                        ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestWriter" )), UNO_QUERY) ;
                            sal_Int32 nCount = GetObjectCount() + 1;
                            Sequence < Sequence < PropertyValue > > aProps( nCount );
                            sal_Int32 nProps = 0;
                            GetProps( nProps, aProps, String() );
                            xWriter->writeManifestSequence( xOutputStream, aProps );

                            // move the stream to its desired location
                            Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
                            xWriter = NULL;
                            xOutputStream = NULL;
                            DELETEZ( pTempFile );
                            aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE );
                        }
                    }
                    else
                    {
#if OSL_DEBUG_LEVEL > 1
                        fprintf ( stderr, "Files: %i\n", nOpenFiles );
                        fprintf ( stderr, "Streams: %i\n", nOpenStreams );
#endif
                        // force writing
                        Any aAny;
                        m_pContent->executeCommand( ::rtl::OUString::createFromAscii("flush"), aAny );
                        if ( m_pSource != 0 )
                        {
                            SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ );
                            m_pSource->SetStreamSize(0);
                            // m_pSource->Seek(0);
                            *pStream >> *m_pSource;
                            DELETEZ( pStream );
                            m_pSource->Seek(0);
                        }
                    }
                }
                catch ( CommandAbortedException& )
                {
                    // how to tell the content : forget all changes ?!
                    // or should we assume that the content does it by itself because he throwed an exception ?!
                    // any command wasn't executed successfully - not specified
                    SetError( ERRCODE_IO_GENERAL );
                    return COMMIT_RESULT_FAILURE;
                }
                catch ( RuntimeException& )
                {
                    // how to tell the content : forget all changes ?!
                    // or should we assume that the content does it by itself because he throwed an exception ?!
                    // any other error - not specified
                    SetError( ERRCODE_IO_GENERAL );
                    return COMMIT_RESULT_FAILURE;
                }
                catch ( InteractiveIOException& r )
                {
                    if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
                        SetError( ERRCODE_IO_ACCESSDENIED );
                    else if ( r.Code == IOErrorCode_NOT_EXISTING )
                        SetError( ERRCODE_IO_NOTEXISTS );
                    else if ( r.Code == IOErrorCode_CANT_READ )
                        SetError( ERRCODE_IO_CANTREAD );
                    else if ( r.Code == IOErrorCode_CANT_WRITE )
                        SetError( ERRCODE_IO_CANTWRITE );
                    else
                        SetError( ERRCODE_IO_GENERAL );

                    return COMMIT_RESULT_FAILURE;
                }
                catch ( Exception& )
                {
                    // how to tell the content : forget all changes ?!
                    // or should we assume that the content does it by itself because he throwed an exception ?!
                    // any other error - not specified
                    SetError( ERRCODE_IO_GENERAL );
                    return COMMIT_RESULT_FAILURE;
                }
            }
            else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO )
            {
                // how to tell the content : forget all changes ?! Should we ?!
                SetError( ERRCODE_IO_GENERAL );
                return nRet;
            }

            // after successful root commit all elements names and types are adjusted and all removed elements
            // are also removed from the lists
            UCBStorageElement_Impl* pInnerElement = m_aChildrenList.First();
            sal_Bool bRet = sal_True;
            while ( pInnerElement && bRet )
            {
                UCBStorageElement_Impl* pNext = m_aChildrenList.Next();
                if ( pInnerElement->m_bIsRemoved )
                {
                    // is this correct use of our list class ?!
                    m_aChildrenList.Remove( pInnerElement );
                }
                else
                {
                    pInnerElement->m_aOriginalName = pInnerElement->m_aName;
                    pInnerElement->m_bIsInserted = sal_False;
                }

                pInnerElement = pNext;
            }
        }

        m_bCommited = sal_False;
    }

    return nRet;
}

sal_Bool UCBStorage_Impl::Revert()
{
    UCBStorageElement_Impl* pElement = m_aChildrenList.First();
    sal_Bool bRet = sal_True;
    while ( pElement && bRet )
    {
        pElement->m_bIsRemoved = sal_False;
        if ( pElement->m_bIsInserted )
        {
            m_aChildrenList.Remove( pElement );  // correct usage of list ???
        }
        else
        {
            if ( pElement->m_xStream.Is() )
            {
                pElement->m_xStream->m_bCommited = sal_False;
                pElement->m_xStream->Revert();
            }
            else if ( pElement->m_xStorage.Is() )
            {
                pElement->m_xStorage->m_bCommited = sal_False;
                pElement->m_xStorage->Revert();
            }

            pElement->m_aName = pElement->m_aOriginalName;
            pElement->m_bIsRemoved = sal_False;
        }

        pElement = m_aChildrenList.Next();
    }

    return bRet;
}

const String& UCBStorage::GetName() const
{
    return pImp->m_aName; // pImp->m_aURL ?!
}

sal_Bool UCBStorage::IsRoot() const
{
    return pImp->m_bIsRoot;
}

void UCBStorage::SetDirty()
{
    pImp->m_bDirty = sal_True;
}

void UCBStorage::SetClass( const SvGlobalName & rClass, sal_uLong nOriginalClipFormat, const String & rUserTypeName )
{
    pImp->m_aClassId = rClass;
    pImp->m_nFormat = nOriginalClipFormat;
    pImp->m_aUserTypeName = rUserTypeName;

    // in UCB storages only the content type will be stored, all other information can be reconstructed
    // ( see the UCBStorage_Impl::Init() method )
    ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
    SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
    pImp->m_aContentType = aDataFlavor.MimeType;
}

void UCBStorage::SetClassId( const ClsId& rClsId )
{
    pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId );
    if ( pImp->m_aClassId == SvGlobalName() )
        return;

    // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are
    // stored in one the substreams
    // UCB storages store the content type information as content type in the manifest file and so this information must be
    // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from
    // the content type
    pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId );
    if ( pImp->m_nFormat )
    {
        ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
        SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor );
        pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName;
        pImp->m_aContentType = aDataFlavor.MimeType;
    }
}

const ClsId& UCBStorage::GetClassId() const
{
    return ( const ClsId& ) pImp->m_aClassId.GetCLSID();
}

void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, sal_uLong /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ )
{
    // ???
}

sal_Bool UCBStorage::ShouldConvert()
{
    // ???
    return sal_False;
}

SvGlobalName UCBStorage::GetClassName()
{
    return  pImp->m_aClassId;
}

sal_uLong UCBStorage::GetFormat()
{
    return pImp->m_nFormat;
}

String UCBStorage::GetUserName()
{
    DBG_ERROR("UserName is not implemented in UCB storages!" );
    return pImp->m_aUserTypeName;
}

void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const
{
    // put information in childrenlist into StorageInfoList
    UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
    while ( pElement )
    {
        if ( !pElement->m_bIsRemoved )
        {
            // problem: what about the size of a substorage ?!
            sal_uLong nSize = pElement->m_nSize;
            if ( pElement->m_xStream.Is() )
                nSize = pElement->m_xStream->GetSize();
            SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage );
            pList->Append( aInfo );
        }

        pElement = pImp->m_aChildrenList.Next();
    }
}

sal_Bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const String& rNew ) const
{
    // insert stream or storage into the list or stream of the destination storage
    // not into the content, this will be done on commit !
    // be aware of name changes !
    if ( !rElement.m_bIsStorage )
    {
        // copy the streams data
        // the destination stream must not be open
        BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );
        BaseStorageStream* pStream = NULL;
        sal_Bool bDeleteStream = sal_False;

        // if stream is already open, it is allowed to copy it, so be aware of this
        if ( rElement.m_xStream.Is() )
            pStream = rElement.m_xStream->m_pAntiImpl;
        if ( !pStream )
        {
            pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect );
            bDeleteStream = sal_True;
        }

        pStream->CopyTo( pOtherStream );
        SetError( pStream->GetError() );
        if( pOtherStream->GetError() )
            pDest->SetError( pOtherStream->GetError() );
        else
            pOtherStream->Commit();

        if ( bDeleteStream )
            delete pStream;
        delete pOtherStream;
    }
    else
    {
        // copy the storage content
        // the destination storage must not be open
        BaseStorage* pStorage = NULL;

        // if stream is already open, it is allowed to copy it, so be aware of this
        sal_Bool bDeleteStorage = sal_False;
        if ( rElement.m_xStorage.Is() )
            pStorage = rElement.m_xStorage->m_pAntiImpl;
        if ( !pStorage )
        {
            pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect );
            bDeleteStorage = sal_True;
        }

        UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
        UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );

        sal_Bool bOpenUCBStorage = pUCBDest && pUCBCopy;
        BaseStorage* pOtherStorage = bOpenUCBStorage ?
                pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) :
                pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect );

        // For UCB storages, the class id and the format id may differ,
        // do passing the class id is not sufficient.
        if( bOpenUCBStorage )
            pOtherStorage->SetClass( pStorage->GetClassName(),
                                     pStorage->GetFormat(),
                                     pUCBCopy->pImp->m_aUserTypeName );
        else
            pOtherStorage->SetClassId( pStorage->GetClassId() );
        pStorage->CopyTo( pOtherStorage );
        SetError( pStorage->GetError() );
        if( pOtherStorage->GetError() )
            pDest->SetError( pOtherStorage->GetError() );
        else
            pOtherStorage->Commit();

        if ( bDeleteStorage )
            delete pStorage;
        delete pOtherStorage;
    }

    return sal_Bool( Good() && pDest->Good() );
}

UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const String& rName ) const
{
    DBG_ASSERT( rName.Len(), "Name is empty!" );
    UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
    while ( pElement )
    {
        if ( pElement->m_aName == rName && !pElement->m_bIsRemoved )
            break;
        pElement = pImp->m_aChildrenList.Next();
    }

    return pElement;
}

sal_Bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const
{
    DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
    if ( pDestStg == ((BaseStorage*)this) )
        return sal_False;

    // perhaps it's also a problem if one storage is a parent of the other ?!
    // or if not: could be optimized ?!

    // For UCB storages, the class id and the format id may differ,
    // do passing the class id is not sufficient.
    if( pDestStg->ISA( UCBStorage ) )
        pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat,
                            pImp->m_aUserTypeName );
    else
        pDestStg->SetClassId( GetClassId() );
    pDestStg->SetDirty();

    sal_Bool bRet = sal_True;
    UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First();
    while ( pElement && bRet )
    {
        if ( !pElement->m_bIsRemoved )
            bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName );
        pElement = pImp->m_aChildrenList.Next();
    }

    if( !bRet )
        SetError( pDestStg->GetError() );
    return sal_Bool( Good() && pDestStg->Good() );
}

sal_Bool UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew )
{
    if( !rElemName.Len() )
        return sal_False;

    if ( pDest == ((BaseStorage*) this) )
    {
        // can't double an element
        return sal_False;
    }
    else
    {
        // for copying no optimization is useful, because in every case the stream data must be copied
            UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName );
        if ( pElement )
            return CopyStorageElement_Impl( *pElement, pDest, rNew );
        else
        {
            SetError( SVSTREAM_FILE_NOT_FOUND );
            return sal_False;
        }
    }
}

sal_Bool UCBStorage::Commit()
{
    // mark this storage for sending it on root commit
    pImp->m_bCommited = sal_True;
    if ( pImp->m_bIsRoot )
        // the root storage coordinates committing by sending a Commit command to its content
        return ( pImp->Commit() != COMMIT_RESULT_FAILURE );
    else
        return sal_True;
}

sal_Bool UCBStorage::Revert()
{
    return pImp->Revert();
}

BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
{
    if( !rEleName.Len() )
        return NULL;

    // try to find the storage element
    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    if ( !pElement )
    {
        // element does not exist, check if creation is allowed
        if( ( nMode & STREAM_NOCREATE ) )
        {
            SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
            String aName( pImp->m_aURL );
            aName += '/';
            aName += rEleName;
            UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
            pStream->SetError( GetError() );
            pStream->pImp->m_aName = rEleName;
            return pStream;
        }
        else
        {
            // create a new UCBStorageElement and insert it into the list
            pElement = new UCBStorageElement_Impl( rEleName );
            pElement->m_bIsInserted = sal_True;
            pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
        }
    }

    if ( pElement && !pElement->m_bIsFolder )
    {
        // check if stream is already created
        if ( pElement->m_xStream.Is() )
        {
            // stream has already been created; if it has no external reference, it may be opened another time
            if ( pElement->m_xStream->m_pAntiImpl )
            {
                DBG_ERROR("Stream is already open!" );
                SetError( SVSTREAM_ACCESS_DENIED );  // ???
                return NULL;
            }
            else
            {
                // check if stream is opened with the same keyword as before
                // if not, generate a new stream because it could be encrypted vs. decrypted!
                ByteString aKey;
                if ( pKey )
                    aKey = *pKey;
                if ( pElement->m_xStream->m_aKey == aKey )
                {
                    pElement->m_xStream->PrepareCachedForReopen( nMode );

    //              DBG_ASSERT( bDirect == pElement->m_xStream->m_bDirect, "Wrong DirectMode!" );
                    return new UCBStorageStream( pElement->m_xStream );
                }
            }
        }

        // stream is opened the first time
        pImp->OpenStream( pElement, nMode, bDirect, pKey );

        // if name has been changed before creating the stream: set name!
        pElement->m_xStream->m_aName = rEleName;
        return new UCBStorageStream( pElement->m_xStream );
    }

    return NULL;
}

UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey )
{
    String aName( m_aURL );
    aName += '/';
    aName += pElement->m_aOriginalName;
    pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler );
    return pElement->m_xStream;
}

BaseStorage* UCBStorage::OpenUCBStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
{
    if( !rEleName.Len() )
        return NULL;

    return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
}

BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
{
    if( !rEleName.Len() )
        return NULL;

    return OpenStorage_Impl( rEleName, nMode, bDirect, sal_False );
}

BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect )
{
    if( !rEleName.Len() )
        return NULL;

    return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True );
}

BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, sal_Bool bDirect, sal_Bool bForceUCBStorage )
{
    // try to find the storage element
    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    if ( !pElement )
    {
        // element does not exist, check if creation is allowed
        if( ( nMode & STREAM_NOCREATE ) )
        {
            SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
            String aName( pImp->m_aURL );
            aName += '/';
            aName += rEleName;  //  ???
            UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
            pStorage->pImp->m_bIsRoot = sal_False;
            pStorage->pImp->m_bListCreated = sal_True; // the storage is pretty new, nothing to read
            pStorage->SetError( GetError() );
            return pStorage;
        }

        // create a new UCBStorageElement and insert it into the list
        // problem: perhaps an OLEStorage should be created ?!
        // Because nothing is known about the element that should be created, an external parameter is needed !
        pElement = new UCBStorageElement_Impl( rEleName );
        pElement->m_bIsInserted = sal_True;
        pImp->m_aChildrenList.Insert( pElement, LIST_APPEND );
    }

    if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) )
    {
        // create OLE storages on a stream ( see ctor of SotStorage )
        // Such a storage will be created on a UCBStorageStream; it will write into the stream
        // if it is opened in direct mode or when it is committed. In this case the stream will be
        // modified and then it MUST be treated as commited.
        if ( !pElement->m_xStream.Is() )
        {
            BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect );
            UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr );
            if ( !pStream )
            {
                SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
                return NULL;
            }

            pElement->m_xStream = pStream->pImp;
            delete pStream;
        }

        pElement->m_xStream->PrepareCachedForReopen( nMode );
        pElement->m_xStream->Init();

        pElement->m_bIsStorage = sal_True;
        return pElement->m_xStream->CreateStorage();  // can only be created in transacted mode
    }
    else if ( pElement->m_xStorage.Is() )
    {
        // storage has already been opened; if it has no external reference, it may be opened another time
        if ( pElement->m_xStorage->m_pAntiImpl )
        {
            DBG_ERROR("Storage is already open!" );
            SetError( SVSTREAM_ACCESS_DENIED );  // ???
        }
        else
        {
            sal_Bool bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0);
            if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 ))
            {
                String aName( pImp->m_aURL );
                aName += '/';
                aName += pElement->m_aOriginalName;
                UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
                pElement->m_xStorage = pStorage->pImp;
                return pStorage;
            }
            else
            {
//                    DBG_ASSERT( bDirect == pElement->m_xStorage->m_bDirect, "Wrong DirectMode!" );
                return new UCBStorage( pElement->m_xStorage );
            }
        }
    }
    else if ( !pElement->m_xStream.Is() )
    {
        // storage is opened the first time
        sal_Bool bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 );
        if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable )
        {
            // make sure that the root storage object has been created before substorages will be created
            INetURLObject aFolderObj( pImp->m_aURL );
            String aName = aFolderObj.GetName();
            aFolderObj.removeSegment();

            Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >() );
            pImp->m_pContent = new Content;
            sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent );
            if ( !bRet )
            {
                SetError( SVSTREAM_CANNOT_MAKE );
                return NULL;
            }
        }

        UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect );
        if ( pStor )
        {
            if ( pElement->m_bIsInserted )
                pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read

            return new UCBStorage( pStor );
        }
    }

    return NULL;
}

UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect )
{
    UCBStorage_Impl* pRet = NULL;
    String aName( m_aURL );
    aName += '/';
    aName += pElement->m_aOriginalName;  //  ???

    pElement->m_bIsStorage = pElement->m_bIsFolder = sal_True;

    if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
    {
        Content aNewFolder;
        sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
        if ( bRet )
            pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
    }
    else
    {
        pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler );
    }

    if ( pRet )
    {
        pRet->m_bIsLinked = m_bIsLinked;
        pRet->m_bIsRoot = sal_False;

        // if name has been changed before creating the stream: set name!
        pRet->m_aName = pElement->m_aOriginalName;
        pElement->m_xStorage = pRet;
    }

    if ( pRet )
        pRet->Init();

    return pRet;
}

sal_Bool UCBStorage::IsStorage( const String& rEleName ) const
{
    if( !rEleName.Len() )
        return sal_False;

    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    return ( pElement && pElement->m_bIsStorage );
}

sal_Bool UCBStorage::IsStream( const String& rEleName ) const
{
    if( !rEleName.Len() )
        return sal_False;

    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    return ( pElement && !pElement->m_bIsStorage );
}

sal_Bool UCBStorage::IsContained( const String & rEleName ) const
{
    if( !rEleName.Len() )
        return sal_False;
    const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    return ( pElement != NULL );
}

sal_Bool UCBStorage::Remove( const String& rEleName )
{
    if( !rEleName.Len() )
        return sal_False;

    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    if ( pElement )
    {
        pElement->m_bIsRemoved = sal_True;
    }
    else
        SetError( SVSTREAM_FILE_NOT_FOUND );

    return ( pElement != NULL );
}

sal_Bool UCBStorage::Rename( const String& rEleName, const String& rNewName )
{
    if( !rEleName.Len()|| !rNewName.Len() )
        return sal_False;

    UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
    if ( pAlreadyExisting )
    {
        SetError( SVSTREAM_ACCESS_DENIED );
        return sal_False;                       // can't change to a name that is already used
    }

    UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
    if ( pElement )
    {
        pElement->m_aName = rNewName;
    }
    else
        SetError( SVSTREAM_FILE_NOT_FOUND );

    return pElement != NULL;
}

sal_Bool UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName )
{
    if( !rEleName.Len() || !rNewName.Len() )
        return sal_False;

    if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) )
    {
        return Rename( rEleName, rNewName );
    }
    else
    {
/*
        if ( PTR_CAST( UCBStorage, pNewSt ) )
        {
            // because the element is moved, not copied, a special optimization is possible :
            // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted",
            // clear original name/type of the new element
            // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ),
            // clear original name/type of new content, keep the old original stream/storage, but forget its working streams,
                // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now
            // belong to the new content
            // if original and editable stream are identical ( readonly element ), it has to be copied to the editable
            // stream of the destination object
            // Not implemented at the moment ( risky?! ), perhaps later
        }
*/
        // MoveTo is done by first copying to the new destination and then removing the old element
        sal_Bool bRet = CopyTo( rEleName, pNewSt, rNewName );
        if ( bRet )
            bRet = Remove( rEleName );
        return bRet;
    }
}

sal_Bool UCBStorage::ValidateFAT()
{
    // ???
    return sal_True;
}

sal_Bool UCBStorage::Validate( sal_Bool  bWrite ) const
{
    // ???
    return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
}

sal_Bool UCBStorage::ValidateMode( StreamMode m ) const
{
    // ???
    if( m == ( STREAM_READ | STREAM_TRUNC ) )  // from stg.cxx
        return sal_True;
    sal_uInt16 nCurMode = 0xFFFF;
    if( ( m & 3 ) == STREAM_READ )
    {
        // only SHARE_DENYWRITE or SHARE_DENYALL allowed
        if( ( ( m & STREAM_SHARE_DENYWRITE )
           && ( nCurMode & STREAM_SHARE_DENYWRITE ) )
         || ( ( m & STREAM_SHARE_DENYALL )
           && ( nCurMode & STREAM_SHARE_DENYALL ) ) )
            return sal_True;
    }
    else
    {
        // only SHARE_DENYALL allowed
        // storages open in r/o mode are OK, since only
        // the commit may fail
        if( ( m & STREAM_SHARE_DENYALL )
         && ( nCurMode & STREAM_SHARE_DENYALL ) )
            return sal_True;
    }

    return sal_True;
}

const SvStream* UCBStorage::GetSvStream() const
{
    // this would cause a complete download of the file
    // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ???
    return pImp->m_pSource;
}

sal_Bool UCBStorage::Equals( const BaseStorage& rStorage ) const
{
    // ???
    return ((BaseStorage*)this) == &rStorage;
}

sal_Bool UCBStorage::IsStorageFile( const String& rFileName )
{
    String aFileURL = rFileName;
    INetURLObject aObj( aFileURL );
    if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
    {
        ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFileName, aFileURL );
        aObj.SetURL( aFileURL );
        aFileURL = aObj.GetMainURL( INetURLObject::NO_DECODE );
    }

    SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_STD_READ );
    sal_Bool bRet = UCBStorage::IsStorageFile( pStm );
    delete pStm;
    return bRet;
}

sal_Bool UCBStorage::IsStorageFile( SvStream* pFile )
{
    if ( !pFile )
        return sal_False;

    sal_uLong nPos = pFile->Tell();
    pFile->Seek( STREAM_SEEK_TO_END );
    if ( pFile->Tell() < 4 )
        return sal_False;

    pFile->Seek(0);
    sal_uInt32 nBytes;
    *pFile >> nBytes;

    // search for the magic bytes
    sal_Bool bRet = ( nBytes == 0x04034b50 );
    if ( !bRet )
    {
        // disk spanned file have an additional header in front of the usual one
        bRet = ( nBytes == 0x08074b50 );
        if ( bRet )
        {
            *pFile >> nBytes;
            bRet = ( nBytes == 0x04034b50 );
        }
    }

    pFile->Seek( nPos );
    return bRet;
}

sal_Bool UCBStorage::IsDiskSpannedFile( SvStream* pFile )
{
    if ( !pFile )
        return sal_False;

    sal_uLong nPos = pFile->Tell();
    pFile->Seek( STREAM_SEEK_TO_END );
    if ( !pFile->Tell() )
        return sal_False;

    pFile->Seek(0);
    sal_uInt32 nBytes;
    *pFile >> nBytes;

    // disk spanned file have an additional header in front of the usual one
    sal_Bool bRet = ( nBytes == 0x08074b50 );
    if ( bRet )
    {
        *pFile >> nBytes;
        bRet = ( nBytes == 0x04034b50 );
    }

    pFile->Seek( nPos );
    return bRet;
}

String UCBStorage::GetLinkedFile( SvStream &rStream )
{
    String aString;
    sal_uLong nPos = rStream.Tell();
    rStream.Seek( STREAM_SEEK_TO_END );
    if ( !rStream.Tell() )
        return aString;

    rStream.Seek(0);
    sal_uInt32 nBytes;
    rStream >> nBytes;
    if( nBytes == 0x04034b50 )
    {
        ByteString aTmp;
        rStream.ReadByteString( aTmp );
        if ( aTmp.CompareTo( "ContentURL=", 11 ) == COMPARE_EQUAL )
        {
            aTmp.Erase( 0, 11 );
            aString = String( aTmp, RTL_TEXTENCODING_UTF8 );
        }
    }

    rStream.Seek( nPos );
    return aString;
}

String UCBStorage::CreateLinkFile( const String& rName )
{
    // create a stream to write the link file - use a temp file, because it may be no file content
    INetURLObject aFolderObj( rName );
    String aName = aFolderObj.GetName();
    aFolderObj.removeSegment();
    String aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) );
    ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL );

    // get the stream from the temp file
    SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC );

    // write header
    *pStream << ( sal_uInt32 ) 0x04034b50;

    // assemble a new folder name in the destination folder
    INetURLObject aObj( rName );
    String aTmpName = aObj.GetName();
    String aTitle = String::CreateFromAscii( "content." );
    aTitle += aTmpName;

    // create a folder and store its URL
    Content aFolder( aFolderURL, Reference < XCommandEnvironment >() );
    Content aNewFolder;
    sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder );
    if ( !bRet )
    {
        aFolderObj.insertName( aTitle );
        if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
        {
            // Hack, because already existing files give the same CommandAbortedException as any other error !
            // append a number until the name can be used for a new folder
            aTitle += '.';
            for ( sal_Int32 i=0; !bRet; i++ )
            {
                String aTmp( aTitle );
                aTmp += String::CreateFromInt32( i );
                bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder );
                if ( bRet )
                    aTitle = aTmp;
                else
                {
                    aFolderObj.SetName( aTmp );
                    if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) )
                        // Hack, because already existing files give the same CommandAbortedException as any other error !
                        break;
                }
            }
        }
    }

    if ( bRet )
    {
        // get the URL
        aObj.SetName( aTitle );
        String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE );

        // store it as key/value pair
        String aLink = String::CreateFromAscii("ContentURL=");
        aLink += aURL;
        pStream->WriteByteString( aLink, RTL_TEXTENCODING_UTF8 );
        pStream->Flush();

        // move the stream to its desired location
        Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() );
        DELETEZ( pTempFile );
        aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE );
        return aURL;
    }

    pTempFile->EnableKillingFile( sal_True );
    delete pTempFile;
    return String();
}

sal_Bool UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
{
    if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
        return sal_False;

    if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
    {
        ::rtl::OUString aTmp;
        rValue >>= aTmp;
        pImp->m_aContentType = aTmp;
    }

    try
    {
        if ( pImp->GetContent() )
        {
            pImp->m_pContent->setPropertyValue( rName, rValue );
            return sal_True;
        }
    }
    catch ( Exception& )
    {
    }

    return sal_False;
}

sal_Bool UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
{
    try
    {
        if ( pImp->GetContent() )
        {
            rValue = pImp->m_pContent->getPropertyValue( rName );
            return sal_True;
        }
    }
    catch ( Exception& )
    {
    }

    return sal_False;
}

sal_Bool UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
{
    UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName );
    if ( !pEle )
        return sal_False;

    if ( !pEle->m_bIsFolder )
    {
        if ( !pEle->m_xStream.Is() )
            pImp->OpenStream( pEle, pImp->m_nMode, pImp->m_bDirect );
        if ( pEle->m_xStream->m_nError )
        {
            pEle->m_xStream.Clear();
            return sal_False;
        }

        try
        {
            if ( pEle->m_xStream->m_pContent )
            {
                rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName );
                return sal_True;
            }
        }
        catch ( Exception& )
        {
        }
    }
    else
    {
        if ( !pEle->m_xStorage.Is() )
            pImp->OpenStorage( pEle, pImp->m_nMode, pImp->m_bDirect );
        if ( pEle->m_xStorage->m_nError )
        {
            pEle->m_xStorage.Clear();
            return sal_False;
        }

        try
        {
            if ( pEle->m_xStorage->GetContent() )
            {
                rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName );
                return sal_True;
            }
        }
        catch ( Exception& )
        {
        }
    }

    return sal_False;
}

UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList()
{
    if ( !pImp->m_pUNOStorageHolderList )
        pImp->m_pUNOStorageHolderList = new UNOStorageHolderList;

    return pImp->m_pUNOStorageHolderList;
}