/* -*- 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_dbaccess.hxx"

#include "dbmm_global.hrc"
#include "dbmm_module.hxx"
#include "dbmm_types.hxx"
#include "docinteraction.hxx"
#include "migrationengine.hxx"
#include "migrationerror.hxx"
#include "migrationprogress.hxx"
#include "migrationlog.hxx"
#include "progresscapture.hxx"
#include "progressmixer.hxx"

/** === begin UNO includes === **/
#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
#include <com/sun/star/util/XCloseable.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/ucb/XCommandProcessor.hpp>
#include <com/sun/star/ucb/XContent.hpp>
#include <com/sun/star/embed/XComponentSupplier.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/embed/XEmbedPersist.hpp>
#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
#include <com/sun/star/document/XEmbeddedScripts.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/uri/UriReferenceFactory.hpp>
#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
#include <com/sun/star/form/XFormsSupplier.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/script/XEventAttacherManager.hpp>
#include <com/sun/star/script/XLibraryContainerPassword.hpp>
#include <com/sun/star/io/WrongFormatException.hpp>
#include <com/sun/star/script/XScriptEventsSupplier.hpp>
#include <com/sun/star/io/XInputStreamProvider.hpp>
/** === end UNO includes === **/

#include <comphelper/documentinfo.hxx>
#include <comphelper/interaction.hxx>
#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/storagehelper.hxx>
#include <comphelper/string.hxx>
#include <comphelper/types.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <tools/string.hxx>
#include <tools/diagnose_ex.h>
#include <rtl/ustrbuf.hxx>
#include <rtl/ref.hxx>
#include <unotools/sharedunocomponent.hxx>
#include <xmlscript/xmldlg_imexp.hxx>

#include <vector>
#include <set>

#define DEFAULT_DOC_PROGRESS_RANGE  100000

//........................................................................
namespace dbmm
{
//........................................................................

    /** === begin UNO using === **/
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::uno::XInterface;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::uno::UNO_QUERY_THROW;
    using ::com::sun::star::uno::UNO_SET_THROW;
    using ::com::sun::star::uno::Exception;
    using ::com::sun::star::uno::RuntimeException;
    using ::com::sun::star::uno::Any;
    using ::com::sun::star::uno::makeAny;
    using ::com::sun::star::sdb::XOfficeDatabaseDocument;
    using ::com::sun::star::sdb::XFormDocumentsSupplier;
    using ::com::sun::star::sdb::XReportDocumentsSupplier;
    using ::com::sun::star::container::XNameAccess;
    using ::com::sun::star::uno::Sequence;
    using ::com::sun::star::util::XCloseable;
    using ::com::sun::star::util::CloseVetoException;
    using ::com::sun::star::lang::XComponent;
    using ::com::sun::star::frame::XModel;
    using ::com::sun::star::frame::XComponentLoader;
    using ::com::sun::star::ucb::XCommandProcessor;
    using ::com::sun::star::ucb::XContent;
    using ::com::sun::star::ucb::Command;
    using ::com::sun::star::embed::XComponentSupplier;
    using ::com::sun::star::task::XStatusIndicator;
    using ::com::sun::star::embed::XStorage;
    using ::com::sun::star::document::XStorageBasedDocument;
    using ::com::sun::star::embed::XTransactedObject;
    using ::com::sun::star::frame::XStorable;
    using ::com::sun::star::embed::XEmbedPersist;
    using ::com::sun::star::script::DocumentDialogLibraryContainer;
    using ::com::sun::star::script::DocumentScriptLibraryContainer;
    using ::com::sun::star::script::XStorageBasedLibraryContainer;
    using ::com::sun::star::document::XEmbeddedScripts;
    using ::com::sun::star::container::XNameContainer;
    using ::com::sun::star::document::XEventsSupplier;
    using ::com::sun::star::container::XNameReplace;
    using com::sun::star::uri::UriReferenceFactory;
    using com::sun::star::uri::XUriReferenceFactory;
    using com::sun::star::uri::XVndSunStarScriptUrlReference;
    using ::com::sun::star::form::XFormsSupplier;
    using ::com::sun::star::drawing::XDrawPageSupplier;
    using ::com::sun::star::drawing::XDrawPagesSupplier;
    using ::com::sun::star::drawing::XDrawPage;
    using ::com::sun::star::drawing::XDrawPages;
    using ::com::sun::star::container::XIndexAccess;
    using ::com::sun::star::script::XEventAttacherManager;
    using ::com::sun::star::script::ScriptEventDescriptor;
    using ::com::sun::star::script::XLibraryContainerPassword;
    using ::com::sun::star::io::WrongFormatException;
    using ::com::sun::star::script::XScriptEventsSupplier;
    using ::com::sun::star::io::XInputStreamProvider;
    using ::com::sun::star::io::XInputStream;
    /** === end UNO using === **/
    namespace ElementModes = ::com::sun::star::embed::ElementModes;

// migration phases whose progresses are to be mixed into one progress
#define PHASE_JAVASCRIPT    1
#define PHASE_BEANSHELL     2
#define PHASE_PYTHON        3
#define PHASE_JAVA          4
#define PHASE_BASIC         5
#define PHASE_DIALOGS       6

    //====================================================================
    //= SubDocument
    //====================================================================
    struct SubDocument
    {
        Reference< XCommandProcessor >  xCommandProcessor;
        Reference< XModel >             xDocument;          // valid only temporarily
        ::rtl::OUString                 sHierarchicalName;
        SubDocumentType                 eType;
        size_t                          nNumber;

        SubDocument( const Reference< XCommandProcessor >& _rxCommandProcessor, const ::rtl::OUString& _rName,
                const SubDocumentType _eType, const size_t _nNumber )
            :xCommandProcessor( _rxCommandProcessor )
            ,xDocument()
            ,sHierarchicalName( _rName )
            ,eType( _eType )
            ,nNumber( _nNumber )
        {
        }
    };

    typedef ::std::vector< SubDocument >    SubDocuments;

    //====================================================================
    //= helper
    //====================================================================
    //--------------------------------------------------------------------
    typedef ::utl::SharedUNOComponent< XStorage >   SharedStorage;

    namespace
    {
        //----------------------------------------------------------------
        static const ::rtl::OUString& lcl_getScriptsStorageName()
        {
            static const ::rtl::OUString s_sScriptsStorageName( RTL_CONSTASCII_USTRINGPARAM( "Scripts" ) );
            return s_sScriptsStorageName;
        }

        //----------------------------------------------------------------
        static const ::rtl::OUString& lcl_getScriptsSubStorageName( const ScriptType _eType )
        {
            static const ::rtl::OUString s_sBeanShell ( RTL_CONSTASCII_USTRINGPARAM( "beanshell" ) );
            static const ::rtl::OUString s_sJavaScript( RTL_CONSTASCII_USTRINGPARAM( "javascript" ) );
            static const ::rtl::OUString s_sPython    ( RTL_CONSTASCII_USTRINGPARAM( "python" ) );      // TODO: is this correct?
            static const ::rtl::OUString s_sJava      ( RTL_CONSTASCII_USTRINGPARAM( "java" ) );

            switch ( _eType )
            {
            case eBeanShell:    return s_sBeanShell;
            case eJavaScript:   return s_sJavaScript;
            case ePython:       return s_sPython;
            case eJava:         return s_sJava;
            default:
                break;
            }

            OSL_ENSURE( false, "lcl_getScriptsSubStorageName: illegal type!" );
            static ::rtl::OUString s_sEmpty;
            return s_sEmpty;
        }

        //----------------------------------------------------------------
        static bool lcl_getScriptTypeFromLanguage( const ::rtl::OUString& _rLanguage, ScriptType& _out_rScriptType )
        {
            struct LanguageMapping
            {
                const sal_Char*     pAsciiLanguage;
                const ScriptType    eScriptType;

                LanguageMapping( const sal_Char* _pAsciiLanguage, const ScriptType _eScriptType )
                    :pAsciiLanguage( _pAsciiLanguage )
                    ,eScriptType( _eScriptType )
                {
                }
            }
            aLanguageMapping[] =
            {
                LanguageMapping( "JavaScript", eJavaScript ),
                LanguageMapping( "BeanShell",  eBeanShell ),
                LanguageMapping( "Java",       eJava ),
                LanguageMapping( "Python",     ePython ),          // TODO: is this correct?
                LanguageMapping( "Basic",      eBasic )
            };
            for ( size_t i=0; i < SAL_N_ELEMENTS( aLanguageMapping ); ++i )
            {
                if ( _rLanguage.equalsAscii( aLanguageMapping[i].pAsciiLanguage ) )
                {
                    _out_rScriptType = aLanguageMapping[i].eScriptType;
                    return true;
                }
            }
            OSL_ENSURE( false, "lcl_getScriptTypeFromLanguage: unknown language!" );
            return false;
        }

