    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   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 .
     */

    #include <config_features.h>

    #include <sal/config.h>
    #include <sal/log.hxx>

    #include <algorithm>

    #include <comphelper/fileformat.h>
    #include <comphelper/processfactory.hxx>
    #include <osl/file.hxx>
    #include <tools/urlobj.hxx>
    #include <tools/vcompat.hxx>
    #include <unotools/streamwrap.hxx>
    #include <unotools/ucbstreamhelper.hxx>
    #include <unotools/tempfile.hxx>
    #include <ucbhelper/content.hxx>
    #include <com/sun/star/ucb/ContentCreationException.hpp>
    #include <sot/storage.hxx>
    #include <sot/formats.hxx>
    #include <sot/filelist.hxx>
    #include <vcl/virdev.hxx>
    #include <vcl/cvtgrf.hxx>
    #include <svl/itempool.hxx>
    #include <sfx2/docfile.hxx>
    #include <avmedia/mediawindow.hxx>
    #include <svx/svxids.hrc>
    #include <svx/svdograf.hxx>
    #include <svx/fmpage.hxx>
    #include "codec.hxx"
    #include <svx/unomodel.hxx>
    #include <svx/fmmodel.hxx>
    #include <svx/fmview.hxx>
    #include <svx/galmisc.hxx>
    #include <svx/galtheme.hxx>
    #include <com/sun/star/sdbc/XResultSet.hpp>
    #include <com/sun/star/ucb/XContentAccess.hpp>
    #include <com/sun/star/io/XInputStream.hpp>
    #include <galobj.hxx>
    #include <svx/gallery1.hxx>
    #include <vcl/lstbox.hxx>
    #include "gallerydrawmodel.hxx"
    #include <memory>

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

    GalleryTheme::GalleryTheme( Gallery* pGallery, GalleryThemeEntry* pThemeEntry )
        : m_bDestDirRelative(false)
        , pParent(pGallery)
        , pThm(pThemeEntry)
        , mnThemeLockCount(0)
        , mnBroadcasterLockCount(0)
        , nDragPos(0)
        , bDragging(false)
        , bAbortActualize(false)
    {
        ImplCreateSvDrawStorage();
    }

    GalleryTheme::~GalleryTheme()
    {
        ImplWrite();

        for (auto & pEntry : aObjectList)
        {
            Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
            Broadcast( GalleryHint( GalleryHintType::OBJECT_REMOVED, GetName(), pEntry.get() ) );
            pEntry.reset();
        }
        aObjectList.clear();

    }

    void GalleryTheme::ImplCreateSvDrawStorage()
    {
        try
        {
            aSvDrawStorageRef = new SotStorage( false, GetSdvURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pThm->IsReadOnly() ? StreamMode::READ : StreamMode::STD_READWRITE );
            // #i50423# ReadOnly may not been set though the file can't be written (because of security reasons)
            if ( ( aSvDrawStorageRef->GetError() != ERRCODE_NONE ) && !pThm->IsReadOnly() )
                aSvDrawStorageRef = new SotStorage( false, GetSdvURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
        }
        catch (const css::ucb::ContentCreationException& e)
        {
            SAL_WARN("svx", "failed to open: "
                      << GetSdvURL().GetMainURL(INetURLObject::DecodeMechanism::NONE)
                      << "due to : " << e);
        }
    }

    bool GalleryTheme::ImplWriteSgaObject(const SgaObject& rObj, sal_uInt32 nPos, GalleryObject* pExistentEntry)
    {
        std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( GetSdgURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE ));
        bool        bRet = false;

        if( pOStm )
        {
            const sal_uInt32 nOffset = pOStm->Seek( STREAM_SEEK_TO_END );

            rObj.WriteData( *pOStm, m_aDestDir );

            if( !pOStm->GetError() )
            {
                GalleryObject* pEntry;

                if( !pExistentEntry )
                {
                    pEntry = new GalleryObject;
                    if ( nPos < aObjectList.size() )
                    {
                        aObjectList.emplace( aObjectList.begin() + nPos, pEntry );
                    }
                    else
                        aObjectList.emplace_back( pEntry );
                }
                else
                    pEntry = pExistentEntry;

                pEntry->aURL = rObj.GetURL();
                pEntry->nOffset = nOffset;
                pEntry->eObjKind = rObj.GetObjKind();
                bRet = true;
            }
        }

        return bRet;
    }

    std::unique_ptr<SgaObject> GalleryTheme::ImplReadSgaObject( GalleryObject const * pEntry )
    {
        std::unique_ptr<SgaObject> pSgaObj;

        if( pEntry )
        {
            std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( GetSdgURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));

            if( pIStm )
            {
                sal_uInt32 nInventor;

                // Check to ensure that the file is a valid SGA file
                pIStm->Seek( pEntry->nOffset );
                pIStm->ReadUInt32( nInventor );

                if( nInventor == COMPAT_FORMAT( 'S', 'G', 'A', '3' ) )
                {
                    pIStm->Seek( pEntry->nOffset );

                    switch( pEntry->eObjKind )
                    {
                        case SgaObjKind::Bitmap:    pSgaObj.reset(new SgaObjectBmp()); break;
                        case SgaObjKind::Animation:   pSgaObj.reset(new SgaObjectAnim()); break;
                        case SgaObjKind::Inet:   pSgaObj.reset(new SgaObjectINet()); break;
                        case SgaObjKind::SvDraw: pSgaObj.reset(new SgaObjectSvDraw()); break;
                        case SgaObjKind::Sound:  pSgaObj.reset(new SgaObjectSound()); break;

                        default:
                        break;
                    }

                    if( pSgaObj )
                    {
                        ReadSgaObject( *pIStm, *pSgaObj );
                        pSgaObj->ImplUpdateURL( pEntry->aURL );
                    }
                }
            }
        }

        return pSgaObj;
    }

    void GalleryTheme::ImplWrite()
    {
        if( pThm->IsModified() )
        {
            INetURLObject aPathURL( GetThmURL() );

            aPathURL.removeSegment();
            aPathURL.removeFinalSlash();

            DBG_ASSERT( aPathURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );

            if( FileExists( aPathURL ) || CreateDir( aPathURL ) )
            {
    #ifdef UNX
                std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( GetThmURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::COPY_ON_SYMLINK | StreamMode::TRUNC ));
    #else
                std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( GetThmURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC ));
    #endif

                if( pOStm )
                {
                    WriteGalleryTheme( *pOStm, *this );
                    pOStm.reset();
                }

                ImplSetModified( false );
            }
        }
    }

    const GalleryObject* GalleryTheme::ImplGetGalleryObject( const INetURLObject& rURL )
    {
        for (auto const & i : aObjectList)
            if ( i->aURL == rURL )
                return i.get();
        return nullptr;
    }

    INetURLObject GalleryTheme::ImplGetURL( const GalleryObject* pObject )
    {
        INetURLObject aURL;

        if( pObject )
            aURL = pObject->aURL;

        return aURL;
    }

    INetURLObject GalleryTheme::ImplCreateUniqueURL( SgaObjKind eObjKind, ConvertDataFormat nFormat )
    {
        INetURLObject   aDir( GetParent()->GetUserURL() );
        INetURLObject   aInfoFileURL( GetParent()->GetUserURL() );
        INetURLObject   aNewURL;
        sal_uInt32      nNextNumber = 1999;
        sal_Char const* pExt = nullptr;
        bool            bExists;

        aDir.Append( "dragdrop" );
        CreateDir( aDir );

        aInfoFileURL.Append( "sdddndx1" );

        // read next possible number
        if( FileExists( aInfoFileURL ) )
        {
            std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aInfoFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));

            if( pIStm )
            {
                pIStm->ReadUInt32( nNextNumber );
            }
        }

        // create extension
        if( nFormat != ConvertDataFormat::Unknown )
        {
            switch( nFormat )
            {
                case ConvertDataFormat::BMP: pExt = ".bmp"; break;
                case ConvertDataFormat::GIF: pExt = ".gif"; break;
                case ConvertDataFormat::JPG: pExt = ".jpg"; break;
                case ConvertDataFormat::MET: pExt = ".met"; break;
                case ConvertDataFormat::PCT: pExt = ".pct"; break;
                case ConvertDataFormat::PNG: pExt = ".png"; break;
                case ConvertDataFormat::SVM: pExt = ".svm"; break;
                case ConvertDataFormat::TIF: pExt = ".tif"; break;
                case ConvertDataFormat::WMF: pExt = ".wmf"; break;
                case ConvertDataFormat::EMF: pExt = ".emf"; break;

                default:
                    pExt = ".grf";
                break;
            }
        }

        do
        {
            // get URL
            if( SgaObjKind::SvDraw == eObjKind )
            {
                OUString aFileName( "gallery/svdraw/dd" );
                aNewURL = INetURLObject( aFileName += OUString::number( ++nNextNumber % 99999999 ), INetProtocol::PrivSoffice );

                bExists = false;

                for (auto const & p : aObjectList)
                    if ( p->aURL == aNewURL )
                    {
                        bExists = true;
                        break;
                    }
            }
            else
            {
                OUString aFileName( "dd" );

                aFileName += OUString::number( ++nNextNumber % 999999 );

                if (pExt)
                    aFileName += OUString( pExt, strlen(pExt), RTL_TEXTENCODING_ASCII_US );

                aNewURL = aDir;
                aNewURL.Append( aFileName );

                bExists = FileExists( aNewURL );
            }
        }
        while( bExists );

        // write updated number
        std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( aInfoFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE ));

        if( pOStm )
        {
            pOStm->WriteUInt32( nNextNumber );
        }

        return aNewURL;
    }

    void GalleryTheme::ImplBroadcast(sal_uInt32 nUpdatePos)
    {
        if( !IsBroadcasterLocked() )
        {
            if( GetObjectCount() && ( nUpdatePos >= GetObjectCount() ) )
                nUpdatePos = GetObjectCount() - 1;

            Broadcast( GalleryHint( GalleryHintType::THEME_UPDATEVIEW, GetName(), reinterpret_cast<void*>(nUpdatePos) ) );
        }
    }

    bool GalleryTheme::UnlockTheme()
    {
        DBG_ASSERT( mnThemeLockCount, "Theme is not locked" );

        bool bRet = false;

        if( mnThemeLockCount )
        {
            --mnThemeLockCount;
            bRet = true;
        }

        return bRet;
    }

    void GalleryTheme::UnlockBroadcaster()
    {
        DBG_ASSERT( mnBroadcasterLockCount, "Broadcaster is not locked" );

        if( mnBroadcasterLockCount && !--mnBroadcasterLockCount )
            ImplBroadcast( 0 );
    }

    bool GalleryTheme::InsertObject(const SgaObject& rObj, sal_uInt32 nInsertPos)
    {
        if (!rObj.IsValid())
            return false;

        GalleryObject* pFoundEntry = nullptr;
        sal_uInt32 iFoundPos = 0;
        for (sal_uInt32 n = aObjectList.size(); iFoundPos < n; ++iFoundPos)
        {
            if (aObjectList[ iFoundPos ]->aURL == rObj.GetURL())
            {
                pFoundEntry = aObjectList[ iFoundPos ].get();
                break;
            }
        }

        if (pFoundEntry)
        {
            GalleryObject aNewEntry;

            // update title of new object if necessary
            if (rObj.GetTitle().isEmpty())
            {
                std::unique_ptr<SgaObject> pOldObj(ImplReadSgaObject(pFoundEntry));

                if (pOldObj)
                {
                    const_cast<SgaObject&>(rObj).SetTitle( pOldObj->GetTitle() );
                }
            }
            else if (rObj.GetTitle() == "__<empty>__")
                const_cast<SgaObject&>(rObj).SetTitle("");

            ImplWriteSgaObject(rObj, nInsertPos, &aNewEntry);
            pFoundEntry->nOffset = aNewEntry.nOffset;
        }
        else
            ImplWriteSgaObject(rObj, nInsertPos, nullptr);

        ImplSetModified(true);
        ImplBroadcast(pFoundEntry? iFoundPos: nInsertPos);

        return true;
    }

    std::unique_ptr<SgaObject> GalleryTheme::AcquireObject(sal_uInt32 nPos)
    {
        return ImplReadSgaObject(ImplGetGalleryObject(nPos));
    }

    void GalleryTheme::GetPreviewBitmapExAndStrings(sal_uInt32 nPos, BitmapEx& rBitmapEx, Size& rSize, OUString& rTitle, OUString& rPath) const
    {
        const GalleryObject* pGalleryObject = aObjectList[ nPos ].get();

        rBitmapEx = pGalleryObject->maPreviewBitmapEx;
        rSize = pGalleryObject->maPreparedSize;
        rTitle = pGalleryObject->maTitle;
        rPath = pGalleryObject->maPath;
    }

    void GalleryTheme::SetPreviewBitmapExAndStrings(sal_uInt32 nPos, const BitmapEx& rBitmapEx, const Size& rSize, const OUString& rTitle, const OUString& rPath)
    {
        GalleryObject* pGalleryObject = aObjectList[ nPos ].get();

        pGalleryObject->maPreviewBitmapEx = rBitmapEx;
        pGalleryObject->maPreparedSize = rSize;
        pGalleryObject->maTitle = rTitle;
        pGalleryObject->maPath = rPath;
    }

    void GalleryTheme::RemoveObject(sal_uInt32 nPos)
    {
        auto it = aObjectList.begin() + nPos;
        std::unique_ptr<GalleryObject> pEntry = std::move(*it);
        aObjectList.erase( it );

        if( aObjectList.empty() )
            KillFile( GetSdgURL() );

        if( SgaObjKind::SvDraw == pEntry->eObjKind )
            aSvDrawStorageRef->Remove( pEntry->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );

        Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pEntry.get() ) );
        Broadcast( GalleryHint( GalleryHintType::OBJECT_REMOVED, GetName(), pEntry.get() ) );
        pEntry.reset();

        ImplSetModified( true );
        ImplBroadcast( nPos );
    }

    bool GalleryTheme::ChangeObjectPos(sal_uInt32 nOldPos, sal_uInt32 nNewPos)
    {
        if (nOldPos == nNewPos || nOldPos >= aObjectList.size())
            return false;

        std::unique_ptr<GalleryObject> pEntry = std::move(aObjectList[nOldPos]);

        aObjectList.insert(aObjectList.begin() + nNewPos, std::move(pEntry));

        if (nNewPos < nOldPos)
            nOldPos++;

        auto it = aObjectList.begin() + nOldPos;
        aObjectList.erase(it);

        ImplSetModified(true);
        ImplBroadcast((nNewPos < nOldPos)? nNewPos: (nNewPos - 1));

        return true;
    }

    void GalleryTheme::Actualize( const Link<const INetURLObject&, void>& rActualizeLink, GalleryProgress* pProgress )
    {
        if( IsReadOnly() )
            return;

        Graphic         aGraphic;
        OUString        aFormat;
        const sal_uInt32 nCount = aObjectList.size();

        LockBroadcaster();
        bAbortActualize = false;

        // reset delete flag
        for (sal_uInt32 i = 0; i < nCount; i++)
            aObjectList[ i ]->mbDelete = false;

        for (sal_uInt32 i = 0; ( i < nCount ) && !bAbortActualize; i++)
        {
            if( pProgress )
                pProgress->Update( i, nCount - 1 );

            GalleryObject* pEntry = aObjectList[ i ].get();

            const INetURLObject aURL( pEntry->aURL );

            rActualizeLink.Call( aURL );

            // SvDraw objects will be updated later
            if( pEntry->eObjKind != SgaObjKind::SvDraw )
            {
                // Still a function should be implemented,
                // which assigns files to the relevant entry.
                // insert graphics as graphic objects into the gallery
                if( pEntry->eObjKind == SgaObjKind::Sound )
                {
                    SgaObjectSound aObjSound( aURL );
                    if( !InsertObject( aObjSound ) )
                        pEntry->mbDelete = true;
                }
                else
                {
                    aGraphic.Clear();

                    if ( GalleryGraphicImport( aURL, aGraphic, aFormat ) != GalleryGraphicImportRet::IMPORT_NONE )
                    {
                        std::unique_ptr<SgaObject> pNewObj;

                        if ( SgaObjKind::Inet == pEntry->eObjKind )
                            pNewObj.reset(static_cast<SgaObject*>(new SgaObjectINet( aGraphic, aURL )));
                        else if ( aGraphic.IsAnimated() )
                            pNewObj.reset(static_cast<SgaObject*>(new SgaObjectAnim( aGraphic, aURL )));
                        else
                            pNewObj.reset(static_cast<SgaObject*>(new SgaObjectBmp( aGraphic, aURL )));

                        if( !InsertObject( *pNewObj ) )
                            pEntry->mbDelete = true;
                    }
                    else
                        pEntry->mbDelete = true; // set delete flag
                }
            }
            else
            {
                if ( aSvDrawStorageRef.is() )
                {
                    const OUString        aStmName( GetSvDrawStreamNameFromURL( pEntry->aURL ) );
                    tools::SvRef<SotStorageStream>  pIStm = aSvDrawStorageRef->OpenSotStream( aStmName, StreamMode::READ );

                    if( pIStm.is() && !pIStm->GetError() )
                    {
                        pIStm->SetBufferSize( 16384 );

                        SgaObjectSvDraw aNewObj( *pIStm, pEntry->aURL );

                        if( !InsertObject( aNewObj ) )
                            pEntry->mbDelete = true;

                        pIStm->SetBufferSize( 0 );
                    }
                }
            }
        }

        // remove all entries with set flag
        for ( auto it = aObjectList.begin(); it != aObjectList.end(); /* increment is in the body of loop */)
        {
            if( (*it)->mbDelete )
            {
                Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), it->get() ) );
                Broadcast( GalleryHint( GalleryHintType::OBJECT_REMOVED, GetName(), it->get() ) );
                it = aObjectList.erase( it );
            }
            else
                ++it;
        }

        // update theme
        ::utl::TempFile aTmp;
        INetURLObject   aInURL( GetSdgURL() );
        INetURLObject   aTmpURL( aTmp.GetURL() );

        DBG_ASSERT( aInURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
        DBG_ASSERT( aTmpURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );

        std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aInURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
        std::unique_ptr<SvStream> pTmpStm(::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC ));

        if( pIStm && pTmpStm )
        {
            for (auto & i : aObjectList)
            {
                GalleryObject* pEntry = i.get();
                std::unique_ptr<SgaObject> pObj;

                switch( pEntry->eObjKind )
                {
                case SgaObjKind::Bitmap:    pObj.reset(new SgaObjectBmp());      break;
                case SgaObjKind::Animation:   pObj.reset(new SgaObjectAnim());     break;
                case SgaObjKind::Inet:   pObj.reset(new SgaObjectINet());     break;
                case SgaObjKind::SvDraw: pObj.reset(new SgaObjectSvDraw());   break;
                case SgaObjKind::Sound:   pObj.reset(new SgaObjectSound());    break;

                    default:
                    break;
                }

                if( pObj )
                {
                    pIStm->Seek( pEntry->nOffset );
                    ReadSgaObject( *pIStm, *pObj);
                    pEntry->nOffset = pTmpStm->Tell();
                    WriteSgaObject( *pTmpStm, *pObj );
                }
            }
        }
        else
        {
            OSL_FAIL( "File(s) could not be opened" );
        }

        pIStm.reset();
        pTmpStm.reset();

        CopyFile( aTmpURL, aInURL );
        KillFile( aTmpURL );

        ErrCode nStorErr = ERRCODE_NONE;

        try
        {
            tools::SvRef<SotStorage> aTempStorageRef( new SotStorage( false, aTmpURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::STD_READWRITE ) );
            aSvDrawStorageRef->CopyTo( aTempStorageRef.get() );
            nStorErr = aSvDrawStorageRef->GetError();
        }
        catch (const css::ucb::ContentCreationException& e)
        {
            SAL_WARN("svx", "failed to open: "
                      << aTmpURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)
                      << "due to : " << e);
            nStorErr = ERRCODE_IO_GENERAL;
        }

        if( nStorErr == ERRCODE_NONE )
        {
            aSvDrawStorageRef.clear();
            CopyFile( aTmpURL, GetSdvURL() );
            ImplCreateSvDrawStorage();
        }

        KillFile( aTmpURL );
        ImplSetModified( true );
        ImplWrite();
        UnlockBroadcaster();
    }

    GalleryThemeEntry* GalleryTheme::CreateThemeEntry( const INetURLObject& rURL, bool bReadOnly )
    {
        DBG_ASSERT( rURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );

        GalleryThemeEntry*  pRet = nullptr;

        if( FileExists( rURL ) )
        {
            std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( rURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));

            if( pIStm )
            {
                OUString        aThemeName;
                sal_uInt16      nVersion;

                pIStm->ReadUInt16( nVersion );

                if( nVersion <= 0x00ff )
                {
                    bool bThemeNameFromResource = false;
                    sal_uInt32      nThemeId = 0;

                    OString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOString(*pIStm);
                    aThemeName = OStringToOUString(aTmpStr, RTL_TEXTENCODING_UTF8);

                    // execute a character conversion
                    if( nVersion >= 0x0004 )
                    {
                        sal_uInt32  nCount;
                        sal_uInt16  nTemp16;

                        pIStm->ReadUInt32( nCount ).ReadUInt16( nTemp16 );
                        pIStm->Seek( STREAM_SEEK_TO_END );

                        // check whether there is a newer version;
                        // therefore jump back by 520Bytes (8 bytes ID + 512Bytes reserve buffer)
                        // if this is at all possible.
                        if( pIStm->Tell() >= 520 )
                        {
                            sal_uInt32 nId1, nId2;

                            pIStm->SeekRel( -520 );
                            pIStm->ReadUInt32( nId1 ).ReadUInt32( nId2 );

                            if( nId1 == COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) &&
                                nId2 == COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) )
                            {
                                std::unique_ptr<VersionCompat> pCompat(new VersionCompat( *pIStm, StreamMode::READ ));

                                pIStm->ReadUInt32( nThemeId );

                                if( pCompat->GetVersion() >= 2 )
                                {
                                    pIStm->ReadCharAsBool( bThemeNameFromResource );
                                }
                            }
                        }
                    }

                    pRet = new GalleryThemeEntry( false, rURL, aThemeName,
                                                  bReadOnly, false, nThemeId,
                                                  bThemeNameFromResource );
                }
            }
        }

        return pRet;
    }

    bool GalleryTheme::GetThumb(sal_uInt32 nPos, BitmapEx& rBmp)
    {
        std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );
        bool        bRet = false;

        if( pObj )
        {
            rBmp = pObj->GetThumbBmp();
            bRet = true;
        }

        return bRet;
    }

    bool GalleryTheme::GetGraphic(sal_uInt32 nPos, Graphic& rGraphic)
    {
        const GalleryObject*    pObject = ImplGetGalleryObject( nPos );
        bool                    bRet = false;

        if( pObject )
        {
            const INetURLObject aURL( ImplGetURL( pObject ) );

            switch( pObject->eObjKind )
            {
                case SgaObjKind::Bitmap:
                case SgaObjKind::Animation:
                case SgaObjKind::Inet:
                {
                    OUString aFilterDummy;
                    bRet = ( GalleryGraphicImport( aURL, rGraphic, aFilterDummy ) != GalleryGraphicImportRet::IMPORT_NONE );
                }
                break;

                case SgaObjKind::SvDraw:
                {
                    SvxGalleryDrawModel aModel;

                    if( aModel.GetModel() )
                    {
                        if( GetModel( nPos, *aModel.GetModel() ) )
                        {
                            ImageMap aIMap;

                            if( CreateIMapGraphic( *aModel.GetModel(), rGraphic, aIMap ) )
                                bRet = true;
                            else
                            {
                                ScopedVclPtrInstance< VirtualDevice > pVDev;
                                pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) );
                                FmFormView aView(*aModel.GetModel(), pVDev);

                                aView.hideMarkHandles();
                                aView.ShowSdrPage(aView.GetModel()->GetPage(0));
                                aView.MarkAll();
                                rGraphic = aView.GetAllMarkedGraphic();
                                bRet = true;
                            }
                        }
                    }
                }
                break;

                case SgaObjKind::Sound:
                {
                    std::unique_ptr<SgaObject> pObj = AcquireObject( nPos );

                    if( pObj )
                    {
                        rGraphic = pObj->GetThumbBmp();
                        //Bitmap aBmp( pObj->GetThumbBmp() );
                        //aBmp.Replace( COL_LIGHTMAGENTA, COL_WHITE );
                        //rGraphic = aBmp;
                        bRet = true;
                    }
                }
                break;

                default:
                break;
            }
        }

        return bRet;
    }

    bool GalleryTheme::InsertGraphic(const Graphic& rGraphic, sal_uInt32 nInsertPos)
    {
        bool bRet = false;

        if( rGraphic.GetType() != GraphicType::NONE )
        {
            ConvertDataFormat nExportFormat = ConvertDataFormat::Unknown;
            const GfxLink     aGfxLink( rGraphic.GetGfxLink() );

            if( aGfxLink.GetDataSize() )
            {
                switch( aGfxLink.GetType() )
                {
                    case GfxLinkType::EpsBuffer: nExportFormat = ConvertDataFormat::SVM; break;
                    case GfxLinkType::NativeGif: nExportFormat = ConvertDataFormat::GIF; break;

                    // #i15508# added BMP type
                    // could not find/trigger a call to this, but should do no harm
                    case GfxLinkType::NativeBmp: nExportFormat = ConvertDataFormat::BMP; break;

                    case GfxLinkType::NativeJpg: nExportFormat = ConvertDataFormat::JPG; break;
                    case GfxLinkType::NativePng: nExportFormat = ConvertDataFormat::PNG; break;
                    case GfxLinkType::NativeTif: nExportFormat = ConvertDataFormat::TIF; break;
                    case GfxLinkType::NativeWmf: nExportFormat = ConvertDataFormat::WMF; break;
                    case GfxLinkType::NativeMet: nExportFormat = ConvertDataFormat::MET; break;
                    case GfxLinkType::NativePct: nExportFormat = ConvertDataFormat::PCT; break;
                    case GfxLinkType::NativeSvg: nExportFormat = ConvertDataFormat::SVG; break;
                    default:
                        break;
                }
            }
            else
            {
                if( rGraphic.GetType() == GraphicType::Bitmap )
                {
                    if( rGraphic.IsAnimated() )
                        nExportFormat = ConvertDataFormat::GIF;
                    else
                        nExportFormat = ConvertDataFormat::PNG;
                }
                else
                    nExportFormat = ConvertDataFormat::SVM;
            }

            const INetURLObject aURL( ImplCreateUniqueURL( SgaObjKind::Bitmap, nExportFormat ) );
            std::unique_ptr<SvStream> pOStm(::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::WRITE | StreamMode::TRUNC ));

            if( pOStm )
            {
                pOStm->SetVersion( SOFFICE_FILEFORMAT_50 );

                if( ConvertDataFormat::SVM == nExportFormat )
                {
                    GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );

                    aMtf.Write( *pOStm );
                    bRet = ( pOStm->GetError() == ERRCODE_NONE );
                }
                else
                {
                    if( aGfxLink.GetDataSize() && aGfxLink.GetData() )
                    {
                        pOStm->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
                        bRet = ( pOStm->GetError() == ERRCODE_NONE );
                    }
                    else
                        bRet = ( GraphicConverter::Export( *pOStm, rGraphic, nExportFormat ) == ERRCODE_NONE );
                }

                pOStm.reset();
            }

            if( bRet )
            {
                const SgaObjectBmp aObjBmp( aURL );
                InsertObject( aObjBmp, nInsertPos );
            }
        }

        return bRet;
    }

    bool GalleryTheme::GetModel(sal_uInt32 nPos, SdrModel& rModel)
    {
        const GalleryObject*    pObject = ImplGetGalleryObject( nPos );
        bool                    bRet = false;

        if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
        {
            const INetURLObject aURL( ImplGetURL( pObject ) );
            tools::SvRef<SotStorage>        xStor( GetSvDrawStorage() );

            if( xStor.is() )
            {
                const OUString        aStmName( GetSvDrawStreamNameFromURL( aURL ) );
                tools::SvRef<SotStorageStream>  xIStm( xStor->OpenSotStream( aStmName, StreamMode::READ ) );

                if( xIStm.is() && !xIStm->GetError() )
                {
                    xIStm->SetBufferSize( STREAMBUF_SIZE );
                    bRet = GallerySvDrawImport( *xIStm, rModel );
                    xIStm->SetBufferSize( 0 );
                }
            }
        }

        return bRet;
    }

    bool GalleryTheme::InsertModel(const FmFormModel& rModel, sal_uInt32 nInsertPos)
    {
        INetURLObject   aURL( ImplCreateUniqueURL( SgaObjKind::SvDraw ) );
        tools::SvRef<SotStorage>    xStor( GetSvDrawStorage() );
        bool            bRet = false;

        if( xStor.is() )
        {
            const OUString        aStmName( GetSvDrawStreamNameFromURL( aURL ) );
            tools::SvRef<SotStorageStream>  xOStm( xStor->OpenSotStream( aStmName, StreamMode::WRITE | StreamMode::TRUNC ) );

            if( xOStm.is() && !xOStm->GetError() )
            {
                SvMemoryStream  aMemStm( 65535, 65535 );
                FmFormModel*    pFormModel = const_cast<FmFormModel*>(&rModel);

                pFormModel->BurnInStyleSheetAttributes();

                {
                    uno::Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( aMemStm ) );

                    if( xDocOut.is() )
                        SvxDrawingLayerExport( pFormModel, xDocOut );
                }

                aMemStm.Seek( 0 );

                xOStm->SetBufferSize( 16348 );
                GalleryCodec aCodec( *xOStm );
                aCodec.Write( aMemStm );

                if( !xOStm->GetError() )
                {
                    SgaObjectSvDraw aObjSvDraw( rModel, aURL );
                    bRet = InsertObject( aObjSvDraw, nInsertPos );
                }

                xOStm->SetBufferSize( 0 );
                xOStm->Commit();
            }
        }

        return bRet;
    }

    bool GalleryTheme::GetModelStream(sal_uInt32 nPos, tools::SvRef<SotStorageStream> const & rxModelStream)
    {
        const GalleryObject*    pObject = ImplGetGalleryObject( nPos );
        bool                    bRet = false;

        if( pObject && ( SgaObjKind::SvDraw == pObject->eObjKind ) )
        {
            const INetURLObject aURL( ImplGetURL( pObject ) );
            tools::SvRef<SotStorage>        xStor( GetSvDrawStorage() );

            if( xStor.is() )
            {
                const OUString        aStmName( GetSvDrawStreamNameFromURL( aURL ) );
                tools::SvRef<SotStorageStream>  xIStm( xStor->OpenSotStream( aStmName, StreamMode::READ ) );

                if( xIStm.is() && !xIStm->GetError() )
                {
                    sal_uInt32 nVersion = 0;

                    xIStm->SetBufferSize( 16348 );

                    if( GalleryCodec::IsCoded( *xIStm, nVersion ) )
                    {
                        SvxGalleryDrawModel aModel;

                        if( aModel.GetModel() )
                        {
                            if( GallerySvDrawImport( *xIStm, *aModel.GetModel() ) )
                            {
                                aModel.GetModel()->BurnInStyleSheetAttributes();

                                {
                                    uno::Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxModelStream ) );

                                    if( SvxDrawingLayerExport( aModel.GetModel(), xDocOut ) )
                                        rxModelStream->Commit();
                                }
                            }

                            bRet = ( rxModelStream->GetError() == ERRCODE_NONE );
                        }
                    }

                    xIStm->SetBufferSize( 0 );
                }
            }
        }

        return bRet;
    }

    bool GalleryTheme::InsertModelStream(const tools::SvRef<SotStorageStream>& rxModelStream, sal_uInt32 nInsertPos)
    {
        INetURLObject   aURL( ImplCreateUniqueURL( SgaObjKind::SvDraw ) );
        tools::SvRef<SotStorage>    xStor( GetSvDrawStorage() );
        bool            bRet = false;

        if( xStor.is() )
        {
            const OUString        aStmName( GetSvDrawStreamNameFromURL( aURL ) );
            tools::SvRef<SotStorageStream>  xOStm( xStor->OpenSotStream( aStmName, StreamMode::WRITE | StreamMode::TRUNC ) );

            if( xOStm.is() && !xOStm->GetError() )
            {
                GalleryCodec    aCodec( *xOStm );
                SvMemoryStream  aMemStm( 65535, 65535 );

                xOStm->SetBufferSize( 16348 );
                aCodec.Write( *rxModelStream );

                if( !xOStm->GetError() )
                {
                    xOStm->Seek( 0 );
                    SgaObjectSvDraw aObjSvDraw( *xOStm, aURL );
                    bRet = InsertObject( aObjSvDraw, nInsertPos );
                }

                xOStm->SetBufferSize( 0 );
                xOStm->Commit();
            }
        }

        return bRet;
    }

    bool GalleryTheme::GetURL(sal_uInt32 nPos, INetURLObject& rURL)
    {
        const GalleryObject*    pObject = ImplGetGalleryObject( nPos );
        bool                    bRet = false;

        if( pObject )
        {
            rURL = ImplGetURL( pObject );
            bRet = true;
        }

        return bRet;
    }

    bool GalleryTheme::InsertURL(const INetURLObject& rURL, sal_uInt32 nInsertPos)
    {
        Graphic         aGraphic;
        OUString        aFormat;
        std::unique_ptr<SgaObject> pNewObj;
        const GalleryGraphicImportRet nImportRet = GalleryGraphicImport( rURL, aGraphic, aFormat );
        bool            bRet = false;

        if( nImportRet != GalleryGraphicImportRet::IMPORT_NONE )
        {
            if ( aGraphic.IsAnimated() )
                pNewObj.reset(static_cast<SgaObject*>(new SgaObjectAnim( aGraphic, rURL )));
            else
                pNewObj.reset(static_cast<SgaObject*>(new SgaObjectBmp( aGraphic, rURL )));
        }
    #if HAVE_FEATURE_AVMEDIA
        else if( ::avmedia::MediaWindow::isMediaURL( rURL.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ), ""/*TODO?*/ ) )
            pNewObj.reset(static_cast<SgaObject*>(new SgaObjectSound( rURL )));
    #endif
        if( pNewObj && InsertObject( *pNewObj, nInsertPos ) )
            bRet = true;

        return bRet;
    }

    bool GalleryTheme::InsertFileOrDirURL(const INetURLObject& rFileOrDirURL, sal_uInt32 nInsertPos)
    {
        INetURLObject                   aURL;
        ::std::vector< INetURLObject >  aURLVector;
        bool                            bRet = false;

        try
        {
            ::ucbhelper::Content         aCnt( rFileOrDirURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
            bool        bFolder = false;

            aCnt.getPropertyValue("IsFolder") >>= bFolder;

            if( bFolder )
            {
                uno::Sequence<OUString> aProps { "Url" };
                uno::Reference< sdbc::XResultSet > xResultSet( aCnt.createCursor( aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
                uno::Reference< ucb::XContentAccess > xContentAccess( xResultSet, uno::UNO_QUERY );
                if( xContentAccess.is() )
                {
                    while( xResultSet->next() )
                    {
                        aURL.SetSmartURL( xContentAccess->queryContentIdentifierString() );
                        aURLVector.push_back( aURL );
                    }
                }
            }
            else
                aURLVector.push_back( rFileOrDirURL );
        }
        catch( const ucb::ContentCreationException& )
        {
        }
        catch( const uno::RuntimeException& )
        {
        }
        catch( const uno::Exception& )
        {
        }

        ::std::vector< INetURLObject >::const_iterator aIter( aURLVector.begin() ), aEnd( aURLVector.end() );

        while( aIter != aEnd )
            bRet = bRet || InsertURL( *aIter++, nInsertPos );

        return bRet;
    }

    bool GalleryTheme::InsertTransferable(const uno::Reference< datatransfer::XTransferable >& rxTransferable, sal_uInt32 nInsertPos)
    {
        bool bRet = false;

        if( rxTransferable.is() )
        {
            TransferableDataHelper  aDataHelper( rxTransferable );
            std::unique_ptr<Graphic> pGraphic;

            if( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
            {
                tools::SvRef<SotStorageStream> xModelStm;

                if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xModelStm ) )
                    bRet = InsertModelStream( xModelStm, nInsertPos );
            }
            else if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) ||
                     aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
            {
                FileList aFileList;

                if( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
                    aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
                else
                {
                    OUString aFile;
                    if (aDataHelper.GetString(SotClipboardFormatId::SIMPLE_FILE, aFile) && !aFile.isEmpty())
                        aFileList.AppendFile( aFile );
                }

                for( sal_uInt32 i = 0, nCount = aFileList.Count(); i < nCount; ++i )
                {
                    const OUString  aFile( aFileList.GetFile( i ) );
                    INetURLObject   aURL( aFile );

                    if( aURL.GetProtocol() == INetProtocol::NotValid )
                    {
                        OUString aLocalURL;

                        if( osl::FileBase::getFileURLFromSystemPath( aFile, aLocalURL ) == osl::FileBase::E_None )
                            aURL = INetURLObject( aLocalURL );
                    }

                    if( aURL.GetProtocol() != INetProtocol::NotValid )
                        bRet = InsertFileOrDirURL( aURL, nInsertPos );
                }
            }
            else
            {
                Graphic aGraphic;
                SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;

                if( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
                    nFormat = SotClipboardFormatId::SVXB;
                else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
                    nFormat = SotClipboardFormatId::GDIMETAFILE;
                else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
                    nFormat = SotClipboardFormatId::BITMAP;

                if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetGraphic( nFormat, aGraphic ) )
                    pGraphic.reset(new Graphic( aGraphic ));
            }

            if( pGraphic )
            {
                bRet = false;

                if( aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) )
                {

                    ImageMap aImageMap;

                    // according to KA we don't need a BaseURL here
                    if( aDataHelper.GetImageMap( SotClipboardFormatId::SVIM, aImageMap ) )
                    {
                        SvxGalleryDrawModel aModel;

                        if( aModel.GetModel() )
                        {
                            SdrPage*    pPage = aModel.GetModel()->GetPage(0);
                            SdrGrafObj* pGrafObj = new SdrGrafObj(*aModel.GetModel(), *pGraphic );

                            pGrafObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SgaIMapInfo( aImageMap )) );
                            pPage->InsertObject( pGrafObj );
                            bRet = InsertModel( *aModel.GetModel(), nInsertPos );
                        }
                    }
                }

                if( !bRet )
                    bRet = InsertGraphic( *pGraphic, nInsertPos );
            }
        }

        return bRet;
    }

    void GalleryTheme::CopyToClipboard(vcl::Window* pWindow, sal_uInt32 nPos)
    {
        GalleryTransferable* pTransferable = new GalleryTransferable( this, nPos, false );
        pTransferable->CopyToClipboard( pWindow );
    }

    void GalleryTheme::StartDrag(vcl::Window* pWindow, sal_uInt32 nPos)
    {
        GalleryTransferable* pTransferable = new GalleryTransferable( this, nPos, true );
        pTransferable->StartDrag( pWindow, DND_ACTION_COPY | DND_ACTION_LINK );
    }

    SvStream& GalleryTheme::WriteData( SvStream& rOStm ) const
    {
        const INetURLObject aRelURL1( GetParent()->GetRelativeURL() );
        const INetURLObject aRelURL2( GetParent()->GetUserURL() );
        sal_uInt32          nCount = GetObjectCount();
        bool                bRel;

        rOStm.WriteUInt16( 0x0004 );
        write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, pThm->GetThemeName(), RTL_TEXTENCODING_UTF8);
        rOStm.WriteUInt32( nCount ).WriteUInt16( osl_getThreadTextEncoding() );

        for( sal_uInt32 i = 0; i < nCount; i++ )
        {
            const GalleryObject* pObj = ImplGetGalleryObject( i );
            OUString               aPath;

            if( SgaObjKind::SvDraw == pObj->eObjKind )
            {
                aPath = GetSvDrawStreamNameFromURL( pObj->aURL );
                bRel = false;
            }
            else
            {
                aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                aPath = aPath.copy( 0, std::min(aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) );
                bRel = aPath == aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE );

                if( bRel && ( pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() > ( aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() + 1 ) ) )
                {
                    aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                    aPath = aPath.copy( std::min(aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) );
                }
                else
                {
                    aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                    aPath = aPath.copy( 0, std::min(aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) );
                    bRel = aPath == aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE );

                    if( bRel && ( pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() > ( aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength() + 1 ) ) )
                    {
                        aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                        aPath = aPath.copy( std::min(aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ).getLength(), aPath.getLength()) );
                    }
                    else
                        aPath = pObj->aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                }
            }

            if ( !m_aDestDir.isEmpty() )
            {
                bool aFound = aPath.indexOf(m_aDestDir) != -1;
                aPath = aPath.replaceFirst(m_aDestDir, "");
                if ( aFound )
                    bRel = m_bDestDirRelative;
                else
                    SAL_WARN( "svx", "failed to replace destdir of '"
                              << m_aDestDir << "' in '" << aPath << "'");
            }

            rOStm.WriteBool( bRel );
            write_uInt16_lenPrefixed_uInt8s_FromOUString(rOStm, aPath, RTL_TEXTENCODING_UTF8);
            rOStm.WriteUInt32( pObj->nOffset ).WriteUInt16( static_cast<sal_uInt16>(pObj->eObjKind) );
        }

        // more recently, a 512-byte reserve buffer is written,
        // to recognize them two sal_uInt32-Ids will be written.
        rOStm.WriteUInt32( COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) ).WriteUInt32( COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) );

        const long      nReservePos = rOStm.Tell();
        std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rOStm, StreamMode::WRITE, 2 ));

        rOStm.WriteUInt32( GetId() ).WriteBool( IsThemeNameFromResource() ); // From version 2 and up

        pCompat.reset();

        // Fill the rest of the buffer.
        const long  nRest = std::max( 512L - ( static_cast<long>(rOStm.Tell()) - nReservePos ), 0L );

        if( nRest )
        {
            std::unique_ptr<char[]> pReserve(new char[ nRest ]);
            memset( pReserve.get(), 0, nRest );
            rOStm.WriteBytes(pReserve.get(), nRest);
        }

        return rOStm;
    }

    SvStream& GalleryTheme::ReadData( SvStream& rIStm )
    {
        sal_uInt32          nCount;
        sal_uInt16          nVersion;

        rIStm.ReadUInt16( nVersion );
        read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
        rIStm.ReadUInt32( nCount );

        if( nVersion >= 0x0004 )
        {
            sal_uInt16 nTmp16;
            rIStm.ReadUInt16( nTmp16 );
        }

        if( nCount <= ( 1 << 14 ) )
        {
            INetURLObject   aRelURL1( GetParent()->GetRelativeURL() );
            INetURLObject   aRelURL2( GetParent()->GetUserURL() );
            sal_uInt32      nId1, nId2;
            bool            bRel;

            for(auto & i : aObjectList)
            {
                GalleryObject* pObj = i.get();
                Broadcast( GalleryHint( GalleryHintType::CLOSE_OBJECT, GetName(), pObj ) );
                Broadcast( GalleryHint( GalleryHintType::OBJECT_REMOVED, GetName(), pObj ) );
                i.reset();
            }
            aObjectList.clear();

            for( sal_uInt32 i = 0; i < nCount; i++ )
            {
                std::unique_ptr<GalleryObject> pObj(new GalleryObject);

                OUString    aFileName;
                OUString    aPath;
                sal_uInt16  nTemp;

                rIStm.ReadCharAsBool( bRel );
                OString aTempFileName = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
                rIStm.ReadUInt32( pObj->nOffset );
                rIStm.ReadUInt16( nTemp ); pObj->eObjKind = static_cast<SgaObjKind>(nTemp);

                aFileName = OStringToOUString(aTempFileName, osl_getThreadTextEncoding());

                if( bRel )
                {
                    aFileName = aFileName.replaceAll( "\\", "/" );
                    aPath = aRelURL1.GetMainURL( INetURLObject::DecodeMechanism::NONE );

                    if( aFileName[ 0 ] != '/' )
                            aPath += "/";

                    aPath += aFileName;

                    pObj->aURL = INetURLObject( aPath );

                    if( !FileExists( pObj->aURL ) )
                    {
                        aPath = aRelURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE );

                        if( aFileName[0] != '/' )
                            aPath += "/";

                        aPath += aFileName;

                        // assign this URL, even in the case it is not valid (#94482)
                        pObj->aURL = INetURLObject( aPath );
                    }
                }
                else
                {
                    if( SgaObjKind::SvDraw == pObj->eObjKind )
                    {
                        OUString aDummyURL( "gallery/svdraw/" );
                        pObj->aURL = INetURLObject( aDummyURL += aFileName, INetProtocol::PrivSoffice );
                    }
                    else
                    {
                        OUString aLocalURL;

                        pObj->aURL = INetURLObject( aFileName );

                        if( ( pObj->aURL.GetProtocol() == INetProtocol::NotValid ) &&
                            osl::FileBase::getFileURLFromSystemPath( aFileName, aLocalURL ) == osl::FileBase::E_None )
                        {
                            pObj->aURL = INetURLObject( aLocalURL );
                        }
                    }
                }
                aObjectList.push_back( std::move(pObj) );
            }

            rIStm.ReadUInt32( nId1 ).ReadUInt32( nId2 );

            // In newer versions a 512 byte reserve buffer is located at the end,
            // the data is located at the beginning of this buffer and are clamped
            // by a VersionCompat.
            if( !rIStm.eof() &&
                nId1 == COMPAT_FORMAT( 'G', 'A', 'L', 'R' ) &&
                nId2 == COMPAT_FORMAT( 'E', 'S', 'R', 'V' ) )
            {
                std::unique_ptr<VersionCompat> pCompat(new VersionCompat( rIStm, StreamMode::READ ));
                sal_uInt32      nTemp32;
                bool            bThemeNameFromResource = false;

                rIStm.ReadUInt32( nTemp32 );

                if( pCompat->GetVersion() >= 2 )
                {
                    rIStm.ReadCharAsBool( bThemeNameFromResource );
                }

                SetId( nTemp32, bThemeNameFromResource );
            }
        }
        else
            rIStm.SetError( SVSTREAM_READ_ERROR );

        ImplSetModified( false );

        return rIStm;
    }

    SvStream& WriteGalleryTheme( SvStream& rOut, const GalleryTheme& rTheme )
    {
        return rTheme.WriteData( rOut );
    }

    SvStream& ReadGalleryTheme( SvStream& rIn, GalleryTheme& rTheme )
    {
        return rTheme.ReadData( rIn );
    }

    void GalleryTheme::ImplSetModified( bool bModified )
    {
        pThm->SetModified(bModified);
    }

    const INetURLObject& GalleryTheme::GetThmURL() const { return pThm->GetThmURL(); }
    const INetURLObject& GalleryTheme::GetSdgURL() const { return pThm->GetSdgURL(); }
    const INetURLObject& GalleryTheme::GetSdvURL() const { return pThm->GetSdvURL(); }
    sal_uInt32 GalleryTheme::GetId() const { return pThm->GetId(); }
    void GalleryTheme::SetId( sal_uInt32 nNewId, bool bResetThemeName ) { pThm->SetId( nNewId, bResetThemeName ); }
    bool GalleryTheme::IsThemeNameFromResource() const { return pThm->IsNameFromResource(); }
    bool GalleryTheme::IsReadOnly() const { return pThm->IsReadOnly(); }
    bool GalleryTheme::IsDefault() const { return pThm->IsDefault(); }

    const tools::SvRef<SotStorage>& GalleryTheme::GetSvDrawStorage() const
    {
        return aSvDrawStorageRef;
    }

    const OUString& GalleryTheme::GetName() const { return pThm->GetThemeName(); }

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

↑ V773 Visibility scope of the 'pTransferable' pointer was exited without releasing the memory. A memory leak is possible.

↑ V773 Visibility scope of the 'pTransferable' pointer was exited without releasing the memory. A memory leak is possible.