/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sot.hxx"
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>

#include <rtl/digest.h>
#include <osl/file.hxx>
#include <sot/stg.hxx>
#include <sot/storinfo.hxx>
#include <sot/storage.hxx>
#include <sot/formats.hxx>
#include <sot/exchange.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <tools/fsys.hxx>
#include <tools/cachestr.hxx>
#include <tools/debug.hxx>
#include <tools/urlobj.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/ucbhelper.hxx>
#include <comphelper/processfactory.hxx>

#include "unostorageholder.hxx"

using namespace ::com::sun::star;

/************** class SotStorageStream ***********************************/
class SotStorageStreamFactory : public SotFactory
{
public:
         TYPEINFO();
        SotStorageStreamFactory( const SvGlobalName & rName,
                              const String & rClassName,
                              CreateInstanceType pCreateFuncP )
            : SotFactory( rName, rClassName, pCreateFuncP )
        {}
};
TYPEINIT1(SotStorageStreamFactory,SotFactory);


SO2_IMPL_BASIC_CLASS1_DLL(SotStorageStream,SotStorageStreamFactory,SotObject,
                        SvGlobalName( 0xd7deb420, 0xf902, 0x11d0,
                            0xaa, 0xa1, 0x0, 0xa0, 0x24, 0x9d, 0x55, 0x90 ) )
SO2_IMPL_INVARIANT(SotStorageStream)


void SotStorageStream::TestMemberObjRef( sal_Bool /*bFree*/ )
{
}

#ifdef TEST_INVARIANT
void SotStorageStream::TestMemberInvariant( sal_Bool /*bPrint*/ )
{
}
#endif

/************************************************************************
|*    SotStorageStream::SotStorageStream()
|*
|*    Beschreibung
*************************************************************************/
SvLockBytesRef MakeLockBytes_Impl( const String & rName, StreamMode nMode )
{
    SvLockBytesRef xLB;
    if( rName.Len() )
    {
        SvStream * pFileStm = new SvFileStream( rName, nMode );
        xLB = new SvLockBytes( pFileStm, sal_True );
    }
    else
    {
        SvStream * pCacheStm = new SvCacheStream();
        xLB = new SvLockBytes( pCacheStm, sal_True );
    }
    return xLB;
}

SotStorageStream::SotStorageStream( const String & rName, StreamMode nMode,
                                  StorageMode
                                  #ifdef DBG_UTIL
                                  nStorageMode
                                  #endif
                                  )
    : SvStream( MakeLockBytes_Impl( rName, nMode ) )
    , pOwnStm( NULL )
{
    if( nMode & STREAM_WRITE )
        bIsWritable = sal_True;
    else
        bIsWritable = sal_False;

    DBG_ASSERT( !nStorageMode,"StorageModes ignored" );
}

SotStorageStream::SotStorageStream( BaseStorageStream * pStm )
{
    if( pStm )
    {
        if( STREAM_WRITE & pStm->GetMode() )
            bIsWritable = sal_True;
        else
            bIsWritable = sal_False;

        pOwnStm = pStm;
        SetError( pStm->GetError() );
        pStm->ResetError();
    }
    else
    {
        pOwnStm = NULL;
        bIsWritable = sal_True;
        SetError( SVSTREAM_INVALID_PARAMETER );
    }
}

SotStorageStream::SotStorageStream()
    : pOwnStm( NULL )
{
    // ??? wenn Init virtuell ist, entsprechen setzen
    bIsWritable = sal_True;
}

/************************************************************************
|*    SotStorageStream::~SotStorageStream()
|*
|*    Beschreibung
*************************************************************************/
SotStorageStream::~SotStorageStream()
{
    Flush(); //SetBufferSize(0);
    delete pOwnStm;
}

/*************************************************************************
|*    SotStorageStream::SyncSvStream()
|*
|*    Beschreibung: Der SvStream wird auf den Zustand des Standard-Streams
|*	  				gesetzt. Der Puffer des SvStreams wird weggeworfen.
*************************************************************************/
void SotStorageStream::SyncSvStream()
{
    if( pOwnStm )
    {
        pOwnStm->Flush();
        sal_uLong nPos = pOwnStm->Tell();
        SetError( pOwnStm->GetError() );
        SvStream::SyncSvStream( nPos );
    }
}

/*************************************************************************
|*    SotStorageStream::ResetError()
|*
|*    Beschreibung
*************************************************************************/
void SotStorageStream::ResetError()
{
    SvStream::ResetError();
    if( pOwnStm )
         pOwnStm->ResetError();
}

/*************************************************************************
|*    SotStorageStream::GetData()
|*
|*    Beschreibung
*************************************************************************/
sal_uLong SotStorageStream::GetData( void* pData, sal_uLong nSize )
{
    sal_uLong nRet = 0;

    if( pOwnStm )
    {
        nRet = pOwnStm->Read( pData, nSize );
        SetError( pOwnStm->GetError() );
    }
    else
        nRet = SvStream::GetData( (sal_Char *)pData, nSize );
    return nRet;
}

/*************************************************************************
|*    SotStorageStream::PutData()
|*
|*    Beschreibung
*************************************************************************/
sal_uLong SotStorageStream::PutData( const void* pData, sal_uLong nSize )
{
    sal_uLong nRet = 0;

    if( pOwnStm )
    {
        nRet = pOwnStm->Write( pData, nSize );
        SetError( pOwnStm->GetError() );
    }
    else
        nRet = SvStream::PutData( (sal_Char *)pData, nSize );
    return nRet;
}