        //----------------------------------------------------------------
        ::rtl::OUString lcl_getSubDocumentDescription( const SubDocument& _rDocument )
        {
            ::rtl::OUString sObjectName = String( MacroMigrationResId( _rDocument.eType == eForm ? STR_FORM : STR_REPORT ) );
            ::comphelper::string::searchAndReplaceAsciiI( sObjectName, "$name$", _rDocument.sHierarchicalName );
            return sObjectName;
        }

        //----------------------------------------------------------------
        static Any lcl_executeCommand_throw( const Reference< XCommandProcessor >& _rxCommandProc,
            const sal_Char* _pAsciiCommand )
        {
            OSL_PRECOND( _rxCommandProc.is(), "lcl_executeCommand_throw: illegal object!" );
            if ( !_rxCommandProc.is() )
                return Any();

            Command aCommand;
            aCommand.Name = ::rtl::OUString::createFromAscii( _pAsciiCommand );
            return _rxCommandProc->execute(
                aCommand, _rxCommandProc->createCommandIdentifier(), NULL );
        }

        //----------------------------------------------------------------
        ::rtl::OUString lcl_getMimeType_nothrow( const Reference< XCommandProcessor >& _rxContent )
        {
            ::rtl::OUString sMimeType;
            try
            {
                Reference< XContent > xContent( _rxContent, UNO_QUERY_THROW );
                sMimeType = xContent->getContentType();
            }
            catch( const Exception& )
            {
                DBG_UNHANDLED_EXCEPTION();
            }
            return sMimeType;
        }

        //----------------------------------------------------------------
        enum OpenDocResult
        {
            eOpenedDoc,
            eIgnoreDoc,
            eFailure
        };

        //----------------------------------------------------------------
        static OpenDocResult lcl_loadSubDocument_nothrow( SubDocument& _rDocument,
            const Reference< XStatusIndicator >& _rxProgress, MigrationLog& _rLogger )
        {
            OSL_PRECOND( !_rDocument.xDocument.is(), "lcl_loadSubDocument_nothrow: already loaded!" );

            try
            {
                ::comphelper::NamedValueCollection aLoadArgs;
                aLoadArgs.put( "Hidden", (sal_Bool)sal_True );
                aLoadArgs.put( "StatusIndicator", _rxProgress );

                Reference< XCommandProcessor > xCommandProcessor( _rDocument.xCommandProcessor, UNO_SET_THROW );
                Command aCommand;
                aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "openDesign" ) );
                aCommand.Argument <<= aLoadArgs.getPropertyValues();
                Reference< XComponent > xDocComponent(
                    xCommandProcessor->execute(
                        aCommand, xCommandProcessor->createCommandIdentifier(), NULL
                    ),
                    UNO_QUERY
                );
                OSL_ENSURE( xDocComponent.is(), "lcl_loadSubDocument_nothrow: no component loaded!" );

                _rDocument.xDocument.set( xDocComponent, UNO_QUERY_THROW );
            }
            catch( const Exception& )
            {
                Any aError( ::cppu::getCaughtException() );

                bool bCausedByNewStyleReport =
                        ( _rDocument.eType == eReport )
                    &&  ( aError.isExtractableTo( ::cppu::UnoType< WrongFormatException >::get() ) )
                    &&  ( lcl_getMimeType_nothrow( _rDocument.xCommandProcessor ).equalsAscii( "application/vnd.sun.xml.report" ) );

                if ( bCausedByNewStyleReport )
                {
                    _rLogger.logRecoverable( MigrationError(
                        ERR_NEW_STYLE_REPORT,
                        lcl_getSubDocumentDescription( _rDocument )
                    ) );
                    return eIgnoreDoc;
                }
                else
                {
                    _rLogger.logFailure( MigrationError(
                        ERR_OPENING_SUB_DOCUMENT_FAILED,
                        lcl_getSubDocumentDescription( _rDocument ),
                        aError
                    ) );
                }
            }
            return _rDocument.xDocument.is() ? eOpenedDoc : eFailure;
        }

        //----------------------------------------------------------------
        static bool lcl_unloadSubDocument_nothrow( SubDocument& _rDocument, MigrationLog& _rLogger )
        {
            bool bSuccess = false;
            Any aException;
            try
            {
                OSL_VERIFY( lcl_executeCommand_throw( _rDocument.xCommandProcessor, "close" ) >>= bSuccess );
            }
            catch( const Exception& )
            {
                aException = ::cppu::getCaughtException();
            }

            // log the failure, if any
            if ( !bSuccess )
            {
                _rLogger.logFailure( MigrationError(
                    ERR_CLOSING_SUB_DOCUMENT_FAILED,
                    lcl_getSubDocumentDescription( _rDocument ),
                    aException
                ) );
            }

            _rDocument.xDocument.clear();
            return bSuccess;
        }

        //----------------------------------------------------------------
        bool lcl_commitStorage_nothrow( const Reference< XStorage >& _rxStorage )
        {
            try
            {
                Reference< XTransactedObject > xTrans( _rxStorage, UNO_QUERY_THROW );
                xTrans->commit();
            }
            catch( const Exception& )
            {
                return false;
            }
            return true;
        }

        //----------------------------------------------------------------
        bool lcl_commitDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
        {
            bool bSuccess = false;
            Any aException;
            try
            {
                Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
                Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );
                bSuccess = lcl_commitStorage_nothrow( xDocStorage );
            }
            catch( const Exception& )
            {
                aException = ::cppu::getCaughtException();
            }

            // log the failure, if any
            if ( !bSuccess )
            {
                _rLogger.logFailure( MigrationError(
                    ERR_STORAGE_COMMIT_FAILED,
                    ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
                    aException
                ) );
            }
            return bSuccess;
        }

        //----------------------------------------------------------------
        bool lcl_storeDocument_nothrow( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
        {
            bool bSuccess = false;
            Any aException;
            try
            {
                Reference< XStorable > xStorable( _rxDocument, UNO_QUERY_THROW );
                xStorable->store();
                bSuccess = true;
            }
            catch( const Exception& )
            {
                aException = ::cppu::getCaughtException();
            }

            // log the failure, if any
            if ( !bSuccess )
            {
                _rLogger.logFailure( MigrationError(
                    ERR_STORING_DATABASEDOC_FAILED,
                    aException
                ) );
            }
            return bSuccess;
        }

        //----------------------------------------------------------------
        bool lcl_storeEmbeddedDocument_nothrow( const SubDocument& _rDocument )
        {
            try
            {
                lcl_executeCommand_throw( _rDocument.xCommandProcessor, "store" );
            }
            catch( const Exception& )
            {
                DBG_UNHANDLED_EXCEPTION();
                return false;
            }
            return true;
        }
    }

    //====================================================================
    //= DrawPageIterator
    //====================================================================
    class DrawPageIterator
    {
    public:
        DrawPageIterator( const Reference< XModel >& _rxDocument )
            :m_xDocument( _rxDocument )
            ,m_nPageCount( 0 )
            ,m_nCurrentPage( 0 )
        {
            Reference< XDrawPageSupplier > xSingle( _rxDocument, UNO_QUERY );
            Reference< XDrawPagesSupplier > xMulti( _rxDocument, UNO_QUERY );
            if ( xSingle.is() )
            {
                m_xSinglePage.set( xSingle->getDrawPage(), UNO_SET_THROW );
                m_nPageCount = 1;
            }
            else if ( xMulti.is() )
            {
                m_xMultiPages.set( xMulti->getDrawPages(), UNO_SET_THROW );
                m_nPageCount = m_xMultiPages->getCount();
            }
        }

        bool hasMore() const
        {
            return m_nCurrentPage < m_nPageCount;
        }

        Reference< XDrawPage > next()
        {
            Reference< XDrawPage > xNextPage;

            if ( m_xSinglePage.is() )
            {
                xNextPage = m_xSinglePage;
            }
            else if ( m_xMultiPages.is() )
            {
                xNextPage.set( m_xMultiPages->getByIndex( m_nCurrentPage ), UNO_QUERY_THROW );
            }
            ++m_nCurrentPage;
            return xNextPage;
        }

    private:
        const Reference< XModel >   m_xDocument;
        Reference< XDrawPage >      m_xSinglePage;
        Reference< XDrawPages >     m_xMultiPages;
        sal_Int32                   m_nPageCount;
        sal_Int32                   m_nCurrentPage;
    };

    //====================================================================
    //= FormComponentScripts
    //====================================================================
    class FormComponentScripts
    {
    public:
        FormComponentScripts(
                const Reference< XInterface >& _rxComponent,
                const Reference< XEventAttacherManager >& _rxManager,
                const sal_Int32 _nIndex
            )
            :m_xComponent( _rxComponent, UNO_SET_THROW )
            ,m_xManager( _rxManager, UNO_SET_THROW )
            ,m_nIndex( _nIndex )
        {
        }

        Sequence< ScriptEventDescriptor > getEvents() const
        {
            return m_xManager->getScriptEvents( m_nIndex );
        }

        void setEvents( const Sequence< ScriptEventDescriptor >& _rEvents  ) const
        {
            m_xManager->registerScriptEvents( m_nIndex, _rEvents );
        }

        const Reference< XInterface >& getComponent() const
        {
            return m_xComponent;
        }

    private:
        const Reference< XInterface >               m_xComponent;
        const Reference< XEventAttacherManager >    m_xManager;
        const sal_Int32                             m_nIndex;
    };

    //====================================================================
    //= FormComponentIterator
    //====================================================================
    class FormComponentIterator
    {
    public:
        FormComponentIterator( const Reference< XIndexAccess >& _rxContainer )
            :m_xContainer( _rxContainer, UNO_SET_THROW )
            ,m_xEventManager( _rxContainer, UNO_QUERY_THROW )
            ,m_nElementCount( _rxContainer->getCount() )
            ,m_nCurrentElement( 0 )
        {
        }

        bool hasMore() const
        {
            return m_nCurrentElement < m_nElementCount;
        }

        FormComponentScripts next()
        {
            FormComponentScripts aComponent(
                Reference< XInterface >( m_xContainer->getByIndex( m_nCurrentElement ), UNO_QUERY_THROW ),
                m_xEventManager,
                m_nCurrentElement
            );
            ++m_nCurrentElement;
            return aComponent;
        }

    private:
        const Reference< XIndexAccess >             m_xContainer;
        const Reference< XEventAttacherManager >    m_xEventManager;
        const sal_Int32                             m_nElementCount;
        sal_Int32                                   m_nCurrentElement;

    };

    //====================================================================
    //= ScriptsStorage - declaration
    //====================================================================
    /** a helper class which encapsulates access to the storages for Java/Script, BeanShell, and Python scripts,
        i.e. all script types which can be manipulated on storage level.
    */
    class ScriptsStorage
    {
    public:
        ScriptsStorage( MigrationLog& _rLogger );
        ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger );
        ~ScriptsStorage();

        /** determines whether the instance is valid, i.e. refers to a valid root storage
            for reading/storing scripts
        */
        inline bool isValid() const { return m_xScriptsStorage.is(); }

        /** binds the instance to a new document. Only to be called when the instance is not yet
            bound (i.e. isValid returns <FALSE/>).
        */
        void    bind( const Reference< XModel >& _rxDocument );

        /// determines whether scripts of the given type are present
        bool    hasScripts( const ScriptType _eType ) const;

        /// returns the root storage for the scripts of the given type
        SharedStorage
                getScriptsRoot( const ScriptType _eType ) const;

        /** returns the names of the elements in the "Scripts" storage
        */
        ::std::set< ::rtl::OUString >
                getElementNames() const;

        /** removes the sub storage for a given script type
            @precond
                the respective storage is empty
            @precond
                the ScriptsStorage instance was opened for writing
        */
        void    removeScriptTypeStorage( const ScriptType _eType ) const;

        /** commits the changes at our XStorage object
        */
        bool    commit();

        /** removes the "Scripts" sub storage from the given document's root storage
            @precond
                the "Scripts" storage is empty
        */
        static bool
                removeFromDocument( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger );

    private:
        MigrationLog&   m_rLogger;
        SharedStorage   m_xScriptsStorage;
    };

    //====================================================================
    //= ScriptsStorage - implementation
    //====================================================================
    //--------------------------------------------------------------------
    ScriptsStorage::ScriptsStorage( MigrationLog& _rLogger )
        :m_rLogger( _rLogger )
        ,m_xScriptsStorage()
    {
    }

    //--------------------------------------------------------------------
    ScriptsStorage::ScriptsStorage( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
        :m_rLogger( _rLogger )
        ,m_xScriptsStorage()
    {
        bind( _rxDocument );
    }

    //--------------------------------------------------------------------
    ScriptsStorage::~ScriptsStorage()
    {
    }

    //--------------------------------------------------------------------
    bool ScriptsStorage::commit()
    {
        return lcl_commitStorage_nothrow( m_xScriptsStorage );
    }

    //--------------------------------------------------------------------
    void ScriptsStorage::bind( const Reference< XModel >& _rxDocument )
    {
        OSL_PRECOND( !isValid(), "ScriptsStorage:bind: did not bother, yet, to check whether this is allowed!" );
        try
        {
            Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
            Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );

            // the the "Scripts" storage exist, or if it does not (yet) exist and we are in write mode
            // => open the storage
            if  (   (   xDocStorage->hasByName( lcl_getScriptsStorageName() )
                    &&  xDocStorage->isStorageElement( lcl_getScriptsStorageName() )
                    )
                ||  !xDocStorage->hasByName( lcl_getScriptsStorageName() )
                )
            {
                m_xScriptsStorage.set(
                    xDocStorage->openStorageElement(
                        lcl_getScriptsStorageName(), ElementModes::READWRITE
                    ),
                    UNO_QUERY_THROW
                );
            }
        }
        catch( const Exception& )
        {
            m_rLogger.logFailure( MigrationError(
                ERR_BIND_SCRIPT_STORAGE_FAILED,
                ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
                ::cppu::getCaughtException()
            ) );
        }
    }

    //--------------------------------------------------------------------
    bool ScriptsStorage::hasScripts( const ScriptType _eType ) const
    {
        OSL_PRECOND( isValid(), "ScriptsStorage::hasScripts: illegal call!" );
        if ( !isValid() )
            return false;

        const ::rtl::OUString& rSubStorageName( lcl_getScriptsSubStorageName( _eType ) );
        return  m_xScriptsStorage->hasByName( rSubStorageName )
            &&  m_xScriptsStorage->isStorageElement( rSubStorageName );
    }

    //--------------------------------------------------------------------
    SharedStorage ScriptsStorage::getScriptsRoot( const ScriptType _eType ) const
    {
        SharedStorage xStorage;
        if ( isValid() )
        {
            xStorage.reset( m_xScriptsStorage->openStorageElement(
                lcl_getScriptsSubStorageName( _eType ), ElementModes::READWRITE
            ) );
        }
        return xStorage;
    }

    //--------------------------------------------------------------------
    ::std::set< ::rtl::OUString > ScriptsStorage::getElementNames() const
    {
        Sequence< ::rtl::OUString > aElementNames;
        if ( isValid() )
            aElementNames = m_xScriptsStorage->getElementNames();

        ::std::set< ::rtl::OUString > aNames;
        ::std::copy(
            aElementNames.getConstArray(),
            aElementNames.getConstArray() + aElementNames.getLength(),
            ::std::insert_iterator< ::std::set< ::rtl::OUString > >( aNames, aNames.end() )
        );
        return aNames;
    }

    //--------------------------------------------------------------------
    void ScriptsStorage::removeScriptTypeStorage( const ScriptType _eType ) const
    {
        ::rtl::OUString sSubStorageName( lcl_getScriptsSubStorageName( _eType ) );
        if ( m_xScriptsStorage->hasByName( sSubStorageName ) )
            m_xScriptsStorage->removeElement( sSubStorageName );
    }

    //--------------------------------------------------------------------
    bool ScriptsStorage::removeFromDocument( const Reference< XModel >& _rxDocument, MigrationLog& _rLogger )
    {
        try
        {
            Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY_THROW );
            Reference< XStorage > xDocStorage( xStorageDoc->getDocumentStorage(), UNO_QUERY_THROW );
            xDocStorage->removeElement( lcl_getScriptsStorageName() );
        }
        catch( const Exception& )
        {
            _rLogger.logFailure( MigrationError(
                ERR_REMOVE_SCRIPTS_STORAGE_FAILED,
                ::comphelper::DocumentInfo::getDocumentTitle( _rxDocument ),
                ::cppu::getCaughtException()
            ) ) ;
            return false;
        }
        return true;
    }

    //====================================================================
    //= ProgressDelegator
    //====================================================================
    class ProgressDelegator : public IProgressConsumer
    {
    public:
        ProgressDelegator(  IMigrationProgress& _rDelegator,
                            const ::rtl::OUString& _rObjectName,
                            const ::rtl::OUString& _rAction
                          )
            :m_rDelegator( _rDelegator )
            ,m_sObjectName( _rObjectName )
            ,m_sAction( _rAction )
        {
        }
        virtual ~ProgressDelegator()
        {
        }

        // IProgressConsumer
        virtual void    start( sal_uInt32 _nRange )
        {
            m_rDelegator.startObject( m_sObjectName, m_sAction, _nRange );
        }
        virtual void    advance( sal_uInt32 _nValue )
        {
            m_rDelegator.setObjectProgressValue( _nValue );
        }
        virtual void    end()
        {
            m_rDelegator.endObject();
        }

    private:
        IMigrationProgress& m_rDelegator;
        ::rtl::OUString     m_sObjectName;
        ::rtl::OUString     m_sAction;
    };

    //====================================================================
    //= PhaseGuard
    //====================================================================
    class PhaseGuard
    {
    public:
        PhaseGuard( ProgressMixer& _rMixer )
            :m_rMixer( _rMixer )
        {
        }

        PhaseGuard( ProgressMixer& _rMixer, const PhaseID _nID, const sal_uInt32 _nPhaseRange )
            :m_rMixer( _rMixer )
        {
            start( _nID, _nPhaseRange );
        }

        ~PhaseGuard()
        {
            m_rMixer.endPhase();
        }

        void start( const PhaseID _nID, const sal_uInt32 _nPhaseRange )
        {
            m_rMixer.startPhase( _nID, _nPhaseRange );
        }

    private:
        ProgressMixer&  m_rMixer;
    };

    //====================================================================
    //= MigrationEngine_Impl - declaration
    //====================================================================
    class MigrationEngine_Impl
    {
    public:
        MigrationEngine_Impl(
            const ::comphelper::ComponentContext& _rContext,
            const Reference< XOfficeDatabaseDocument >& _rxDocument,
            IMigrationProgress& _rProgress,
            MigrationLog& _rLogger
        );
        ~MigrationEngine_Impl();

        inline  size_t      getFormCount() const    { return m_nFormCount; }
        inline  size_t      getReportCount()const   { return m_nReportCount; }
        bool    migrateAll();

    private:
        ::comphelper::ComponentContext              m_aContext;
        const Reference< XOfficeDatabaseDocument >  m_xDocument;
        const Reference< XModel >                   m_xDocumentModel;
        IMigrationProgress&                         m_rProgress;
        MigrationLog&                               m_rLogger;
        mutable DocumentID                          m_nCurrentDocumentID;
        SubDocuments                                m_aSubDocs;
        size_t                                      m_nFormCount;
        size_t                                      m_nReportCount;

    private:
        /** collects a description of all sub documents of our database document

            @return
                <TRUE/> if and only if collecting the documents was successful
        */
        bool    impl_collectSubDocuments_nothrow();

        /** migrates the macros/scripts of the given sub document
        */
        bool    impl_handleDocument_nothrow( const SubDocument& _rDocument ) const;

        /** checks the structure of the 'Scripts' folder of a sub document
            for unknown elements

            @return
                <TRUE/> if and only if the 'Scripts' folder contains known elements only.
        */
        bool    impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const;

        /** migrates the scripts of the given "storage-based" script type
        */
        bool    impl_migrateScriptStorage_nothrow(
                    const SubDocument& _rDocument,
                    const ScriptType _eScriptType,
                    ProgressMixer& _rProgress,
                    const PhaseID _nPhaseID
                ) const;

        /** migrates the content of the given "container based" libraries (Basic/Dialogs)
        */
        bool    impl_migrateContainerLibraries_nothrow(
                    const SubDocument& _rDocument,
                    const ScriptType _eScriptType,
                    ProgressMixer& _rProgress,
                    const PhaseID _nPhaseID
                ) const;

        /** adjusts the events for the given dialog/element, taking into account the new names
            of the moved libraries
        */
        void    impl_adjustDialogElementEvents_throw(
                    const Reference< XInterface >& _rxElement
                ) const;

        /** adjusts the events in the given dialog, and its controls, taking into account the new names
            of the moved libraries
        */
        bool    impl_adjustDialogEvents_nothrow(
                    Any& _inout_rDialogLibraryElement,
                    const ::rtl::OUString& _rDocName,
                    const ::rtl::OUString& _rDialogLibName,
                    const ::rtl::OUString& _rDialogName
                ) const;

        /** adjust the document-events which refer to macros/scripts in the document, taking into
            account the new names of the moved libraries
        */
        bool    impl_adjustDocumentEvents_nothrow(
                    const SubDocument& _rDocument
                ) const;

        /** adjusts the script references bound to form component events
        */
        bool    impl_adjustFormComponentEvents_nothrow(
                    const SubDocument& _rDocument
                ) const;

        /** adjusts the script references for the elements of the given form component container
        */
        void    impl_adjustFormComponentEvents_throw(
                    const Reference< XIndexAccess >& _rxComponentContainer
                ) const;

        /** adjusts the library name in the given script URL, so that it reflects
            the new name of the library

            @return <TRUE/>
                if and only if adjustments to the script code have been made
        */
        bool    impl_adjustScriptLibrary_nothrow(
                    const ::rtl::OUString& _rScriptType,
                    ::rtl::OUString& _inout_rScriptCode
                ) const;

        bool    impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const;
        bool    impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const;

        /** asks the user for a password for the given library, and unprotects the library

            @return <TRUE/>
                if and only if the library could be successfully unprotected
        */
        bool    impl_unprotectPasswordLibrary_throw(
                    const Reference< XLibraryContainerPassword >& _rxPasswordManager,
                    const ScriptType _eScriptType,
                    const ::rtl::OUString& _rLibraryName
                ) const;
    };

    //====================================================================
    //= MigrationEngine_Impl - implementation
    //====================================================================
    //--------------------------------------------------------------------
    MigrationEngine_Impl::MigrationEngine_Impl( const ::comphelper::ComponentContext& _rContext,
            const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress, MigrationLog& _rLogger )
        :m_aContext( _rContext )
        ,m_xDocument( _rxDocument )
        ,m_xDocumentModel( _rxDocument, UNO_QUERY_THROW )
        ,m_rProgress( _rProgress )
        ,m_rLogger( _rLogger )
        ,m_nCurrentDocumentID( - 1 )
        ,m_aSubDocs()
        ,m_nFormCount( 0 )
        ,m_nReportCount( 0 )
    {
        OSL_VERIFY( impl_collectSubDocuments_nothrow() );
    }

    //--------------------------------------------------------------------
    MigrationEngine_Impl::~MigrationEngine_Impl()
    {
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::migrateAll()
    {
        if  ( m_aSubDocs.empty() )
        {
            OSL_ENSURE( false, "MigrationEngine_Impl::migrateAll: no forms/reports found!" );
            // The whole migration wizard is not expected to be called when there are no forms/reports
            // with macros, not to mention when there are no forms/reports at all.
            return false;
        }

        // initialize global progress
        sal_Int32 nOverallRange( m_aSubDocs.size() );
        String sProgressSkeleton = String( MacroMigrationResId( STR_OVERALL_PROGRESS ) );
        sProgressSkeleton.SearchAndReplaceAscii( "$overall$", String::CreateFromInt32( nOverallRange ) );

        m_rProgress.start( nOverallRange );

        for (   SubDocuments::const_iterator doc = m_aSubDocs.begin();
                doc != m_aSubDocs.end();
                ++doc
            )
        {
            sal_Int32 nOverallProgressValue( doc - m_aSubDocs.begin() + 1 );
            // update overall progress text
            ::rtl::OUString sOverallProgress( sProgressSkeleton );
            ::comphelper::string::searchAndReplaceAsciiI( sOverallProgress, "$current$", ::rtl::OUString::valueOf( nOverallProgressValue ) );
            m_rProgress.setOverallProgressText( sOverallProgress );

            // migrate document
            if ( !impl_handleDocument_nothrow( *doc ) )
                return false;

            // update overall progress vallue
            m_rProgress.setOverallProgressValue( nOverallProgressValue );
        }

        // commit the root storage of the database document, for all changes made so far to take effect
        if ( !lcl_commitDocumentStorage_nothrow( m_xDocumentModel, m_rLogger ) )
            return false;

        // save the document
        if ( !lcl_storeDocument_nothrow( m_xDocumentModel, m_rLogger ) )
            return false;

        return true;
    }

    //--------------------------------------------------------------------
    namespace
    {
        void lcl_collectHierarchicalElementNames_throw(
            const Reference< XNameAccess >& _rxContainer, const ::rtl::OUString& _rContainerLoc,
            SubDocuments& _out_rDocs, const SubDocumentType _eType, size_t& _io_counter )
        {
            const ::rtl::OUString sHierarhicalBase(
                _rContainerLoc.getLength()  ?   ::rtl::OUStringBuffer( _rContainerLoc ).appendAscii( "/" ).makeStringAndClear()
                                            :   ::rtl::OUString() );

            Sequence< ::rtl::OUString > aElementNames( _rxContainer->getElementNames() );
            for (   const ::rtl::OUString* elementName = aElementNames.getConstArray();
                    elementName != aElementNames.getConstArray() + aElementNames.getLength();
                    ++elementName
                )
            {
                Any aElement( _rxContainer->getByName( *elementName ) );
                ::rtl::OUString sElementName( ::rtl::OUStringBuffer( sHierarhicalBase ).append( *elementName ) );

                Reference< XNameAccess > xSubContainer( aElement, UNO_QUERY );
                if ( xSubContainer.is() )
                {
                    lcl_collectHierarchicalElementNames_throw( xSubContainer, sElementName, _out_rDocs, _eType, _io_counter );
                }
                else
                {
                    Reference< XCommandProcessor > xCommandProcessor( aElement, UNO_QUERY );
                    OSL_ENSURE( xCommandProcessor.is(), "lcl_collectHierarchicalElementNames_throw: no container, and no comand processor? What *is* it, then?!" );
                    if ( xCommandProcessor.is() )
                    {
                        _out_rDocs.push_back( SubDocument( xCommandProcessor, sElementName, _eType, ++_io_counter ) );
                    }
                }
            }
        }
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_collectSubDocuments_nothrow()
    {
        OSL_PRECOND( m_xDocument.is(), "MigrationEngine_Impl::impl_collectSubDocuments_nothrow: invalid document!" );
        if ( !m_xDocument.is() )
            return false;

        try
        {
            Reference< XNameAccess > xDocContainer( m_xDocument->getFormDocuments(), UNO_SET_THROW );
            m_nFormCount = 0;
            lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eForm, m_nFormCount );

            xDocContainer.set( m_xDocument->getReportDocuments(), UNO_SET_THROW );
            m_nReportCount = 0;
            lcl_collectHierarchicalElementNames_throw( xDocContainer, ::rtl::OUString(), m_aSubDocs, eReport, m_nReportCount );
        }
        catch( const Exception& )
        {
            m_rLogger.logFailure( MigrationError(
                ERR_COLLECTING_DOCUMENTS_FAILED,
                ::cppu::getCaughtException()
            ) );
            return false;
        }
        return true;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_handleDocument_nothrow( const SubDocument& _rDocument ) const
    {
        OSL_ENSURE( m_nCurrentDocumentID == -1,
            "MigrationEngine_Impl::impl_handleDocument_nothrow: there already is a current document!");
        m_nCurrentDocumentID = m_rLogger.startedDocument( _rDocument.eType, _rDocument.sHierarchicalName );

        // start the progress
        ::rtl::OUString sObjectName( lcl_getSubDocumentDescription( _rDocument ) );
        m_rProgress.startObject( sObjectName, ::rtl::OUString(), DEFAULT_DOC_PROGRESS_RANGE );

        // -----------------
        // load the document
        ::rtl::Reference< ProgressCapture > pStatusIndicator( new ProgressCapture( sObjectName, m_rProgress ) );
        SubDocument aSubDocument( _rDocument );
        OpenDocResult eResult = lcl_loadSubDocument_nothrow( aSubDocument, pStatusIndicator.get(), m_rLogger );
        if ( eResult != eOpenedDoc )
        {
            pStatusIndicator->dispose();
            m_rProgress.endObject();
            m_rLogger.finishedDocument( m_nCurrentDocumentID );
            m_nCurrentDocumentID = -1;
            return ( eResult == eIgnoreDoc );
        }

        // -----------------
        // migrate the libraries
        ProgressDelegator aDelegator( m_rProgress, sObjectName, String( MacroMigrationResId( STR_MIGRATING_LIBS ) ) );
        ProgressMixer aProgressMixer( aDelegator );
        aProgressMixer.registerPhase( PHASE_JAVASCRIPT, 1 );
        aProgressMixer.registerPhase( PHASE_BEANSHELL, 1 );
        aProgressMixer.registerPhase( PHASE_PYTHON, 1 );
        aProgressMixer.registerPhase( PHASE_JAVA, 1 );
        aProgressMixer.registerPhase( PHASE_BASIC, 5 );
            // more weight than then others, assuming that usually, there are much more Basic macros than any other scripts
        aProgressMixer.registerPhase( PHASE_DIALOGS, 1 );

        bool bSuccess = impl_checkScriptStorageStructure_nothrow( aSubDocument );

        // migrate storage-based script libraries (which can be handled by mere storage operations)
        bSuccess = bSuccess
            &&  impl_migrateScriptStorage_nothrow( aSubDocument, eJavaScript, aProgressMixer, PHASE_JAVASCRIPT )
            &&  impl_migrateScriptStorage_nothrow( aSubDocument, eBeanShell, aProgressMixer, PHASE_BEANSHELL )
            &&  impl_migrateScriptStorage_nothrow( aSubDocument, ePython, aProgressMixer, PHASE_PYTHON )
            &&  impl_migrateScriptStorage_nothrow( aSubDocument, eJava, aProgressMixer, PHASE_JAVA );

        // migrate Basic and dialog libraries
        bSuccess =  bSuccess
                &&  impl_migrateContainerLibraries_nothrow( aSubDocument, eBasic, aProgressMixer, PHASE_BASIC )
                &&  impl_migrateContainerLibraries_nothrow( aSubDocument, eDialog, aProgressMixer, PHASE_DIALOGS );
                // order matters: First Basic scripts, then dialogs. So we can adjust references from the latter
                // to the former

        // adjust the events in the document
        // (note that errors are ignored here - failure to convert a script reference
        // is not considered a critical error)
        if ( bSuccess )
        {
            impl_adjustDocumentEvents_nothrow( aSubDocument );
            impl_adjustFormComponentEvents_nothrow( aSubDocument );
        }

        // -----------------
        // clean up
        // store the sub document, including removal of the (now obsolete) "Scripts" sub folder
        if ( m_rLogger.movedAnyLibrary( m_nCurrentDocumentID ) )
        {
            bSuccess =  bSuccess
                    &&  ScriptsStorage::removeFromDocument( aSubDocument.xDocument, m_rLogger )
                    &&  lcl_commitDocumentStorage_nothrow( aSubDocument.xDocument, m_rLogger )
                    &&  lcl_storeEmbeddedDocument_nothrow( aSubDocument );
        }

        // unload in any case, even if we were not successful
        bSuccess =  lcl_unloadSubDocument_nothrow( aSubDocument, m_rLogger )
                &&  bSuccess;

        pStatusIndicator->dispose();

        // end the progress, just in case the ProgressCapture didn't receive the XStatusIndicator::end event
        m_rProgress.endObject();

        m_rLogger.finishedDocument( m_nCurrentDocumentID );
        m_nCurrentDocumentID = -1;
        return bSuccess;
    }

    //--------------------------------------------------------------------
    namespace
    {
        static ::rtl::OUString lcl_createTargetLibName( const SubDocument& _rDocument,
            const ::rtl::OUString& _rSourceLibName, const Reference< XNameAccess >& _rxTargetContainer )
        {
            // The new library name is composed from the prefix, the base name, and the old library name.
            const ::rtl::OUString sPrefix( ::rtl::OUString::createFromAscii( _rDocument.eType == eForm ? "Form_" : "Report_" ) );

            ::rtl::OUString sBaseName( _rDocument.sHierarchicalName.copy(
                _rDocument.sHierarchicalName.lastIndexOf( '/' ) + 1 ) );
            // Normalize this name. In our current storage implementation (and script containers in a document
            // are finally mapped to sub storages of the document storage), not all characters are allowed.
            // The bug requesting to change this is #i95409#.
            // Unfortunately, the storage implementation does not complain if you use invalid characters/names, but instead
            // it silently accepts them, and produces garbage in the file (#i95408).
            // So, until especially the former is fixed, we need to strip the name from all invalid characters.
            // #i95865# / 2008-11-06 / frank.schoenheit@sun.com

            // The general idea is to replace invalid characters with '_'. However, since "valid" essentially means
            // ASCII only, this implies that for a lot of languages, we would simply replace everything with '_',
            // which of course is not desired.
            // So, we use a heuristics: If the name contains at most 3 invalid characters, and as many valid as invalid
            // characters, then we use the replacement. Otherwise, we just use a unambiguous number for the sub document.
            sal_Int32 nValid=0, nInvalid=0;
            const sal_Unicode* pBaseName = sBaseName.getStr();
            const sal_Int32 nBaseNameLen = sBaseName.getLength();
            for ( sal_Int32 i=0; i<nBaseNameLen; ++i )
            {
                if ( ::comphelper::OStorageHelper::IsValidZipEntryFileName( pBaseName + i, 1, sal_False ) )
                    ++nValid;
                else
                    ++nInvalid;
            }
            if ( ( nInvalid <= 3 ) && ( nInvalid * 2 <= nValid ) )
            {   // not "too many" invalid => replace them
                ::rtl::OUStringBuffer aReplacement;
                aReplacement.ensureCapacity( nBaseNameLen );
                aReplacement.append( sBaseName );
                const sal_Unicode* pReplacement = aReplacement.getStr();
                for ( sal_Int32 i=0; i<nBaseNameLen; ++i )
                {
                    if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( pReplacement + i, 1, sal_False ) )
                        aReplacement.setCharAt( i, '_' );
                }
                sBaseName = aReplacement.makeStringAndClear();

                ::rtl::OUStringBuffer aNewLibNameAttempt;
                aNewLibNameAttempt.append( sPrefix );
                aNewLibNameAttempt.append( sBaseName );
                aNewLibNameAttempt.appendAscii( "_" );
                aNewLibNameAttempt.append( _rSourceLibName );
                ::rtl::OUString sTargetName( aNewLibNameAttempt.makeStringAndClear() );
                if ( !_rxTargetContainer->hasByName( sTargetName ) )
                    return sTargetName;
            }

            // "too many" invalid characters, or the name composed with the base name was already used.
            // (The latter is valid, since there can be multiple sub documents with the same base name,
            // in different levels in the hierarchy.)
            // In this case, just use the umambiguous sub document number.
            ::rtl::OUStringBuffer aNewLibName;
            aNewLibName.append( sPrefix );
            aNewLibName.append( ::rtl::OUString::valueOf( sal_Int64( _rDocument.nNumber ) ) );
            aNewLibName.appendAscii( "_" );
            aNewLibName.append( _rSourceLibName );
            return aNewLibName.makeStringAndClear();
        }
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow( const SubDocument& _rDocument ) const
    {
        OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_checkScriptStorageStructure_nothrow: invalid document!" );
        if ( !_rDocument.xDocument.is() )
            return false;

        try
        {
            // the root storage of the document whose scripts are to be migrated
            ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger );
            if  ( !aDocStorage.isValid() )
            {   // no scripts at all, or no scripts of the given type
                return !m_rLogger.hadFailure();
            }
            ::std::set< ::rtl::OUString > aElementNames( aDocStorage.getElementNames() );

            ScriptType aKnownStorageBasedTypes[] = {
                eBeanShell, eJavaScript, ePython, eJava
            };
            for ( size_t i=0; i< SAL_N_ELEMENTS( aKnownStorageBasedTypes ); ++i )
                aElementNames.erase( lcl_getScriptsSubStorageName( aKnownStorageBasedTypes[i] ) );

            if ( !aElementNames.empty() )
            {
                m_rLogger.logFailure( MigrationError(
                    ERR_UNKNOWN_SCRIPT_FOLDER,
                    lcl_getSubDocumentDescription( _rDocument ),
                    *aElementNames.begin()
                ) );
                return false;
            }
        }
        catch( const Exception& )
        {
            m_rLogger.logFailure( MigrationError(
                ERR_EXAMINING_SCRIPTS_FOLDER_FAILED,
                lcl_getSubDocumentDescription( _rDocument ),
                ::cppu::getCaughtException()
            ) );
            return false;
        }
        return true;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_migrateScriptStorage_nothrow( const SubDocument& _rDocument,
        const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const
    {
        OSL_PRECOND( _rDocument.xDocument.is(), "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: invalid document!" );
        if ( !_rDocument.xDocument.is() )
            return false;

        ScriptsStorage aDatabaseScripts( m_rLogger );
            // the scripts of our complete database document - created on demand only
        SharedStorage xTargetStorage;
            // the target for moving the scripts storages - created on demand only

        PhaseGuard aPhase( _rProgress );
        bool bSuccess = false;
        Any aException;
        try
        {
            // the root storage of the document whose scripts are to be migrated
            ScriptsStorage aDocStorage( _rDocument.xDocument, m_rLogger );
            if  (   !aDocStorage.isValid()
                ||  !aDocStorage.hasScripts( _eScriptType )
                )
            {
                // no scripts at all, or no scripts of the given type
                _rProgress.startPhase( _nPhaseID, 1 );
                _rProgress.endPhase();
                return !m_rLogger.hadFailure();
            }

            SharedStorage xScriptsRoot( aDocStorage.getScriptsRoot( _eScriptType ) );
            if ( !xScriptsRoot.is() )
                throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "internal error" ) ), NULL );

            // loop through the script libraries
            Sequence< ::rtl::OUString > aStorageElements( xScriptsRoot->getElementNames() );
            aPhase.start( _nPhaseID, aStorageElements.getLength() );

            for (   const ::rtl::OUString* element = aStorageElements.getConstArray();
                    element != aStorageElements.getConstArray() + aStorageElements.getLength();
                    ++element
                )
            {
                bool bIsScriptLibrary = xScriptsRoot->isStorageElement( *element );
                OSL_ENSURE( bIsScriptLibrary,
                    "MigrationEngine_Impl::impl_migrateScriptStorage_nothrow: warning: unknown scripts storage structure!" );
                    // we cannot handle this. We would need to copy this stream to the respective scripts storage
                    // of the database document, but we cannot guarantee that the name is not used, yet, and we cannot
                    // simply rename the thing.
                if ( !bIsScriptLibrary )
                {
                    m_rLogger.logFailure( MigrationError(
                        ERR_UNEXPECTED_LIBSTORAGE_ELEMENT,
                        lcl_getSubDocumentDescription( _rDocument ),
                        getScriptTypeDisplayName( _eScriptType ),
                        *element
                    ) );
                    return false;
                }

                // ensure we have access to the DBDoc's scripts storage
                if ( !aDatabaseScripts.isValid() )
                {   // not needed 'til now
                    aDatabaseScripts.bind( m_xDocumentModel );
                    if ( aDatabaseScripts.isValid() )
                        xTargetStorage = aDatabaseScripts.getScriptsRoot( _eScriptType );

                    if ( !xTargetStorage.is() )
                    {
                        m_rLogger.logFailure( MigrationError(
                            ERR_CREATING_DBDOC_SCRIPT_STORAGE_FAILED,
                            getScriptTypeDisplayName( _eScriptType )
                        ) );
                        return false;
                    }
                }

                // move the library to the DBDoc's scripts library, under the new name
                ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *element, xTargetStorage.getTyped().get() ) );
                xScriptsRoot->moveElementTo( *element, xTargetStorage, sNewLibName );

                // log the fact that we moved the library
                m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *element, sNewLibName );

                // progress
                _rProgress.advancePhase( element - aStorageElements.getConstArray() );
            }

            // commit the storages, so the changes we made persist
            if  (   !lcl_commitStorage_nothrow( xScriptsRoot )
                ||  ( xTargetStorage.is() && !lcl_commitStorage_nothrow( xTargetStorage ) )
                )
            {
                m_rLogger.logFailure( MigrationError(
                    ERR_COMMITTING_SCRIPT_STORAGES_FAILED,
                    getScriptTypeDisplayName( _eScriptType ),
                    lcl_getSubDocumentDescription( _rDocument )
                ) );
                return false;
            }

            // now that the concrete scripts storage does not have any elements anymore,
            // remove it
            xScriptsRoot.reset( NULL ); // need to reset the storage to be allowed to remove it
            aDocStorage.removeScriptTypeStorage( _eScriptType );

            // done so far
            bSuccess =  aDocStorage.commit()
                    &&  aDatabaseScripts.commit();
        }
        catch( const Exception& )
        {
            aException = ::cppu::getCaughtException();
            bSuccess = false;
        }

        // log the error, if any
        if ( !bSuccess )
        {
            m_rLogger.logFailure( MigrationError(
                ERR_GENERAL_SCRIPT_MIGRATION_FAILURE,
                getScriptTypeDisplayName( _eScriptType ),
                lcl_getSubDocumentDescription( _rDocument ),
                aException
            ) );
        }

        return bSuccess;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow( const SubDocument& _rDocument,
            const ScriptType _eScriptType, ProgressMixer& _rProgress, const PhaseID _nPhaseID ) const
    {
        OSL_PRECOND( ( _eScriptType == eBasic ) || ( _eScriptType == eDialog ),
            "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: illegal script type!" );

        bool bSuccess = false;
        PhaseGuard aPhase( _rProgress );
        Any aException;
        do  // artificial loop for flow control only
        {
        try
        {
            // access library container of the sub document
            Reference< XEmbeddedScripts > xSubDocScripts( _rDocument.xDocument, UNO_QUERY );
            if ( !xSubDocScripts.is() )
            {   // no script support in the sub document -> nothing to migrate
                // (though ... this is suspicious, at least ...)
                bSuccess = true;
                break;
            }

            Reference< XStorageBasedLibraryContainer > xSourceLibraries(
                _eScriptType == eBasic ? xSubDocScripts->getBasicLibraries() : xSubDocScripts->getDialogLibraries(),
                UNO_QUERY_THROW
            );
            Reference< XLibraryContainerPassword > xSourcePasswords( xSourceLibraries, UNO_QUERY );
            OSL_ENSURE( xSourcePasswords.is(),
                "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: suspicious: no password management for the source libraries!" );

            Sequence< ::rtl::OUString > aSourceLibNames( xSourceLibraries->getElementNames() );
            aPhase.start( _nPhaseID, aSourceLibNames.getLength() );

            if ( !xSourceLibraries->hasElements() )
            {
                bSuccess = true;
                break;
            }

            // create library containers for the document - those will be the target for the migration
            Reference< XStorageBasedDocument > xStorageDoc( m_xDocument, UNO_QUERY_THROW );
            Reference< XStorageBasedLibraryContainer > xTargetLibraries;
            if ( _eScriptType == eBasic )
            {
                xTargetLibraries.set( DocumentScriptLibraryContainer::create(
                    m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW );
            }
            else
            {
                xTargetLibraries.set( DocumentDialogLibraryContainer::create(
                    m_aContext.getUNOContext(), xStorageDoc ), UNO_QUERY_THROW );
            }

            // copy all libs to the target, with potentially renaming them
            const ::rtl::OUString* pSourceLibBegin = aSourceLibNames.getConstArray();
            const ::rtl::OUString* pSourceLibEnd = pSourceLibBegin + aSourceLibNames.getLength();
            for (   const ::rtl::OUString* pSourceLibName = pSourceLibBegin;
                    pSourceLibName != pSourceLibEnd;
                    ++pSourceLibName
                )
            {
                // if the library is password-protected, ask the user to unprotect it
                if  (   xSourcePasswords.is()
                    &&  xSourcePasswords->isLibraryPasswordProtected( *pSourceLibName )
                    &&  !xSourcePasswords->isLibraryPasswordVerified( *pSourceLibName )
                    )
                {
                    if ( !impl_unprotectPasswordLibrary_throw( xSourcePasswords, _eScriptType, *pSourceLibName ) )
                    {
                        m_rLogger.logFailure( MigrationError(
                            ERR_PASSWORD_VERIFICATION_FAILED,
                            _rDocument.sHierarchicalName,
                            getScriptTypeDisplayName( _eScriptType ),
                            *pSourceLibName
                        ) );
                        return false;
                    }
                }

                ::rtl::OUString sNewLibName( lcl_createTargetLibName( _rDocument, *pSourceLibName, xTargetLibraries.get() ) );

                if ( xSourceLibraries->isLibraryLink( *pSourceLibName ) )
                {
                    // just re-create the link in the target library
                    xTargetLibraries->createLibraryLink(
                        sNewLibName,
                        xSourceLibraries->getLibraryLinkURL( *pSourceLibName ),
                        xSourceLibraries->isLibraryReadOnly( *pSourceLibName )
                    );
                }
                else
                {
                    if ( !xSourceLibraries->isLibraryLoaded( *pSourceLibName ) )
                        xSourceLibraries->loadLibrary( *pSourceLibName );

                    // copy the content of this particular libary
                    Reference< XNameAccess > xSourceLib( xSourceLibraries->getByName( *pSourceLibName ), UNO_QUERY_THROW );
                    Reference< XNameContainer > xTargetLib( xTargetLibraries->createLibrary( sNewLibName ), UNO_QUERY_THROW );

                    Sequence< ::rtl::OUString > aLibElementNames( xSourceLib->getElementNames() );
                    for (   const ::rtl::OUString* pSourceElementName = aLibElementNames.getConstArray();
                            pSourceElementName != aLibElementNames.getConstArray() + aLibElementNames.getLength();
                            ++pSourceElementName
                        )
                    {
                        Any aElement = xSourceLib->getByName( *pSourceElementName );
                        OSL_ENSURE( aElement.hasValue(),
                            "MigrationEngine_Impl::impl_migrateContainerLibraries_nothrow: invalid (empty) lib element!" );

                        // if this is a dialog, adjust the references to scripts
                        if ( _eScriptType == eDialog )
                        {
                            impl_adjustDialogEvents_nothrow( aElement, lcl_getSubDocumentDescription( _rDocument ),
                                *pSourceLibName, *pSourceElementName );
                        }

                        xTargetLib->insertByName( *pSourceElementName, aElement );
                    }

                    // transfer the read-only flag
                    xTargetLibraries->setLibraryReadOnly(
                        sNewLibName, xSourceLibraries->isLibraryReadOnly( *pSourceLibName ) );
                }

                // remove the source lib
                xSourceLibraries->removeLibrary( *pSourceLibName );

                // tell the logger
                m_rLogger.movedLibrary( m_nCurrentDocumentID, _eScriptType, *pSourceLibName, sNewLibName );

                // tell the progress
                _rProgress.advancePhase( pSourceLibName - pSourceLibBegin );
            }

            // clean up
            xSourceLibraries->storeLibraries();

            xTargetLibraries->storeLibraries();
            Reference< XStorage > xTargetRoot( xTargetLibraries->getRootLocation(), UNO_QUERY_THROW );
            bSuccess = lcl_commitStorage_nothrow( xTargetRoot );
        }
        catch( const Exception& )
        {
            aException = ::cppu::getCaughtException();
            bSuccess = false;
        }
        } while ( false );

        // log the error, if any
        if ( !bSuccess )
        {
            m_rLogger.logFailure( MigrationError(
                ERR_GENERAL_MACRO_MIGRATION_FAILURE,
                lcl_getSubDocumentDescription( _rDocument ),
                aException
            ) );
        }

        return bSuccess;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( const ::rtl::OUString& _rScriptType,
            ::rtl::OUString& _inout_rScriptCode ) const
    {
        OSL_PRECOND( _inout_rScriptCode.getLength(), "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid script!" );
        if ( !_inout_rScriptCode.getLength() )
            return false;

        bool bSuccess = false;
        Any aException;
        try
        {
            if  (   !_rScriptType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Script" ) )
                ||  !_rScriptType.getLength()
                )
            {
                OSL_ENSURE( false,
                    "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: no or unknown script type!" );
                m_rLogger.logRecoverable( MigrationError(
                    ERR_UNKNOWN_SCRIPT_TYPE,
                    _rScriptType
                ) );
                return false;
            }

            // analyze the script URI
            Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_aContext.getUNOContext() );
            Reference< XVndSunStarScriptUrlReference > xUri( xUriRefFac->parse( _inout_rScriptCode ), UNO_QUERY_THROW );

            ::rtl::OUString sScriptLanguage = xUri->getParameter(
                ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "language" ) ) );
            ScriptType eScriptType = eBasic;
            if ( !lcl_getScriptTypeFromLanguage( sScriptLanguage, eScriptType ) )
            {
                OSL_ENSURE( false,
                    "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: unknown script language!" );
                m_rLogger.logRecoverable( MigrationError(
                    ERR_UNKNOWN_SCRIPT_LANGUAGE,
                    sScriptLanguage
                ) );
                return false;
            }

            ::rtl::OUString sLocation = xUri->getParameter(
                ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "location" ) ) );
            if ( !sLocation.equalsAscii( "document" ) )
            {
                // only document libraries must be migrated, of course
                return false;
            }

            ::rtl::OUString sScriptName = xUri->getName();
            sal_Int32 nLibModuleSeparator = sScriptName.indexOf( '.' );
            if ( nLibModuleSeparator < 0 )
            {
                OSL_ENSURE( false,
                    "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: invalid/unknown location format!" );
                m_rLogger.logRecoverable( MigrationError(
                    ERR_UNKNOWN_SCRIPT_NAME_FORMAT,
                    sScriptName
                ) );
                return false;
            }

            // replace the library name
            ::rtl::OUString sLibrary = sScriptName.copy( 0, nLibModuleSeparator );
            ::rtl::OUString sNewLibName = m_rLogger.getNewLibraryName(
                m_nCurrentDocumentID, eScriptType, sLibrary );
            OSL_ENSURE( sLibrary != sNewLibName,
                "MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow: a library which has not been migrated?" );

            ::rtl::OUStringBuffer aNewLocation;
            aNewLocation.append( sNewLibName );
            aNewLocation.append( sScriptName.copy( nLibModuleSeparator ) );
            xUri->setName( aNewLocation.makeStringAndClear() );

            // update the new script URL
            _inout_rScriptCode = xUri->getUriReference();
            bSuccess = true;
        }
        catch( const Exception& )
        {
            aException = ::cppu::getCaughtException();
            bSuccess = false;
        }

        // log the failure, if any
        if ( !bSuccess )
        {
            m_rLogger.logRecoverable( MigrationError(
                ERR_SCRIPT_TRANSLATION_FAILURE,
                _rScriptType,
                _inout_rScriptCode,
                aException
            ) );
        }

        return bSuccess;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( ScriptEventDescriptor& _inout_rScriptEvent ) const
    {
        if ( _inout_rScriptEvent.ScriptType.getLength() && _inout_rScriptEvent.ScriptCode.getLength() )
            return impl_adjustScriptLibrary_nothrow( _inout_rScriptEvent.ScriptType, _inout_rScriptEvent.ScriptCode );
        return false;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustScriptLibrary_nothrow( Any& _inout_rScriptDescriptor ) const
    {
        ::comphelper::NamedValueCollection aScriptDesc( _inout_rScriptDescriptor );

        ::rtl::OUString sScriptType;
        ::rtl::OUString sScript;
        try
        {
            OSL_VERIFY( aScriptDesc.get_ensureType( "EventType", sScriptType ) );
            OSL_VERIFY( aScriptDesc.get_ensureType( "Script", sScript ) );
        }
        catch( const Exception& )
        {
            m_rLogger.logRecoverable( MigrationError(
                ERR_INVALID_SCRIPT_DESCRIPTOR_FORMAT,
                ::cppu::getCaughtException()
            ) );
        }

        if ( sScriptType.getLength() && sScript.getLength() )
            if ( !impl_adjustScriptLibrary_nothrow( sScriptType, sScript ) )
                return false;

        aScriptDesc.put( "Script", sScript );
        _inout_rScriptDescriptor <<= aScriptDesc.getPropertyValues();
        return true;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustDocumentEvents_nothrow( const SubDocument& _rDocument ) const
    {
        try
        {
            Reference< XEventsSupplier > xSuppEvents( _rDocument.xDocument, UNO_QUERY );
            if ( !xSuppEvents.is() )
                // this is allowed. E.g. new-style reports currently do not support this
                return true;

            Reference< XNameReplace > xEvents( xSuppEvents->getEvents(), UNO_SET_THROW );
            Sequence< ::rtl::OUString > aEventNames = xEvents->getElementNames();

            Any aEvent;
            for (   const ::rtl::OUString* eventName = aEventNames.getConstArray();
                    eventName != aEventNames.getConstArray() + aEventNames.getLength();
                    ++eventName
                )
            {
                aEvent = xEvents->getByName( *eventName );
                if ( !aEvent.hasValue() )
                    continue;

                // translate
                if ( !impl_adjustScriptLibrary_nothrow( aEvent ) )
                    continue;

                // put back
                xEvents->replaceByName( *eventName, aEvent );
            }
        }
        catch( const Exception& )
        {
            m_rLogger.logRecoverable( MigrationError(
                ERR_ADJUSTING_DOCUMENT_EVENTS_FAILED,
                lcl_getSubDocumentDescription( _rDocument ),
                ::cppu::getCaughtException()
            ) );
            return false;
        }
        return true;
    }

    //--------------------------------------------------------------------
    void MigrationEngine_Impl::impl_adjustDialogElementEvents_throw( const Reference< XInterface >& _rxElement ) const
    {
        Reference< XScriptEventsSupplier > xEventsSupplier( _rxElement, UNO_QUERY_THROW );
        Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_QUERY_THROW );
        Sequence< ::rtl::OUString > aEventNames( xEvents->getElementNames() );

        const ::rtl::OUString* eventName = aEventNames.getArray();
        const ::rtl::OUString* eventNamesEnd = eventName + aEventNames.getLength();

        ScriptEventDescriptor aScriptEvent;
        for ( ; eventName != eventNamesEnd; ++eventName )
        {
            OSL_VERIFY( xEvents->getByName( *eventName ) >>= aScriptEvent );

            if ( !impl_adjustScriptLibrary_nothrow( aScriptEvent ) )
                continue;

            xEvents->replaceByName( *eventName, makeAny( aScriptEvent ) );
        }
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustDialogEvents_nothrow( Any& _inout_rDialogLibraryElement,
        const ::rtl::OUString& _rDocName, const ::rtl::OUString& _rDialogLibName, const ::rtl::OUString& _rDialogName ) const
    {
        try
        {
            // load a dialog model from the stream describing it
            Reference< XInputStreamProvider > xISP( _inout_rDialogLibraryElement, UNO_QUERY_THROW );
            Reference< XInputStream > xInput( xISP->createInputStream(), UNO_QUERY_THROW );

            Reference< XNameContainer > xDialogModel( m_aContext.createComponent( "com.sun.star.awt.UnoControlDialogModel" ), UNO_QUERY_THROW );
            ::xmlscript::importDialogModel( xInput, xDialogModel, m_aContext.getUNOContext(), m_xDocumentModel );

            // adjust the events of the dialog
            impl_adjustDialogElementEvents_throw( xDialogModel );

            // adjust the events of the controls
            Sequence< ::rtl::OUString > aControlNames( xDialogModel->getElementNames() );
            const ::rtl::OUString* controlName = aControlNames.getConstArray();
            const ::rtl::OUString* controlNamesEnd = controlName + aControlNames.getLength();
            for ( ; controlName != controlNamesEnd; ++controlName )
            {
                impl_adjustDialogElementEvents_throw( Reference< XInterface >( xDialogModel->getByName( *controlName ), UNO_QUERY ) );
            }

            // export dialog model
            xISP = ::xmlscript::exportDialogModel( xDialogModel, m_aContext.getUNOContext(), m_xDocumentModel );
            _inout_rDialogLibraryElement <<= xISP;
        }
        catch( const Exception& )
        {
            m_rLogger.logRecoverable( MigrationError(
                ERR_ADJUSTING_DIALOG_EVENTS_FAILED,
                _rDocName,
                _rDialogLibName,
                _rDialogName,
                ::cppu::getCaughtException()
            ) );
            return false;
        }
        return true;
    }

    //--------------------------------------------------------------------
    void MigrationEngine_Impl::impl_adjustFormComponentEvents_throw( const Reference< XIndexAccess >& _rxComponentContainer ) const
    {
        FormComponentIterator aCompIter( _rxComponentContainer );
        while ( aCompIter.hasMore() )
        {
            // 1. adjust the component's scripts of the current component
            FormComponentScripts aComponent( aCompIter.next() );
            Sequence< ScriptEventDescriptor > aEvents( aComponent.getEvents() );

            bool bChangedComponentEvents = false;
            for (   ScriptEventDescriptor* scriptEvent = aEvents.getArray();
                    scriptEvent != aEvents.getArray() + aEvents.getLength();
                    ++scriptEvent
                )
            {
                if ( !impl_adjustScriptLibrary_nothrow( *scriptEvent ) )
                    continue;

                bChangedComponentEvents = true;
            }

            if ( bChangedComponentEvents )
                aComponent.setEvents( aEvents );

            // 2. step down if the component is a container itself
            Reference< XIndexAccess > xContainer( aComponent.getComponent(), UNO_QUERY );
            if ( xContainer.is() )
                impl_adjustFormComponentEvents_throw( xContainer );
        }
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_adjustFormComponentEvents_nothrow( const SubDocument& _rDocument ) const
    {
        try
        {
            DrawPageIterator aPageIter( _rDocument.xDocument );
            while ( aPageIter.hasMore() )
            {
                Reference< XFormsSupplier > xSuppForms( aPageIter.next(), UNO_QUERY_THROW );
                Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW );
                impl_adjustFormComponentEvents_throw( xForms );
            }
        }
        catch( const Exception& )
        {
            m_rLogger.logRecoverable( MigrationError(
                ERR_ADJUSTING_FORMCOMP_EVENTS_FAILED,
                lcl_getSubDocumentDescription( _rDocument ),
                ::cppu::getCaughtException()
            ) );
            return false;
        }
        return true;
    }

    //--------------------------------------------------------------------
    bool MigrationEngine_Impl::impl_unprotectPasswordLibrary_throw( const Reference< XLibraryContainerPassword >& _rxPasswordManager,
            const ScriptType _eScriptType, const ::rtl::OUString& _rLibraryName ) const
    {
        // a human-readable description of the affected library
        ::rtl::OUString sLibraryDescription( String(
            MacroMigrationResId( STR_LIBRARY_TYPE_AND_NAME ) ) );
        ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$type$",
            getScriptTypeDisplayName( _eScriptType ) );
        ::comphelper::string::searchAndReplaceAsciiI( sLibraryDescription, "$library$",
            _rLibraryName );

        InteractionHandler aHandler( m_aContext, m_xDocumentModel );
        ::rtl::OUString sPassword;
        while ( true )
        {
            if ( !aHandler.requestDocumentPassword( sLibraryDescription, sPassword ) )
                // aborted by the user
                return false;

            bool bSuccessVerification = _rxPasswordManager->verifyLibraryPassword( _rLibraryName, sPassword );
            if ( bSuccessVerification )
                return true;
        }

    }

    //====================================================================
    //= MigrationEngine
    //====================================================================
    //--------------------------------------------------------------------
    MigrationEngine::MigrationEngine( const ::comphelper::ComponentContext& _rContext,
            const Reference< XOfficeDatabaseDocument >& _rxDocument, IMigrationProgress& _rProgress,
            MigrationLog& _rLogger )
        :m_pImpl( new MigrationEngine_Impl( _rContext, _rxDocument, _rProgress, _rLogger ) )
    {
    }

    //--------------------------------------------------------------------
    MigrationEngine::~MigrationEngine()
    {
    }

    //--------------------------------------------------------------------
    sal_Int32 MigrationEngine::getFormCount() const
    {
        return m_pImpl->getFormCount();
    }

    //--------------------------------------------------------------------
    sal_Int32 MigrationEngine::getReportCount() const
    {
        return m_pImpl->getReportCount();
    }

    //--------------------------------------------------------------------
    bool MigrationEngine::migrateAll()
    {
        return m_pImpl->migrateAll();
    }

//........................................................................
} // namespace dbmm
//........................................................................

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