/*************************************************************************
|*    SotStorageStream::SeekPos()
|*
|*    Beschreibung
*************************************************************************/
sal_uLong SotStorageStream::SeekPos( sal_uLong nPos )
{
    sal_uLong nRet = 0;

    if( pOwnStm )
    {
        nRet = pOwnStm->Seek( nPos );
        SetError( pOwnStm->GetError() );
    }
    else
        nRet = SvStream::SeekPos( nPos );
    return nRet;
}

/*************************************************************************
|*    SotStorageStream::Flush()
|*
|*    Beschreibung
*************************************************************************/
void SotStorageStream::FlushData()
{
    if( pOwnStm )
    {
        pOwnStm->Flush();
        SetError( pOwnStm->GetError() );
    }
    else
        SvStream::FlushData();
}

/*************************************************************************
|*    SotStorageStream::SetSize()
|*
|*    Beschreibung
*************************************************************************/
void SotStorageStream::SetSize( sal_uLong nNewSize )
{
    sal_uLong   nPos = Tell();
    if( pOwnStm )
    {
        pOwnStm->SetSize( nNewSize );
        SetError( pOwnStm->GetError() );
    }
    else
        SvStream::SetSize( nNewSize );

    if( nNewSize < nPos )
        // ans Ende setzen
        Seek( nNewSize );

    //return GetError() == SVSTREAM_OK;
}

/*************************************************************************
|*
|*    SotStorageStream::GetSize()
|*
|*    Beschreibung
|*
*************************************************************************/
sal_uInt32 SotStorageStream::GetSize() const
{
    sal_uLong nPos = Tell();
    ((SotStorageStream *)this)->Seek( STREAM_SEEK_TO_END );
    sal_uLong nSize = Tell();
    ((SotStorageStream *)this)->Seek( nPos );
    return nSize;
}

/*************************************************************************
|*    SotStorageStream::CopyTo()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorageStream::CopyTo( SotStorageStream * pDestStm )
{
    Flush(); // alle Daten schreiben
    pDestStm->ClearBuffer();
    if( !pOwnStm || !pDestStm->pOwnStm )
    { // Wenn Ole2 oder nicht nur eigene StorageStreams

        sal_uLong nPos = Tell();    // Position merken
        Seek( 0L );
        pDestStm->SetSize( 0 ); // Ziel-Stream leeren

        void * pMem = new sal_uInt8[ 8192 ];
        sal_uLong  nRead;
        while( 0 != (nRead = Read( pMem, 8192 )) )
        {
            if( nRead != pDestStm->Write( pMem, nRead ) )
            {
                SetError( SVSTREAM_GENERALERROR );
                break;
            }
        }
        delete [] static_cast<sal_uInt8*>(pMem);
        // Position setzen
        pDestStm->Seek( nPos );
        Seek( nPos );
    }
    else
    {
        /*
        // Kopieren
        nErr = pObjI->CopyTo( pDestStm->pObjI, uSize, NULL, &uWrite );
        if( SUCCEEDED( nErr ) )
        {
            // Ziel-Streamzeiger steht hinter den Daten
            // SvSeek abgleichen
            pDestStm->Seek( uWrite.LowPart );
        }
        else if( GetScode( nErr ) == E_NOTIMPL )
        { // Eines Tages werden alle MS... ?!#
        */
        pOwnStm->CopyTo( pDestStm->pOwnStm );
        SetError( pOwnStm->GetError() );
    }
    return GetError() == SVSTREAM_OK;
}

/*************************************************************************
|*    SotStorageStream::Commit()
|*    SotStorageStream::Revert()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorageStream::Commit()
{
    if( pOwnStm )
    {
        pOwnStm->Flush();
        if( pOwnStm->GetError() == SVSTREAM_OK )
            pOwnStm->Commit();
        SetError( pOwnStm->GetError() );
    }
    return GetError() == SVSTREAM_OK;
}

sal_Bool SotStorageStream::Revert()
{
    if( !pOwnStm )
    {
        pOwnStm->Revert();
        SetError( pOwnStm->GetError() );
    }
    return GetError() == SVSTREAM_OK;
}

sal_Bool SotStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
{
    UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pOwnStm );
    if ( pStg )
    {
        return pStg->SetProperty( rName, rValue );
    }
    else
    {
        OSL_FAIL("Not implemented!");
        return sal_False;
    }
}

sal_Bool SotStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
{
    UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pOwnStm );
    if ( pStg )
    {
        return pStg->GetProperty( rName, rValue );
    }
    else
    {
        OSL_FAIL("Not implemented!");
        return sal_False;
    }
}

::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SotStorageStream::GetXInputStream() const
{
    UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pOwnStm );
    if ( pStg )
    {
        return pStg->GetXInputStream();
    }
    else
    {
        OSL_FAIL("Not implemented!");
        return ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >();
    }
}



/************** class SotStorage ******************************************
*************************************************************************/
class SotStorageFactory : public SotFactory
{
public:
         TYPEINFO();
        SotStorageFactory( const SvGlobalName & rName,
                              const String & rClassName,
                              CreateInstanceType pCreateFuncP )
            : SotFactory( rName, rClassName, pCreateFuncP )
        {}
};
TYPEINIT1(SotStorageFactory,SotFactory);


SO2_IMPL_BASIC_CLASS1_DLL(SotStorage,SotStorageFactory,SotObject,
                        SvGlobalName( 0x980ce7e0, 0xf905, 0x11d0,
                            0xaa, 0xa1, 0x0, 0xa0, 0x24, 0x9d, 0x55, 0x90 ) )
SO2_IMPL_INVARIANT(SotStorage)


/************************************************************************
|*
|*    SotStorage::Tes*()
|*
|*    Beschreibung
*************************************************************************/
void SotStorage::TestMemberObjRef( sal_Bool /*bFree*/ )
{
}

#ifdef TEST_INVARIANT
void SotStorage::TestMemberInvariant( sal_Bool /*bPrint*/ )
{
}
#endif

/************************************************************************
|*
|*    SotStorage::SotStorage()
|*
|*    Beschreibung      Es muss ein I... Objekt an SvObject uebergeben
|*                      werden, da es sonst selbst ein IUnknown anlegt und
|*                      festlegt, dass alle weiteren I... Objekte mit
|*                      delete zerstoert werden (Owner() == sal_True).
|*                      Es werden aber nur IStorage Objekte benutzt und nicht
|*                      selbst implementiert, deshalb wird so getan, als ob
|*                      das IStorage Objekt von aussen kam und es wird mit
|*                      Release() freigegeben.
|*                      Die CreateStorage Methoden werden benoetigt, um
|*                      ein IStorage Objekt vor dem Aufruf von SvObject
|*                      zu erzeugen (Own, !Own automatik).
|*                      Hat CreateStorage ein Objekt erzeugt, dann wurde
|*                      der RefCounter schon um 1 erhoet.
|*                      Die Uebergabe erfolgt in pStorageCTor. Die Variable
|*                      ist NULL, wenn es nicht geklappt hat.
|*
*************************************************************************/
#define INIT_SotStorage()            		\
    : m_pOwnStg( NULL )                       \
    , m_pStorStm( NULL )                      \
    , m_nError( SVSTREAM_OK )         		\
    , m_bIsRoot( sal_False )              		\
    , m_bDelStm( sal_False )						\
    , m_nVersion( SOFFICE_FILEFORMAT_CURRENT )

SotStorage::SotStorage()
    INIT_SotStorage()
{
    // ??? What's this ???
}

#define ERASEMASK  ( STREAM_TRUNC | STREAM_WRITE | STREAM_SHARE_DENYALL )
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/ucb/XCommandEnvironment.hpp>
#include <ucbhelper/content.hxx>

SotStorage::SotStorage( const ::ucbhelper::Content& rContent, const String & rName, StreamMode nMode, StorageMode nStorageMode )
    INIT_SotStorage()
{
    m_aName = rName; // Namen merken
    m_pOwnStg = new UCBStorage( rContent, m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );

    SetError( m_pOwnStg->GetError() );

    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;

    SignAsRoot( m_pOwnStg->IsRoot() );
}

SotStorage::SotStorage( const String & rName, StreamMode nMode, StorageMode nStorageMode )
    INIT_SotStorage()
{
    m_aName = rName; // Namen merken
    CreateStorage( sal_True, nMode, nStorageMode );
    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;
}

void SotStorage::CreateStorage( sal_Bool bForceUCBStorage, StreamMode nMode, StorageMode nStorageMode  )
{
    DBG_ASSERT( !m_pStorStm && !m_pOwnStg, "Use only in ctor!" );
    if( m_aName.Len() )
    {
        // named storage
        if( ( ( nMode & ERASEMASK ) == ERASEMASK ) )
            ::utl::UCBContentHelper::Kill( m_aName );

        INetURLObject aObj( m_aName );
        if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
        {
            String aURL;
            ::utl::LocalFileHelper::ConvertPhysicalNameToURL( m_aName, aURL );
            aObj.SetURL( aURL );
            m_aName = aObj.GetMainURL( INetURLObject::NO_DECODE );
        }

        // a new unpacked storage should be created
        if ( nStorageMode == STORAGE_CREATE_UNPACKED )
        {
            // don't open stream readwrite, content provider may not support this !
            String aURL = UCBStorage::CreateLinkFile( m_aName );
            if ( aURL.Len() )
            {
                ::ucbhelper::Content aContent( aURL, ::com::sun::star::uno::Reference < ::com::sun::star::ucb::XCommandEnvironment >() );
                m_pOwnStg = new UCBStorage( aContent, aURL, nMode, sal_False );
            }
            else
            {
                m_pOwnStg = new Storage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                SetError( ERRCODE_IO_NOTSUPPORTED );
            }
        }
        else
        {
            // check the stream
            m_pStorStm = ::utl::UcbStreamHelper::CreateStream( m_aName, nMode );
            if ( m_pStorStm && m_pStorStm->GetError() )
                DELETEZ( m_pStorStm );

            if ( m_pStorStm )
            {
                // try as UCBStorage, next try as OLEStorage
                sal_Bool bIsUCBStorage = UCBStorage::IsStorageFile( m_pStorStm );
                if ( !bIsUCBStorage && bForceUCBStorage )
                    // if UCBStorage has priority, it should not be used only if it is really an OLEStorage
                    bIsUCBStorage = !Storage::IsStorageFile( m_pStorStm );

                if ( bIsUCBStorage )
                {
                    if ( UCBStorage::GetLinkedFile( *m_pStorStm ).Len() )
                    {
                        // detect special unpacked storages
                        m_pOwnStg = new UCBStorage( *m_pStorStm, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                        m_bDelStm = sal_True;
                    }
                    else
                    {
                        // detect special disk spanned storages
                        if ( UCBStorage::IsDiskSpannedFile( m_pStorStm ) )
                            nMode |= STORAGE_DISKSPANNED_MODE;

                        // UCBStorage always works directly on the UCB content, so discard the stream first
                        DELETEZ( m_pStorStm );
                        m_pOwnStg = new UCBStorage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                    }
                }
                else
                {
                    // OLEStorage can be opened with a stream
                    m_pOwnStg = new Storage( *m_pStorStm, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                    m_bDelStm = sal_True;
                }
            }
            else if ( bForceUCBStorage )
            {
                m_pOwnStg = new UCBStorage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                SetError( ERRCODE_IO_NOTSUPPORTED );
            }
            else
            {
                m_pOwnStg = new Storage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
                SetError( ERRCODE_IO_NOTSUPPORTED );
            }
        }
    }
    else
    {
        // temporary storage
        if ( bForceUCBStorage )
            m_pOwnStg = new UCBStorage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        else
            m_pOwnStg = new Storage( m_aName, nMode, (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        m_aName = m_pOwnStg->GetName();
    }

    SetError( m_pOwnStg->GetError() );

    SignAsRoot( m_pOwnStg->IsRoot() );
}

SotStorage::SotStorage( sal_Bool bUCBStorage, const String & rName, StreamMode nMode, StorageMode nStorageMode )
    INIT_SotStorage()
{
    m_aName = rName;
    CreateStorage( bUCBStorage, nMode, nStorageMode );
    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;
}

SotStorage::SotStorage( BaseStorage * pStor )
    INIT_SotStorage()
{
    if ( pStor )
    {
        m_aName = pStor->GetName(); // Namen merken
        SignAsRoot( pStor->IsRoot() );
        SetError( pStor->GetError() );
    }

    m_pOwnStg = pStor;
    sal_uLong nErr = m_pOwnStg ? m_pOwnStg->GetError() : SVSTREAM_CANNOT_MAKE;
    SetError( nErr );
    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;
}

SotStorage::SotStorage( sal_Bool bUCBStorage, SvStream & rStm )
    INIT_SotStorage()
{
    SetError( rStm.GetError() );

    // try as UCBStorage, next try as OLEStorage
    if ( UCBStorage::IsStorageFile( &rStm ) || bUCBStorage )
        m_pOwnStg = new UCBStorage( rStm, sal_False );
    else
        m_pOwnStg = new Storage( rStm, sal_False );

    SetError( m_pOwnStg->GetError() );

    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;

    SignAsRoot( m_pOwnStg->IsRoot() );
}

SotStorage::SotStorage( SvStream & rStm )
    INIT_SotStorage()
{
    SetError( rStm.GetError() );

    // try as UCBStorage, next try as OLEStorage
    if ( UCBStorage::IsStorageFile( &rStm ) )
        m_pOwnStg = new UCBStorage( rStm, sal_False );
    else
        m_pOwnStg = new Storage( rStm, sal_False );

    SetError( m_pOwnStg->GetError() );

    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;

    SignAsRoot( m_pOwnStg->IsRoot() );
}

SotStorage::SotStorage( SvStream * pStm, sal_Bool bDelete )
    INIT_SotStorage()
{
    SetError( pStm->GetError() );

    // try as UCBStorage, next try as OLEStorage
    if ( UCBStorage::IsStorageFile( pStm ) )
        m_pOwnStg = new UCBStorage( *pStm, sal_False );
    else
        m_pOwnStg = new Storage( *pStm, sal_False );

    SetError( m_pOwnStg->GetError() );

    m_pStorStm = pStm;
    m_bDelStm = bDelete;
    if ( IsOLEStorage() )
        m_nVersion = SOFFICE_FILEFORMAT_50;

    SignAsRoot( m_pOwnStg->IsRoot() );
}

/*************************************************************************
|*    SotStorage::~SotStorage()
|*
|*    Beschreibung
*************************************************************************/
SotStorage::~SotStorage()
{
    delete m_pOwnStg;
    if( m_bDelStm )
        delete m_pStorStm;
}

/*************************************************************************
|*    SotStorage::RemoveUNOStorageHolder()
|*
|*    Beschreibung
*************************************************************************/
void SotStorage::RemoveUNOStorageHolder( UNOStorageHolder* pHolder )
{
    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    if ( pStg )
    {
        pStg->GetUNOStorageHolderList()->remove( pHolder );
        pHolder->release();
    }
    else
    {
        OSL_FAIL("Not implemented!");
    }
}

/*************************************************************************
|*    SotStorage::GetUNOAPIDuplicate()
|*
|*    Beschreibung
*************************************************************************/
uno::Reference< embed::XStorage > SotStorage::GetUNOAPIDuplicate( const String& rEleName, sal_Int32 nUNOStorageMode )
{
    // after we create a duplicate we will register wrapper
    // for storage messages, the wrapper will control the real storage
    // the real storage will be able to ask the duplicate to dispose if it's parent is disposed

    uno::Reference< embed::XStorage > xResult;

    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    if ( !pStg )
        return xResult;

    UNOStorageHolderList* pUNOStorageHolderList = pStg->GetUNOStorageHolderList();
    if ( !pUNOStorageHolderList )
        return xResult;

    for ( UNOStorageHolderList::iterator aIter = pUNOStorageHolderList->begin();
          aIter != pUNOStorageHolderList->end(); ++aIter )
        if ( (*aIter) && (*aIter)->GetStorageName().Equals( rEleName ) )
        {
            // the storage is already in use
            return xResult;
        }

    if ( IsStream( rEleName ) )
        return xResult;

    if ( GetError() == ERRCODE_NONE )
    {
        StreamMode nMode = ( ( nUNOStorageMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE ) ?
                                    STREAM_WRITE : ( STREAM_READ | STREAM_NOCREATE );
        if ( nUNOStorageMode & embed::ElementModes::NOCREATE )
            nMode |= STREAM_NOCREATE;

        sal_Bool bStorageReady = !IsStorage( rEleName );
        SotStorageRef pChildStorage = OpenUCBStorage( rEleName, nMode, STORAGE_TRANSACTED );
        if ( pChildStorage->GetError() == ERRCODE_NONE && pChildStorage->m_pOwnStg )
        {
            ::utl::TempFile* pTempFile = new ::utl::TempFile();
            if ( pTempFile->GetURL().Len() )
            {
                    if ( !bStorageReady )
                    {
                           UCBStorage* pChildUCBStg = PTR_CAST( UCBStorage, pChildStorage->m_pOwnStg );
                        if ( pChildUCBStg )
                        {
                            UCBStorage* pTempStorage = new UCBStorage( pTempFile->GetURL(), STREAM_WRITE, sal_False, sal_True );
                            if ( pTempStorage )
                            {
                                pChildUCBStg->CopyTo( pTempStorage );

                                // CopyTo does not transport unknown media type
                                // just workaround it
                                uno::Any aMediaType;

                                if ( pChildUCBStg->GetProperty(
                                                    ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")), aMediaType ) )
                                    pTempStorage->SetProperty( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")), aMediaType );

                                bStorageReady = !pChildUCBStg->GetError() && !pTempStorage->GetError()
                                            && pTempStorage->Commit();

                                delete ((BaseStorage*)pTempStorage);
                                pTempStorage = NULL;
                            }
                        }

                        OSL_ENSURE( bStorageReady, "Problem on storage copy!\n" );
                    }

                    if ( bStorageReady )
                    {
                        try {
                            uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
                                    ::comphelper::getProcessServiceFactory()->createInstance(
                                        ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.embed.StorageFactory")) ),
                                    uno::UNO_QUERY );

                            OSL_ENSURE( xStorageFactory.is(), "Can't create storage factory!\n" );
                            if ( xStorageFactory.is() )
                            {
                                uno::Sequence< uno::Any > aArg( 2 );
                                aArg[0] <<= ::rtl::OUString( pTempFile->GetURL() );
                                aArg[1] <<= nUNOStorageMode;
                                uno::Reference< embed::XStorage > xDuplStorage(
                                                    xStorageFactory->createInstanceWithArguments( aArg ),
                                                    uno::UNO_QUERY );

                                OSL_ENSURE( xDuplStorage.is(), "Can't open storage!\n" );
                                if ( xDuplStorage.is() )
                                {
                                    UNOStorageHolder* pHolder =
                                            new UNOStorageHolder( *this, *pChildStorage, xDuplStorage, pTempFile );
                                    pHolder->acquire();
                                    pTempFile = NULL;
                                    pUNOStorageHolderList->push_back( pHolder );
                                    xResult = xDuplStorage;
                                }
                            }
                        }
                        catch( uno::Exception& e )
                        {
                                                    (void)e;
                                                    OSL_FAIL( ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ) );
                        }
                    }
            }

            if ( pTempFile != NULL )
                delete pTempFile;
        }
        else
            SetError( pChildStorage->GetError() );
    }

    return xResult;
}

/*************************************************************************
|*    SotStorage::CreateMemoryStream()
|*
|*    Beschreibung
*************************************************************************/
SvMemoryStream * SotStorage::CreateMemoryStream()
{
    SvMemoryStream * pStm = NULL;
    pStm = new SvMemoryStream( 0x8000, 0x8000 );
    SotStorageRef aStg = new SotStorage( *pStm );
    if( CopyTo( aStg ) )
        aStg->Commit();
    else
    {
        aStg.Clear(); // Storage vorher freigeben
        delete pStm;
        pStm = NULL;
    }
    return pStm;
}

/*************************************************************************
|*    SotStorage::GetStorage()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::IsStorageFile( const String & rFileName )
{
    String aName( rFileName );
    INetURLObject aObj( aName );
    if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
    {
        String aURL;
        ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL );
        aObj.SetURL( aURL );
        aName = aObj.GetMainURL( INetURLObject::NO_DECODE );
    }

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

sal_Bool SotStorage::IsStorageFile( SvStream* pStream )
{
    /** code for new storages must come first! **/
    if ( pStream )
    {
        long nPos = pStream->Tell();
        sal_Bool bRet = UCBStorage::IsStorageFile( pStream );
        if ( !bRet )
            bRet = Storage::IsStorageFile( pStream );
        pStream->Seek( nPos );
        return bRet;
    }
    else
        return sal_False;
}
/*************************************************************************
|*    SotStorage::GetStorage()
|*
|*    Beschreibung
*************************************************************************/
const String & SotStorage::GetName() const
{
    if( !m_aName.Len() )
    {
        DBG_ASSERT( Owner(), "must be owner" );
        if( m_pOwnStg )
            ((SotStorage *)this)->m_aName = m_pOwnStg->GetName();
    }
    return m_aName;
}

void SotStorage::SetName( const String& rName )
{
    // This method is necessary because most storages will not be opened with a FileName, but an external stream instead
    // This stream is a stream opened by a UCP and so aName is only used as a transport for all client code of the SotStorage
    // class that depends on the fact that a root storage has a name
    DBG_ASSERT( !GetName().Len(), "SetName() must not be called when the storage already has a name!" );
    m_aName = rName;
}

/*************************************************************************
|*    SotStorage::ResetError()
|*
|*    Beschreibung
*************************************************************************/
void SotStorage::ResetError()
{
    m_nError = SVSTREAM_OK;
    if( m_pOwnStg )
        m_pOwnStg->ResetError();
}

/*************************************************************************
|*    SotStorage::SetClass()
|*    SotStorage::SetConvertClass()
|*
|*    Beschreibung
*************************************************************************/
void SotStorage::SetClass( const SvGlobalName & rName,
                          sal_uLong nOriginalClipFormat,
                          const String & rUserTypeName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        m_pOwnStg->SetClass( rName, nOriginalClipFormat, rUserTypeName );
    else
        SetError( SVSTREAM_GENERALERROR );
}

void SotStorage::SetConvertClass( const SvGlobalName & rName,
                                 sal_uLong nOriginalClipFormat,
                                 const String & rUserTypeName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        m_pOwnStg->SetConvertClass( rName, nOriginalClipFormat, rUserTypeName );
    else
        SetError( SVSTREAM_GENERALERROR );
}

/*************************************************************************
|*    SotStorage::GetClassName()
|*    SotStorage::GetFormat()
|*    SotStorage::GetUserName()
|*    SotStorage::ShouldConvert()
|*
|*    Beschreibung
*************************************************************************/
SvGlobalName SotStorage::GetClassName()
{
    SvGlobalName aGN;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        aGN = m_pOwnStg->GetClassName();
    else
        SetError( SVSTREAM_GENERALERROR );
    return aGN;
}

sal_uLong SotStorage::GetFormat()
{
    sal_uLong nFormat = 0;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        nFormat = m_pOwnStg->GetFormat();
    else
        SetError( SVSTREAM_GENERALERROR );
    return nFormat;
}

String SotStorage::GetUserName()
{
    String aName;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        aName = m_pOwnStg->GetUserName();
    else
        SetError( SVSTREAM_GENERALERROR );
    return aName;
}

sal_Bool SotStorage::ShouldConvert()
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        return m_pOwnStg->ShouldConvert();
    else
        SetError( SVSTREAM_GENERALERROR );
    return sal_False;
}

/*************************************************************************
|*    SotStorage::FillInfoList()
|*
|*    Beschreibung
*************************************************************************/
void SotStorage::FillInfoList( SvStorageInfoList * pFillList ) const
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        m_pOwnStg->FillInfoList( pFillList );
}

/*************************************************************************
|*    SotStorage::CopyTo()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::CopyTo( SotStorage * pDestStg )
{
    DBG_ASSERT( Owner(), "must be owner" );
    DBG_ASSERT( pDestStg->Owner(), "must be owner" );
    if( m_pOwnStg && pDestStg->m_pOwnStg )
    {
        m_pOwnStg->CopyTo( pDestStg->m_pOwnStg );
        SetError( m_pOwnStg->GetError() );
        pDestStg->m_aKey = m_aKey;
        pDestStg->m_nVersion = m_nVersion;
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::Commit()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::Commit()
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        if( !m_pOwnStg->Commit() )
            SetError( m_pOwnStg->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::Revert()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::Revert()
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        if( !m_pOwnStg->Revert() )
            SetError( m_pOwnStg->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::OpenStream()
|*
|*    Beschreibung
*************************************************************************/
SotStorageStream * SotStorage::OpenEncryptedSotStream( const String & rEleName, const ByteString& rKey,
                                             StreamMode nMode,
                                             StorageMode nStorageMode )
{
    DBG_ASSERT( !nStorageMode, "StorageModes ignored" );
    SotStorageStream * pStm = NULL;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        // volle Ole-Patches einschalten
        // egal was kommt, nur exclusiv gestattet
        nMode |= STREAM_SHARE_DENYALL;
        ErrCode nE = m_pOwnStg->GetError();
        BaseStorageStream* p = m_pOwnStg->OpenStream( rEleName, nMode,
                            (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True, &rKey );
        pStm = new SotStorageStream( p );

        if( !nE )
            m_pOwnStg->ResetError(); // kein Fehler setzen
        if( nMode & STREAM_TRUNC )
            pStm->SetSize( 0 );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return pStm;
}

SotStorageStream * SotStorage::OpenSotStream( const String & rEleName,
                                             StreamMode nMode,
                                             StorageMode nStorageMode )
{
    DBG_ASSERT( !nStorageMode, "StorageModes ignored" );
    SotStorageStream * pStm = NULL;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        // volle Ole-Patches einschalten
        // egal was kommt, nur exclusiv gestattet
        nMode |= STREAM_SHARE_DENYALL;
        ErrCode nE = m_pOwnStg->GetError();
        BaseStorageStream * p = m_pOwnStg->OpenStream( rEleName, nMode,
                            (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        pStm = new SotStorageStream( p );

        if( !nE )
            m_pOwnStg->ResetError(); // kein Fehler setzen
        if( nMode & STREAM_TRUNC )
            pStm->SetSize( 0 );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return pStm;
}

/*************************************************************************
|*    SotStorage::OpenStorage()
|*
|*    Beschreibung
*************************************************************************/
SotStorage * SotStorage::OpenSotStorage( const String & rEleName,
                                        StreamMode nMode,
                                        StorageMode nStorageMode )
{
    SotStorage * pStor = NULL;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        nMode |= STREAM_SHARE_DENYALL;
        ErrCode nE = m_pOwnStg->GetError();
        BaseStorage * p = m_pOwnStg->OpenStorage( rEleName, nMode,
                        (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        if( p )
        {
            pStor = new SotStorage( p );
            if( !nE )
                m_pOwnStg->ResetError(); // kein Fehler setzen

            return pStor;
        }
    }

    SetError( SVSTREAM_GENERALERROR );

    return NULL;
}

SotStorage * SotStorage::OpenUCBStorage( const String & rEleName,
                                        StreamMode nMode,
                                        StorageMode nStorageMode )
{
    SotStorage * pStor = NULL;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        nMode |= STREAM_SHARE_DENYALL;
        ErrCode nE = m_pOwnStg->GetError();
        BaseStorage * p = m_pOwnStg->OpenUCBStorage( rEleName, nMode,
                        (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        pStor = new SotStorage( p );
        if( !nE )
            m_pOwnStg->ResetError(); // kein Fehler setzen
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return pStor;
}

SotStorage * SotStorage::OpenOLEStorage( const String & rEleName,
                                        StreamMode nMode,
                                        StorageMode nStorageMode )
{
    SotStorage * pStor = NULL;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        nMode |= STREAM_SHARE_DENYALL;
        ErrCode nE = m_pOwnStg->GetError();
        BaseStorage * p = m_pOwnStg->OpenOLEStorage( rEleName, nMode,
                        (nStorageMode & STORAGE_TRANSACTED) ? sal_False : sal_True );
        pStor = new SotStorage( p );
        if( !nE )
            m_pOwnStg->ResetError(); // kein Fehler setzen
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return pStor;
}

/*************************************************************************
|*    SotStorage::IsStream()
|*    SotStorage::IsStorage()
|*    SotStorage::IsContained()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::IsStorage( const String & rEleName ) const
{
    DBG_ASSERT( Owner(), "must be owner" );
    // ein bisschen schneller
    if( m_pOwnStg )
        return m_pOwnStg->IsStorage( rEleName );
    return sal_False;
}

sal_Bool SotStorage::IsStream( const String & rEleName ) const
{
    DBG_ASSERT( Owner(), "must be owner" );
    // ein bisschen schneller
    if( m_pOwnStg )
        return m_pOwnStg->IsStream( rEleName );
    return sal_False;
}

sal_Bool SotStorage::IsContained( const String & rEleName ) const
{
    DBG_ASSERT( Owner(), "must be owner" );
    // ein bisschen schneller
    if( m_pOwnStg )
        return m_pOwnStg->IsContained( rEleName );
    return sal_False;
}

/*************************************************************************
|*    SotStorage::Remove()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::Remove( const String & rEleName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        m_pOwnStg->Remove( rEleName );
        SetError( m_pOwnStg->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::Rename()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::Rename( const String & rEleName, const String & rNewName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        m_pOwnStg->Rename( rEleName, rNewName );
        SetError( m_pOwnStg->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::CopyTo()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::CopyTo( const String & rEleName,
                        SotStorage * pNewSt, const String & rNewName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    DBG_ASSERT( pNewSt->Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        m_pOwnStg->CopyTo( rEleName, pNewSt->m_pOwnStg, rNewName );
        SetError( m_pOwnStg->GetError() );
        SetError( pNewSt->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

/*************************************************************************
|*    SotStorage::MoveTo()
|*
|*    Beschreibung
*************************************************************************/
sal_Bool SotStorage::MoveTo( const String & rEleName,
                        SotStorage * pNewSt, const String & rNewName )
{
    DBG_ASSERT( Owner(), "must be owner" );
    DBG_ASSERT( pNewSt->Owner(), "must be owner" );
    if( m_pOwnStg )
    {
        m_pOwnStg->MoveTo( rEleName, pNewSt->m_pOwnStg, rNewName );
        SetError( m_pOwnStg->GetError() );
        SetError( pNewSt->GetError() );
    }
    else
        SetError( SVSTREAM_GENERALERROR );
    return SVSTREAM_OK == GetError();
}

const SvStream* SotStorage::GetSvStream()
{
    const SvStream* pResult = 0;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        pResult = m_pOwnStg->GetSvStream();
    return pResult;
}

SvStream* SotStorage::GetTargetSvStream() const
{
    SvStream* pResult = 0;
    DBG_ASSERT( Owner(), "must be owner" );
    if( m_pOwnStg )
        pResult = (SvStream*)(m_pOwnStg->GetSvStream());
    return pResult;
}


sal_Bool SotStorage::Validate()
{
    DBG_ASSERT( m_bIsRoot, "Validate nur an Rootstorage" );
    if( m_pOwnStg )
        return m_pOwnStg->ValidateFAT();
    else
        return sal_True;
}

sal_Bool SotStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
{
    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    if ( pStg )
    {
        return pStg->SetProperty( rName, rValue );
    }
    else
    {
        DBG_WARNING("W1:Not implemented!");
        return sal_False;
    }
}

sal_Bool SotStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
{
    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    if ( pStg )
    {
        return pStg->GetProperty( rName, rValue );
    }
    else if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL )
    {
        String aStr = SotExchange::GetFormatMimeType( GetFormat() );
        sal_uInt16 nPos = aStr.Search(';');
        if ( nPos != STRING_NOTFOUND )
            aStr = aStr.Copy( 0, nPos );
        rValue <<= (::rtl::OUString) aStr;
        return sal_True;
    }
    else
    {
        DBG_WARNING("W1:Not implemented!");
        return sal_False;
    }
}

sal_Bool SotStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
{
    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    if ( pStg )
    {
        return pStg->GetProperty( rEleName, rName, rValue );
    }
    else
    {
        DBG_WARNING("W1:Not implemented!");
        return sal_False;
    }
}

sal_Bool SotStorage::IsOLEStorage() const
{
    UCBStorage* pStg = PTR_CAST( UCBStorage, m_pOwnStg );
    return !pStg;
}

sal_Bool SotStorage::IsOLEStorage( const String & rFileName )
{
    return Storage::IsStorageFile( rFileName );
}

sal_Bool SotStorage::IsOLEStorage( SvStream* pStream )
{
    return Storage::IsStorageFile( pStream );
}

void SotStorage::SetKey( const ByteString& rKey )
{
    m_aKey = rKey;
    if ( !IsOLEStorage() )
    {
        sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1];
        rtlDigestError nError = rtl_digest_SHA1( m_aKey.GetBuffer(), m_aKey.Len(), aBuffer, RTL_DIGEST_LENGTH_SHA1 );
        if ( nError == 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;
            SetProperty( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("EncryptionKey")), aAny );
        }
    }
}

SotStorage* SotStorage::OpenOLEStorage( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& xStorage,
                                    const String& rEleName, StreamMode nMode )
{
    sal_Int32 nEleMode = embed::ElementModes::SEEKABLEREAD;
    if ( nMode & STREAM_WRITE )
        nEleMode |= embed::ElementModes::WRITE;
    if ( nMode & STREAM_TRUNC )
        nEleMode |= embed::ElementModes::TRUNCATE;
    if ( nMode & STREAM_NOCREATE )
        nEleMode |= embed::ElementModes::NOCREATE;

    SvStream* pStream = NULL;
    try
    {
        uno::Reference < io::XStream > xStream = xStorage->openStreamElement( rEleName, nEleMode );

        // TODO/LATER: should it be done this way?
        if ( nMode & STREAM_WRITE )
        {
            uno::Reference < beans::XPropertySet > xStreamProps( xStream, uno::UNO_QUERY_THROW );
            xStreamProps->setPropertyValue(
                        ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
                        uno::makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.oleobject" ) ) ) );
        }

           pStream = utl::UcbStreamHelper::CreateStream( xStream );
    }
    catch ( uno::Exception& )
    {
        //TODO/LATER: ErrorHandling
        pStream = new SvMemoryStream;
        pStream->SetError( ERRCODE_IO_GENERAL );
    }

    return new SotStorage( pStream, sal_True );
}

sal_Int32 SotStorage::GetFormatID( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& xStorage )
{
    uno::Reference< beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
    if ( !xProps.is() )
        return 0;

    ::rtl::OUString aMediaType;
    xProps->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")) ) >>= aMediaType;
    if ( aMediaType.getLength() )
    {
        ::com::sun::star::datatransfer::DataFlavor aDataFlavor;
        aDataFlavor.MimeType = aMediaType;
        return SotExchange::GetFormat( aDataFlavor );
    }

    return 0;
}

sal_Int32 SotStorage::GetVersion( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& xStorage )
{
    sal_Int32 nSotFormatID = SotStorage::GetFormatID( xStorage );
    switch( nSotFormatID )
    {
        case SOT_FORMATSTR_ID_STARWRITER_8:
        case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE:
        case SOT_FORMATSTR_ID_STARWRITERWEB_8:
        case SOT_FORMATSTR_ID_STARWRITERGLOB_8:
        case SOT_FORMATSTR_ID_STARDRAW_8:
        case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE:
        case SOT_FORMATSTR_ID_STARIMPRESS_8:
        case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE:
        case SOT_FORMATSTR_ID_STARCALC_8:
        case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE:
        case SOT_FORMATSTR_ID_STARCHART_8:
        case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE:
        case SOT_FORMATSTR_ID_STARMATH_8:
        case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE:
            return SOFFICE_FILEFORMAT_8;
        case SOT_FORMATSTR_ID_STARWRITER_60:
        case SOT_FORMATSTR_ID_STARWRITERWEB_60:
        case SOT_FORMATSTR_ID_STARWRITERGLOB_60:
        case SOT_FORMATSTR_ID_STARDRAW_60:
        case SOT_FORMATSTR_ID_STARIMPRESS_60:
        case SOT_FORMATSTR_ID_STARCALC_60:
        case SOT_FORMATSTR_ID_STARCHART_60:
        case SOT_FORMATSTR_ID_STARMATH_60:
            return SOFFICE_FILEFORMAT_60;
    }

    return 0;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
