office-gobmx/basic/source/basmgr/basmgr.cxx
Noel Grandin f48c9d59cc use more concrete UNO in basic
Change-Id: I6606008d9b45e00295cf441a7321a677d62317f2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173581
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Jenkins
2024-09-18 15:02:58 +02:00

2116 lines
67 KiB
C++

/* -*- 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 <utility>
#include <vcl/errinf.hxx>
#include <tools/stream.hxx>
#include <sot/storage.hxx>
#include <tools/urlobj.hxx>
#include <svl/hint.hxx>
#include <basic/sbx.hxx>
#include <basic/sbmeth.hxx>
#include <sot/storinfo.hxx>
#include <unotools/pathoptions.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <basic/sbmod.hxx>
#include <unotools/transliterationwrapper.hxx>
#include <sal/log.hxx>
#include <o3tl/string_view.hxx>
#include <basic/sberrors.hxx>
#include <basic/sbuno.hxx>
#include <basic/basmgr.hxx>
#include <global.hxx>
#include <com/sun/star/script/XLibraryContainer.hpp>
#include <com/sun/star/script/XPersistentLibraryContainer.hpp>
#include <scriptcont.hxx>
#include <memory>
#include <vector>
#define LIB_SEP 0x01
#define LIBINFO_SEP 0x02
#define LIBINFO_ID 0x1491
#define PASSWORD_MARKER 0x31452134
// Library API, implemented for XML import/export
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XContainer.hpp>
#include <com/sun/star/script/XStarBasicAccess.hpp>
#include <com/sun/star/script/XStarBasicModuleInfo.hpp>
#include <com/sun/star/script/XStarBasicDialogInfo.hpp>
#include <com/sun/star/script/XStarBasicLibraryInfo.hpp>
#include <com/sun/star/script/XLibraryContainerPassword.hpp>
#include <com/sun/star/script/ModuleInfo.hpp>
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
#include <com/sun/star/ucb/ContentCreationException.hpp>
#include <cppuhelper/implbase.hxx>
using com::sun::star::uno::Reference;
using namespace com::sun::star;
using namespace com::sun::star::script;
using namespace cppu;
typedef WeakImplHelper< container::XNameContainer > NameContainerHelper;
typedef WeakImplHelper< script::XStarBasicModuleInfo > ModuleInfoHelper;
typedef WeakImplHelper< script::XStarBasicAccess > StarBasicAccessHelper;
// Version 1
// sal_uInt32 nEndPos
// sal_uInt16 nId
// sal_uInt16 nVer
// bool bDoLoad
// String LibName
// String AbsStorageName
// String RelStorageName
// Version 2
// + bool bReference
constexpr OUString szStdLibName = u"Standard"_ustr;
constexpr OUString szBasicStorage = u"StarBASIC"_ustr;
constexpr OUString szOldManagerStream = u"BasicManager"_ustr;
constexpr OUString szManagerStream = u"BasicManager2"_ustr;
constexpr OUString szImbedded = u"LIBIMBEDDED"_ustr;
constexpr OString szCryptingKey = "CryptedBasic"_ostr;
const StreamMode eStreamReadMode = StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL;
const StreamMode eStorageReadMode = StreamMode::READ | StreamMode::SHARE_DENYWRITE;
// BasMgrContainerListenerImpl
typedef ::cppu::WeakImplHelper< container::XContainerListener > ContainerListenerHelper;
class BasMgrContainerListenerImpl: public ContainerListenerHelper
{
BasicManager* mpMgr;
OUString maLibName; // empty -> no lib, but lib container
public:
BasMgrContainerListenerImpl( BasicManager* pMgr, OUString aLibName )
: mpMgr( pMgr )
, maLibName(std::move( aLibName )) {}
static void insertLibraryImpl( const uno::Reference< script::XLibraryContainer >& xScriptCont, BasicManager* pMgr,
const uno::Any& aLibAny, const OUString& aLibName );
static void addLibraryModulesImpl( BasicManager const * pMgr, const uno::Reference< container::XNameAccess >& xLibNameAccess,
std::u16string_view aLibName );
// XEventListener
virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
// XContainerListener
virtual void SAL_CALL elementInserted( const container::ContainerEvent& Event ) override;
virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) override;
virtual void SAL_CALL elementRemoved( const container::ContainerEvent& Event ) override;
};
// BasMgrContainerListenerImpl
void BasMgrContainerListenerImpl::insertLibraryImpl( const uno::Reference< script::XLibraryContainer >& xScriptCont,
BasicManager* pMgr, const uno::Any& aLibAny, const OUString& aLibName )
{
Reference< container::XNameAccess > xLibNameAccess;
aLibAny >>= xLibNameAccess;
if( !pMgr->GetLib( aLibName ) )
{
StarBASIC* pLib =
pMgr->CreateLibForLibContainer( aLibName, xScriptCont );
DBG_ASSERT( pLib, "XML Import: Basic library could not be created");
}
uno::Reference< container::XContainer> xLibContainer( xLibNameAccess, uno::UNO_QUERY );
if( xLibContainer.is() )
{
// Register listener for library
Reference< container::XContainerListener > xLibraryListener
= new BasMgrContainerListenerImpl( pMgr, aLibName );
xLibContainer->addContainerListener( xLibraryListener );
}
if( xScriptCont->isLibraryLoaded( aLibName ) )
{
addLibraryModulesImpl( pMgr, xLibNameAccess, aLibName );
}
}
void BasMgrContainerListenerImpl::addLibraryModulesImpl( BasicManager const * pMgr,
const uno::Reference< container::XNameAccess >& xLibNameAccess, std::u16string_view aLibName )
{
uno::Sequence< OUString > aModuleNames = xLibNameAccess->getElementNames();
sal_Int32 nModuleCount = aModuleNames.getLength();
StarBASIC* pLib = pMgr->GetLib( aLibName );
DBG_ASSERT( pLib, "BasMgrContainerListenerImpl::addLibraryModulesImpl: Unknown lib!");
if( !pLib )
return;
const OUString* pNames = aModuleNames.getConstArray();
for( sal_Int32 j = 0 ; j < nModuleCount ; j++ )
{
OUString aModuleName = pNames[ j ];
uno::Any aElement = xLibNameAccess->getByName( aModuleName );
OUString aMod;
aElement >>= aMod;
uno::Reference< vba::XVBAModuleInfo > xVBAModuleInfo( xLibNameAccess, uno::UNO_QUERY );
if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( aModuleName ) )
{
ModuleInfo aInfo = xVBAModuleInfo->getModuleInfo( aModuleName );
pLib->MakeModule( aModuleName, aInfo, aMod );
}
else
pLib->MakeModule( aModuleName, aMod );
}
pLib->SetModified( false );
}
// XEventListener
void SAL_CALL BasMgrContainerListenerImpl::disposing( const lang::EventObject& ) {}
// XContainerListener
void SAL_CALL BasMgrContainerListenerImpl::elementInserted( const container::ContainerEvent& Event )
{
bool bLibContainer = maLibName.isEmpty();
OUString aName;
Event.Accessor >>= aName;
if( bLibContainer )
{
uno::Reference< script::XLibraryContainer > xScriptCont( Event.Source, uno::UNO_QUERY );
if (xScriptCont.is())
insertLibraryImpl(xScriptCont, mpMgr, Event.Element, aName);
StarBASIC* pLib = mpMgr->GetLib( aName );
if ( pLib )
{
uno::Reference< vba::XVBACompatibility > xVBACompat( xScriptCont, uno::UNO_QUERY );
if ( xVBACompat.is() )
pLib->SetVBAEnabled( xVBACompat->getVBACompatibilityMode() );
}
}
else
{
StarBASIC* pLib = mpMgr->GetLib( maLibName );
DBG_ASSERT( pLib, "BasMgrContainerListenerImpl::elementInserted: Unknown lib!");
if( pLib )
{
SbModule* pMod = pLib->FindModule( aName );
if( !pMod )
{
OUString aMod;
Event.Element >>= aMod;
uno::Reference< vba::XVBAModuleInfo > xVBAModuleInfo( Event.Source, uno::UNO_QUERY );
if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( aName ) )
{
ModuleInfo aInfo = xVBAModuleInfo->getModuleInfo( aName );
pLib->MakeModule( aName, aInfo, aMod );
}
else
pLib->MakeModule( aName, aMod );
pLib->SetModified( false );
}
}
}
}
void SAL_CALL BasMgrContainerListenerImpl::elementReplaced( const container::ContainerEvent& Event )
{
OUString aName;
Event.Accessor >>= aName;
// Replace not possible for library container
DBG_ASSERT( !maLibName.isEmpty(), "library container fired elementReplaced()");
StarBASIC* pLib = mpMgr->GetLib( maLibName );
if( !pLib )
return;
SbModule* pMod = pLib->FindModule( aName );
OUString aMod;
Event.Element >>= aMod;
if( pMod )
pMod->SetSource32( aMod );
else
pLib->MakeModule( aName, aMod );
pLib->SetModified( false );
}
void SAL_CALL BasMgrContainerListenerImpl::elementRemoved( const container::ContainerEvent& Event )
{
OUString aName;
Event.Accessor >>= aName;
bool bLibContainer = maLibName.isEmpty();
if( bLibContainer )
{
StarBASIC* pLib = mpMgr->GetLib( aName );
if( pLib )
{
sal_uInt16 nLibId = mpMgr->GetLibId( aName );
mpMgr->RemoveLib( nLibId, false );
}
}
else
{
StarBASIC* pLib = mpMgr->GetLib( maLibName );
SbModule* pMod = pLib ? pLib->FindModule( aName ) : nullptr;
if( pMod )
{
pLib->Remove( pMod );
pLib->SetModified( false );
}
}
}
BasicError::BasicError( ErrCodeMsg nId )
: nErrorId(std::move(nId))
{
}
BasicError::BasicError( const BasicError& rErr )
: nErrorId(rErr.nErrorId)
{
}
class BasicLibInfo
{
private:
StarBASICRef xLib;
OUString aLibName;
OUString aStorageName; // string is sufficient, unique at runtime
OUString aRelStorageName;
OUString aPassword;
bool bDoLoad;
bool bReference;
// Lib represents library in new UNO library container
uno::Reference< script::XLibraryContainer > mxScriptCont;
public:
BasicLibInfo();
bool IsReference() const { return bReference; }
void SetReference(bool b) { bReference = b; }
bool IsExtern() const { return aStorageName != szImbedded; }
void SetStorageName( const OUString& rName ) { aStorageName = rName; }
const OUString& GetStorageName() const { return aStorageName; }
void SetRelStorageName( const OUString& rN ) { aRelStorageName = rN; }
const OUString& GetRelStorageName() const { return aRelStorageName; }
StarBASICRef GetLib() const
{
if( mxScriptCont.is() && mxScriptCont->hasByName( aLibName ) &&
!mxScriptCont->isLibraryLoaded( aLibName ) )
return StarBASICRef();
return xLib;
}
StarBASICRef& GetLibRef() { return xLib; }
void SetLib( StarBASIC* pBasic ) { xLib = pBasic; }
const OUString& GetLibName() const { return aLibName; }
void SetLibName( const OUString& rName ) { aLibName = rName; }
// Only temporary for Load/Save
bool DoLoad() const { return bDoLoad; }
bool HasPassword() const { return !aPassword.isEmpty(); }
const OUString& GetPassword() const { return aPassword; }
void SetPassword( const OUString& rNewPassword )
{ aPassword = rNewPassword; }
static BasicLibInfo* Create( SotStorageStream& rSStream );
const uno::Reference< script::XLibraryContainer >& GetLibraryContainer() const
{ return mxScriptCont; }
void SetLibraryContainer( const uno::Reference< script::XLibraryContainer >& xScriptCont )
{ mxScriptCont = xScriptCont; }
};
BasicLibInfo::BasicLibInfo()
: aStorageName(szImbedded)
, aRelStorageName(szImbedded)
, bDoLoad(false)
, bReference(false)
{
}
BasicLibInfo* BasicLibInfo::Create( SotStorageStream& rSStream )
{
BasicLibInfo* pInfo = new BasicLibInfo;
sal_uInt32 nEndPos;
sal_uInt16 nId;
sal_uInt16 nVer;
rSStream.ReadUInt32( nEndPos );
rSStream.ReadUInt16( nId );
rSStream.ReadUInt16( nVer );
DBG_ASSERT( nId == LIBINFO_ID, "No BasicLibInfo?!" );
if( nId == LIBINFO_ID )
{
// Reload?
bool bDoLoad;
rSStream.ReadCharAsBool( bDoLoad );
pInfo->bDoLoad = bDoLoad;
// The name of the lib...
OUString aName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
pInfo->SetLibName( aName );
// Absolute path...
OUString aStorageName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
pInfo->SetStorageName( aStorageName );
// Relative path...
OUString aRelStorageName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
pInfo->SetRelStorageName( aRelStorageName );
if ( nVer >= 2 )
{
bool bReferenz;
rSStream.ReadCharAsBool( bReferenz );
pInfo->SetReference(bReferenz);
}
rSStream.Seek( nEndPos );
}
return pInfo;
}
BasicManager::BasicManager( SotStorage& rStorage, std::u16string_view rBaseURL, StarBASIC* pParentFromStdLib, OUString const * pLibPath, bool bDocMgr ) : mbDocMgr( bDocMgr )
{
if( pLibPath )
{
aBasicLibPath = *pLibPath;
}
OUString aStorName( rStorage.GetName() );
maStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
// If there is no Manager Stream, no further actions are necessary
if ( rStorage.IsStream( szManagerStream ) )
{
LoadBasicManager( rStorage, rBaseURL );
// StdLib contains Parent:
StarBASIC* pStdLib = GetStdLib();
DBG_ASSERT( pStdLib, "Standard-Lib not loaded?" );
if ( !pStdLib )
{
// Should never happen, but if it happens we won't crash...
pStdLib = new StarBASIC( nullptr, mbDocMgr );
if (maLibs.empty())
CreateLibInfo();
BasicLibInfo& rStdLibInfo = *maLibs.front();
rStdLibInfo.SetLib( pStdLib );
StarBASICRef xStdLib = rStdLibInfo.GetLib();
xStdLib->SetName( szStdLibName );
rStdLibInfo.SetLibName( szStdLibName );
xStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
xStdLib->SetModified( false );
}
else
{
pStdLib->SetParent( pParentFromStdLib );
// The other get StdLib as parent:
for ( sal_uInt16 nBasic = 1; nBasic < GetLibCount(); nBasic++ )
{
StarBASIC* pBasic = GetLib( nBasic );
if ( pBasic )
{
pStdLib->Insert( pBasic );
pBasic->SetFlag( SbxFlagBits::ExtSearch );
}
}
// Modified through insert
pStdLib->SetModified( false );
}
}
else
{
ImpCreateStdLib( pParentFromStdLib );
if ( rStorage.IsStream( szOldManagerStream ) )
LoadOldBasicManager( rStorage );
}
}
static void copyToLibraryContainer( StarBASIC* pBasic, const LibraryContainerInfo& rInfo )
{
uno::Reference< script::XLibraryContainer > xScriptCont( rInfo.mxScriptCont );
if ( !xScriptCont.is() )
return;
OUString aLibName = pBasic->GetName();
if( !xScriptCont->hasByName( aLibName ) )
xScriptCont->createLibrary( aLibName );
uno::Any aLibAny = xScriptCont->getByName( aLibName );
uno::Reference< container::XNameContainer > xLib;
aLibAny >>= xLib;
if ( !xLib.is() )
return;
for ( const auto& pModule: pBasic->GetModules() )
{
OUString aModName = pModule->GetName();
if( !xLib->hasByName( aModName ) )
{
OUString aSource = pModule->GetSource32();
uno::Any aSourceAny;
aSourceAny <<= aSource;
xLib->insertByName( aModName, aSourceAny );
}
}
}
const uno::Reference< script::XPersistentLibraryContainer >& BasicManager::GetDialogLibraryContainer() const
{
return maContainerInfo.mxDialogCont;
}
const uno::Reference< script::XPersistentLibraryContainer >& BasicManager::GetScriptLibraryContainer() const
{
return maContainerInfo.mxScriptCont;
}
void BasicManager::SetLibraryContainerInfo( const LibraryContainerInfo& rInfo )
{
maContainerInfo = rInfo;
uno::Reference< script::XLibraryContainer > xScriptCont( maContainerInfo.mxScriptCont );
if( xScriptCont.is() )
{
// Register listener for lib container
uno::Reference< container::XContainerListener > xLibContainerListener
= new BasMgrContainerListenerImpl( this, u""_ustr );
uno::Reference< container::XContainer> xLibContainer( xScriptCont, uno::UNO_QUERY );
xLibContainer->addContainerListener( xLibContainerListener );
const uno::Sequence< OUString > aScriptLibNames = xScriptCont->getElementNames();
if( aScriptLibNames.hasElements() )
{
for(const auto& rScriptLibName : aScriptLibNames)
{
uno::Any aLibAny = xScriptCont->getByName( rScriptLibName );
if ( rScriptLibName == "Standard" || rScriptLibName == "VBAProject")
xScriptCont->loadLibrary( rScriptLibName );
BasMgrContainerListenerImpl::insertLibraryImpl
( xScriptCont, this, aLibAny, rScriptLibName );
}
}
else
{
// No libs? Maybe an 5.2 document already loaded
for (auto const& rpBasLibInfo : maLibs)
{
StarBASIC* pLib = rpBasLibInfo->GetLib().get();
if( !pLib )
{
bool bLoaded = ImpLoadLibrary( rpBasLibInfo.get(), nullptr );
if( bLoaded )
pLib = rpBasLibInfo->GetLib().get();
}
if( pLib )
{
copyToLibraryContainer( pLib, maContainerInfo );
if (rpBasLibInfo->HasPassword())
{
basic::SfxScriptLibraryContainer* pOldBasicPassword =
maContainerInfo.mpOldBasicPassword;
if( pOldBasicPassword )
{
pOldBasicPassword->setLibraryPassword(
pLib->GetName(), rpBasLibInfo->GetPassword() );
}
}
}
}
}
}
SetGlobalUNOConstant( u"BasicLibraries"_ustr, uno::Any( maContainerInfo.mxScriptCont ) );
SetGlobalUNOConstant( u"DialogLibraries"_ustr, uno::Any( maContainerInfo.mxDialogCont ) );
}
BasicManager::BasicManager( StarBASIC* pSLib, OUString const * pLibPath, bool bDocMgr ) : mbDocMgr( bDocMgr )
{
DBG_ASSERT( pSLib, "BasicManager cannot be created with a NULL-Pointer!" );
if( pLibPath )
{
aBasicLibPath = *pLibPath;
}
BasicLibInfo* pStdLibInfo = CreateLibInfo();
pStdLibInfo->SetLib( pSLib );
StarBASICRef xStdLib = pStdLibInfo->GetLib();
xStdLib->SetName(szStdLibName);
pStdLibInfo->SetLibName(szStdLibName );
pSLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
// Save is only necessary if basic has changed
xStdLib->SetModified( false );
}
void BasicManager::ImpMgrNotLoaded( const OUString& rStorageName )
{
// pErrInf is only destroyed if the error os processed by an
// ErrorHandler
ErrCodeMsg aErrInf( ERRCODE_BASMGR_MGROPEN, rStorageName, DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
// Create a stdlib otherwise we crash!
BasicLibInfo* pStdLibInfo = CreateLibInfo();
pStdLibInfo->SetLib( new StarBASIC( nullptr, mbDocMgr ) );
StarBASICRef xStdLib = pStdLibInfo->GetLib();
xStdLib->SetName( szStdLibName );
pStdLibInfo->SetLibName( szStdLibName );
xStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
xStdLib->SetModified( false );
}
void BasicManager::ImpCreateStdLib( StarBASIC* pParentFromStdLib )
{
BasicLibInfo* pStdLibInfo = CreateLibInfo();
StarBASIC* pStdLib = new StarBASIC( pParentFromStdLib, mbDocMgr );
pStdLibInfo->SetLib( pStdLib );
pStdLib->SetName( szStdLibName );
pStdLibInfo->SetLibName( szStdLibName );
pStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
}
void BasicManager::LoadBasicManager( SotStorage& rStorage, std::u16string_view rBaseURL )
{
rtl::Reference<SotStorageStream> xManagerStream = rStorage.OpenSotStream( szManagerStream, eStreamReadMode );
OUString aStorName( rStorage.GetName() );
// #i13114 removed, DBG_ASSERT( aStorName.Len(), "No Storage Name!" );
if ( !xManagerStream.is() || xManagerStream->GetError() || ( xManagerStream->TellEnd() == 0 ) )
{
ImpMgrNotLoaded( aStorName );
return;
}
maStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
// #i13114 removed, DBG_ASSERT(aStorageName.Len() != 0, "Bad storage name");
OUString aRealStorageName = maStorageName; // for relative paths, can be modified through BaseURL
if ( !rBaseURL.empty() )
{
INetURLObject aObj( rBaseURL );
if ( aObj.GetProtocol() == INetProtocol::File )
{
aRealStorageName = aObj.PathToFileName();
}
}
xManagerStream->SetBufferSize( 1024 );
xManagerStream->Seek( STREAM_SEEK_TO_BEGIN );
sal_uInt32 nEndPos;
xManagerStream->ReadUInt32( nEndPos );
sal_uInt16 nLibs;
xManagerStream->ReadUInt16( nLibs );
// Plausibility!
if( nLibs & 0xF000 )
{
SAL_WARN( "basic", "BasicManager-Stream defect!" );
return;
}
const size_t nMinBasicLibSize(8);
const size_t nMaxPossibleLibs = xManagerStream->remainingSize() / nMinBasicLibSize;
if (nLibs > nMaxPossibleLibs)
{
SAL_WARN("basic", "Parsing error: " << nMaxPossibleLibs <<
" max possible entries, but " << nLibs << " claimed, truncating");
nLibs = nMaxPossibleLibs;
}
for (sal_uInt16 nL = 0; nL < nLibs; ++nL)
{
BasicLibInfo* pInfo = BasicLibInfo::Create( *xManagerStream );
// Correct absolute pathname if relative is existing.
// Always try relative first if there are two stands on disk
if ( !pInfo->GetRelStorageName().isEmpty() && pInfo->GetRelStorageName() != szImbedded )
{
INetURLObject aObj( aRealStorageName, INetProtocol::File );
aObj.removeSegment();
bool bWasAbsolute = false;
aObj = aObj.smartRel2Abs( pInfo->GetRelStorageName(), bWasAbsolute );
//*** TODO: Replace if still necessary
//*** TODO-End
if ( ! aBasicLibPath.isEmpty() )
{
// Search lib in path
OUString aSearchFile = pInfo->GetRelStorageName();
OUString aSearchFileOldFormat(aSearchFile);
SvtPathOptions aPathCFG;
if( aPathCFG.SearchFile( aSearchFileOldFormat, SvtPathOptions::Paths::Basic ) )
{
pInfo->SetStorageName( aSearchFile );
}
}
}
maLibs.push_back(std::unique_ptr<BasicLibInfo>(pInfo));
// Libs from external files should be loaded only when necessary.
// But references are loaded at once, otherwise some big customers get into trouble
if ( pInfo->DoLoad() &&
( !pInfo->IsExtern() || pInfo->IsReference()))
{
ImpLoadLibrary( pInfo, &rStorage );
}
}
xManagerStream->Seek( nEndPos );
xManagerStream->SetBufferSize( 0 );
xManagerStream.clear();
}
void BasicManager::LoadOldBasicManager( SotStorage& rStorage )
{
rtl::Reference<SotStorageStream> xManagerStream = rStorage.OpenSotStream( szOldManagerStream, eStreamReadMode );
OUString aStorName( rStorage.GetName() );
DBG_ASSERT( aStorName.getLength(), "No Storage Name!" );
if ( !xManagerStream.is() || xManagerStream->GetError() || ( xManagerStream->TellEnd() == 0 ) )
{
ImpMgrNotLoaded( aStorName );
return;
}
xManagerStream->SetBufferSize( 1024 );
xManagerStream->Seek( STREAM_SEEK_TO_BEGIN );
sal_uInt32 nBasicStartOff, nBasicEndOff;
xManagerStream->ReadUInt32( nBasicStartOff );
xManagerStream->ReadUInt32( nBasicEndOff );
DBG_ASSERT( !xManagerStream->GetError(), "Invalid Manager-Stream!" );
xManagerStream->Seek( nBasicStartOff );
if (!ImplLoadBasic( *xManagerStream, maLibs.front()->GetLibRef() ))
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_MGROPEN, aStorName, DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
// and it proceeds ...
}
xManagerStream->Seek( nBasicEndOff+1 ); // +1: 0x00 as separator
OUString aLibs = xManagerStream->ReadUniOrByteString(xManagerStream->GetStreamCharSet());
xManagerStream->SetBufferSize( 0 );
xManagerStream.clear(); // Close stream
if ( aLibs.isEmpty() )
return;
INetURLObject aCurStorage( aStorName, INetProtocol::File );
sal_Int32 nLibPos {0};
do {
const OUString aLibInfo(aLibs.getToken(0, LIB_SEP, nLibPos));
sal_Int32 nInfoPos {0};
const OUString aLibName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
DBG_ASSERT( nInfoPos >= 0, "Invalid Lib-Info!" );
const OUString aLibAbsStorageName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
// TODO: fail also here if there are no more tokens?
const OUString aLibRelStorageName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
DBG_ASSERT( nInfoPos < 0, "Invalid Lib-Info!" );
INetURLObject aLibAbsStorage( aLibAbsStorageName, INetProtocol::File );
INetURLObject aLibRelStorage( aStorName );
aLibRelStorage.removeSegment();
bool bWasAbsolute = false;
aLibRelStorage = aLibRelStorage.smartRel2Abs( aLibRelStorageName, bWasAbsolute);
DBG_ASSERT(!bWasAbsolute, "RelStorageName was absolute!" );
rtl::Reference<SotStorage> xStorageRef;
if ( aLibAbsStorage == aCurStorage || aLibRelStorageName == szImbedded )
{
xStorageRef = &rStorage;
}
else
{
xStorageRef = new SotStorage( false, aLibAbsStorage.GetMainURL
( INetURLObject::DecodeMechanism::NONE ), eStorageReadMode );
if ( xStorageRef->GetError() != ERRCODE_NONE )
xStorageRef = new SotStorage( false, aLibRelStorage.
GetMainURL( INetURLObject::DecodeMechanism::NONE ), eStorageReadMode );
}
if ( xStorageRef.is() )
{
AddLib( *xStorageRef, aLibName, false );
}
else
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_LIBLOAD, aStorName, DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
} while (nLibPos>=0);
}
BasicManager::~BasicManager()
{
// Notify listener if something needs to be saved
Broadcast( SfxHint( SfxHintId::Dying) );
}
bool BasicManager::HasExeCode( std::u16string_view sLib )
{
StarBASIC* pLib = GetLib(sLib);
if ( pLib )
{
for (const auto& pModule: pLib->GetModules())
{
if (pModule->HasExeCode())
return true;
}
}
return false;
}
BasicLibInfo* BasicManager::CreateLibInfo()
{
maLibs.push_back(std::make_unique<BasicLibInfo>());
return maLibs.back().get();
}
bool BasicManager::ImpLoadLibrary( BasicLibInfo* pLibInfo, SotStorage* pCurStorage )
{
try {
DBG_ASSERT( pLibInfo, "LibInfo!?" );
OUString aStorageName( pLibInfo->GetStorageName() );
if ( aStorageName.isEmpty() || aStorageName == szImbedded )
{
aStorageName = GetStorageName();
}
rtl::Reference<SotStorage> xStorage;
// The current must not be opened again...
if ( pCurStorage )
{
OUString aStorName( pCurStorage->GetName() );
// #i13114 removed, DBG_ASSERT( aStorName.Len(), "No Storage Name!" );
INetURLObject aCurStorageEntry(aStorName, INetProtocol::File);
// #i13114 removed, DBG_ASSERT(aCurStorageEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ).Len() != 0, "Bad storage name");
INetURLObject aStorageEntry(aStorageName, INetProtocol::File);
// #i13114 removed, DBG_ASSERT(aCurStorageEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ).Len() != 0, "Bad storage name");
if ( aCurStorageEntry == aStorageEntry )
{
xStorage = pCurStorage;
}
}
if ( !xStorage.is() )
{
xStorage = new SotStorage( false, aStorageName, eStorageReadMode );
}
rtl::Reference<SotStorage> xBasicStorage = xStorage->OpenSotStorage( szBasicStorage, eStorageReadMode, false );
if ( !xBasicStorage.is() || xBasicStorage->GetError() )
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_MGROPEN, xStorage->GetName(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
else
{
// In the Basic-Storage every lib is in a Stream...
rtl::Reference<SotStorageStream> xBasicStream = xBasicStorage->OpenSotStream( pLibInfo->GetLibName(), eStreamReadMode );
if ( !xBasicStream.is() || xBasicStream->GetError() )
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_LIBLOAD , pLibInfo->GetLibName(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
else
{
bool bLoaded = false;
if ( xBasicStream->TellEnd() != 0 )
{
if ( !pLibInfo->GetLib().is() )
{
pLibInfo->SetLib( new StarBASIC( GetStdLib(), mbDocMgr ) );
}
xBasicStream->SetBufferSize( 1024 );
xBasicStream->Seek( STREAM_SEEK_TO_BEGIN );
bLoaded = ImplLoadBasic( *xBasicStream, pLibInfo->GetLibRef() );
xBasicStream->SetBufferSize( 0 );
StarBASICRef xStdLib = pLibInfo->GetLib();
xStdLib->SetName( pLibInfo->GetLibName() );
xStdLib->SetModified( false );
xStdLib->SetFlag( SbxFlagBits::DontStore );
}
if ( !bLoaded )
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_LIBLOAD, pLibInfo->GetLibName(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
else
{
// Perhaps there are additional information in the stream...
xBasicStream->SetCryptMaskKey(szCryptingKey);
xBasicStream->RefreshBuffer();
sal_uInt32 nPasswordMarker = 0;
xBasicStream->ReadUInt32( nPasswordMarker );
if ( ( nPasswordMarker == PASSWORD_MARKER ) && !xBasicStream->eof() )
{
OUString aPassword = xBasicStream->ReadUniOrByteString(
xBasicStream->GetStreamCharSet());
pLibInfo->SetPassword( aPassword );
}
xBasicStream->SetCryptMaskKey(OString());
CheckModules( pLibInfo->GetLib().get(), pLibInfo->IsReference() );
}
return bLoaded;
}
}
}
catch (const css::ucb::ContentCreationException&)
{
}
return false;
}
bool BasicManager::ImplEncryptStream( SvStream& rStrm )
{
sal_uInt64 const nPos = rStrm.Tell();
sal_uInt32 nCreator;
rStrm.ReadUInt32( nCreator );
rStrm.Seek( nPos );
bool bProtected = false;
if ( nCreator != SBXCR_SBX )
{
// Should only be the case for encrypted Streams
bProtected = true;
rStrm.SetCryptMaskKey(szCryptingKey);
rStrm.RefreshBuffer();
}
return bProtected;
}
// This code is necessary to load the BASIC of Beta 1
// TODO: Which Beta 1?
bool BasicManager::ImplLoadBasic( SvStream& rStrm, StarBASICRef& rOldBasic ) const
{
bool bProtected = ImplEncryptStream( rStrm );
SbxBaseRef xNew = SbxBase::Load( rStrm );
bool bLoaded = false;
if( xNew.is() )
{
if( auto pNew = dynamic_cast<StarBASIC*>( xNew.get() ) )
{
// Use the Parent of the old BASICs
if( rOldBasic.is() )
{
pNew->SetParent( rOldBasic->GetParent() );
if( pNew->GetParent() )
{
pNew->GetParent()->Insert( pNew );
}
pNew->SetFlag( SbxFlagBits::ExtSearch );
}
rOldBasic = pNew;
// Fill new library container (5.2 -> 6.0)
copyToLibraryContainer( pNew, maContainerInfo );
pNew->SetModified( false );
bLoaded = true;
}
}
if ( bProtected )
{
rStrm.SetCryptMaskKey(OString());
}
return bLoaded;
}
void BasicManager::CheckModules( StarBASIC* pLib, bool bReference )
{
if ( !pLib )
{
return;
}
bool bModified = pLib->IsModified();
for ( const auto& pModule: pLib->GetModules() )
{
DBG_ASSERT(pModule, "Module not received!");
if ( !pModule->IsCompiled() && !StarBASIC::GetErrorCode() )
{
pModule->Compile();
}
}
// #67477, AB 8.12.99 On demand compile in referenced libs should not
// cause modified
if( !bModified && bReference )
{
OSL_FAIL( "Referenced basic library is not compiled!" );
pLib->SetModified( false );
}
}
StarBASIC* BasicManager::AddLib( SotStorage& rStorage, const OUString& rLibName, bool bReference )
{
OUString aStorName( rStorage.GetName() );
DBG_ASSERT( !aStorName.isEmpty(), "No Storage Name!" );
OUString aStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
DBG_ASSERT(!aStorageName.isEmpty(), "Bad storage name");
OUString aNewLibName( rLibName );
while ( HasLib( aNewLibName ) )
{
aNewLibName += "_";
}
BasicLibInfo* pLibInfo = CreateLibInfo();
// Use original name otherwise ImpLoadLibrary fails...
pLibInfo->SetLibName( rLibName );
// but doesn't work this way if name exists twice
sal_uInt16 nLibId = static_cast<sal_uInt16>(maLibs.size()) - 1;
// Set StorageName before load because it is compared with pCurStorage
pLibInfo->SetStorageName( aStorageName );
bool bLoaded = ImpLoadLibrary( pLibInfo, &rStorage );
if ( bLoaded )
{
if ( aNewLibName != rLibName )
{
pLibInfo->SetLibName(aNewLibName);
}
if ( bReference )
{
pLibInfo->GetLib()->SetModified( false ); // Don't save in this case
pLibInfo->SetRelStorageName( OUString() );
pLibInfo->SetReference(true);
}
else
{
pLibInfo->GetLib()->SetModified( true ); // Must be saved after Add!
pLibInfo->SetStorageName( szImbedded ); // Save in BasicManager-Storage
}
}
else
{
RemoveLib( nLibId, false );
pLibInfo = nullptr;
}
return pLibInfo ? &*pLibInfo->GetLib() : nullptr;
}
bool BasicManager::IsReference( sal_uInt16 nLib )
{
DBG_ASSERT( nLib < maLibs.size(), "Lib does not exist!" );
if ( nLib < maLibs.size() )
{
return maLibs[nLib]->IsReference();
}
return false;
}
void BasicManager::RemoveLib( sal_uInt16 nLib )
{
// Only physical deletion if no reference
RemoveLib( nLib, !IsReference( nLib ) );
}
bool BasicManager::RemoveLib( sal_uInt16 nLib, bool bDelBasicFromStorage )
{
DBG_ASSERT( nLib, "Standard-Lib cannot be removed!" );
DBG_ASSERT( !nLib || nLib < maLibs.size(), "Lib not found!" );
if( !nLib || nLib < maLibs.size() )
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_REMOVELIB, OUString(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
return false;
}
auto const itLibInfo = maLibs.begin() + nLib;
// If one of the streams cannot be opened, this is not an error,
// because BASIC was never written before...
if (bDelBasicFromStorage && !(*itLibInfo)->IsReference() &&
(!(*itLibInfo)->IsExtern() || SotStorage::IsStorageFile((*itLibInfo)->GetStorageName())))
{
rtl::Reference<SotStorage> xStorage;
try
{
if (!(*itLibInfo)->IsExtern())
{
xStorage = new SotStorage(false, GetStorageName());
}
else
{
xStorage = new SotStorage(false, (*itLibInfo)->GetStorageName());
}
}
catch (const css::ucb::ContentCreationException&)
{
TOOLS_WARN_EXCEPTION("basic", "BasicManager::RemoveLib:");
}
if (xStorage.is() && xStorage->IsStorage(szBasicStorage))
{
rtl::Reference<SotStorage> xBasicStorage = xStorage->OpenSotStorage
( szBasicStorage, StreamMode::STD_READWRITE, false );
if ( !xBasicStorage.is() || xBasicStorage->GetError() )
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_REMOVELIB, OUString(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
else if (xBasicStorage->IsStream((*itLibInfo)->GetLibName()))
{
xBasicStorage->Remove((*itLibInfo)->GetLibName());
xBasicStorage->Commit();
// If no further stream available,
// delete the SubStorage.
SvStorageInfoList aInfoList;
xBasicStorage->FillInfoList( &aInfoList );
if ( aInfoList.empty() )
{
xBasicStorage.clear();
xStorage->Remove( szBasicStorage );
xStorage->Commit();
// If no further Streams or SubStorages available,
// delete the Storage, too.
aInfoList.clear();
xStorage->FillInfoList( &aInfoList );
if ( aInfoList.empty() )
{
//OUString aName_( xStorage->GetName() );
xStorage.clear();
//*** TODO: Replace if still necessary
//SfxContentHelper::Kill( aName );
//*** TODO-End
}
}
}
}
}
if ((*itLibInfo)->GetLib().is())
{
GetStdLib()->Remove( (*itLibInfo)->GetLib().get() );
}
maLibs.erase(itLibInfo);
return true; // Remove was successful, del unimportant
}
sal_uInt16 BasicManager::GetLibCount() const
{
return static_cast<sal_uInt16>(maLibs.size());
}
StarBASIC* BasicManager::GetLib( sal_uInt16 nLib ) const
{
DBG_ASSERT( nLib < maLibs.size(), "Lib does not exist!" );
if ( nLib < maLibs.size() )
{
return maLibs[nLib]->GetLib().get();
}
return nullptr;
}
StarBASIC* BasicManager::GetStdLib() const
{
StarBASIC* pLib = GetLib( 0 );
return pLib;
}
StarBASIC* BasicManager::GetLib( std::u16string_view rName ) const
{
for (auto const& rpLib : maLibs)
{
if (rpLib->GetLibName().equalsIgnoreAsciiCase(rName)) // Check if available...
{
return rpLib->GetLib().get();
}
}
return nullptr;
}
sal_uInt16 BasicManager::GetLibId( std::u16string_view rName ) const
{
for (size_t i = 0; i < maLibs.size(); i++)
{
if (maLibs[i]->GetLibName().equalsIgnoreAsciiCase( rName ))
{
return static_cast<sal_uInt16>(i);
}
}
return LIB_NOTFOUND;
}
bool BasicManager::HasLib( std::u16string_view rName ) const
{
for (const auto& rpLib : maLibs)
{
if (rpLib->GetLibName().equalsIgnoreAsciiCase(rName)) // Check if available...
{
return true;
}
}
return false;
}
OUString BasicManager::GetLibName( sal_uInt16 nLib )
{
DBG_ASSERT( nLib < maLibs.size(), "Lib?!" );
if ( nLib < maLibs.size() )
{
return maLibs[nLib]->GetLibName();
}
return OUString();
}
bool BasicManager::LoadLib( sal_uInt16 nLib )
{
bool bDone = false;
DBG_ASSERT( nLib < maLibs.size() , "Lib?!" );
if ( nLib < maLibs.size() )
{
BasicLibInfo& rLibInfo = *maLibs[nLib];
uno::Reference< script::XLibraryContainer > xLibContainer = rLibInfo.GetLibraryContainer();
if( xLibContainer.is() )
{
OUString aLibName = rLibInfo.GetLibName();
xLibContainer->loadLibrary( aLibName );
bDone = xLibContainer->isLibraryLoaded( aLibName );
}
else
{
bDone = ImpLoadLibrary( &rLibInfo, nullptr );
StarBASIC* pLib = GetLib( nLib );
if ( pLib )
{
GetStdLib()->Insert( pLib );
pLib->SetFlag( SbxFlagBits::ExtSearch );
}
}
}
else
{
ErrCodeMsg aErrInf( ERRCODE_BASMGR_LIBLOAD, OUString(), DialogMask::ButtonsOk );
aErrors.emplace_back(aErrInf);
}
return bDone;
}
StarBASIC* BasicManager::CreateLib( const OUString& rLibName )
{
if ( GetLib( rLibName ) )
{
return nullptr;
}
BasicLibInfo* pLibInfo = CreateLibInfo();
StarBASIC* pNew = new StarBASIC( GetStdLib(), mbDocMgr );
GetStdLib()->Insert( pNew );
pNew->SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::DontStore );
pLibInfo->SetLib( pNew );
pLibInfo->SetLibName( rLibName );
pLibInfo->GetLib()->SetName( rLibName );
return pLibInfo->GetLib().get();
}
// For XML import/export:
StarBASIC* BasicManager::CreateLib( const OUString& rLibName, const OUString& Password,
const OUString& LinkTargetURL )
{
// Ask if lib exists because standard lib is always there
StarBASIC* pLib = GetLib( rLibName );
if( !pLib )
{
if( !LinkTargetURL.isEmpty())
{
try
{
rtl::Reference<SotStorage> xStorage = new SotStorage(false, LinkTargetURL, StreamMode::READ | StreamMode::SHARE_DENYWRITE);
if (!xStorage->GetError())
{
pLib = AddLib(*xStorage, rLibName, true);
}
}
catch (const css::ucb::ContentCreationException&)
{
TOOLS_WARN_EXCEPTION("basic", "BasicManager::RemoveLib:");
}
DBG_ASSERT( pLib, "XML Import: Linked basic library could not be loaded");
}
else
{
pLib = CreateLib( rLibName );
if( Password.isEmpty())
{
BasicLibInfo* pLibInfo = FindLibInfo( pLib );
pLibInfo ->SetPassword( Password );
}
}
//ExternalSourceURL ?
}
return pLib;
}
StarBASIC* BasicManager::CreateLibForLibContainer( const OUString& rLibName,
const uno::Reference< script::XLibraryContainer >& xScriptCont )
{
if ( GetLib( rLibName ) )
{
return nullptr;
}
BasicLibInfo* pLibInfo = CreateLibInfo();
StarBASIC* pNew = new StarBASIC( GetStdLib(), mbDocMgr );
GetStdLib()->Insert( pNew );
pNew->SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::DontStore );
pLibInfo->SetLib( pNew );
pLibInfo->SetLibName( rLibName );
pLibInfo->GetLib()->SetName( rLibName );
pLibInfo->SetLibraryContainer( xScriptCont );
return pNew;
}
BasicLibInfo* BasicManager::FindLibInfo( StarBASIC const * pBasic )
{
for (auto const& rpLib : maLibs)
{
if (rpLib->GetLib().get() == pBasic)
{
return rpLib.get();
}
}
return nullptr;
}
bool BasicManager::IsBasicModified() const
{
for (auto const& rpLib : maLibs)
{
if (rpLib->GetLib().is() && rpLib->GetLib()->IsModified())
{
return true;
}
}
return false;
}
bool BasicManager::GetGlobalUNOConstant( const OUString& rName, uno::Any& aOut )
{
bool bRes = false;
StarBASIC* pStandardLib = GetStdLib();
OSL_PRECOND( pStandardLib, "BasicManager::GetGlobalUNOConstant: no lib to read from!" );
if ( pStandardLib )
bRes = pStandardLib->GetUNOConstant( rName, aOut );
return bRes;
}
void BasicManager::SetGlobalUNOConstant( const OUString& rName, const uno::Any& _rValue, css::uno::Any* pOldValue )
{
StarBASIC* pStandardLib = GetStdLib();
OSL_PRECOND( pStandardLib, "BasicManager::SetGlobalUNOConstant: no lib to insert into!" );
if ( !pStandardLib )
return;
if (pOldValue)
{
// obtain the old value
SbxVariable* pVariable = pStandardLib->Find( rName, SbxClassType::Object );
if ( pVariable )
*pOldValue = sbxToUnoValue( pVariable );
}
SbxObjectRef xUnoObj = GetSbUnoObject( _rValue.getValueType ().getTypeName () , _rValue );
xUnoObj->SetName(rName);
xUnoObj->SetFlag( SbxFlagBits::DontStore );
pStandardLib->Insert( xUnoObj.get() );
}
bool BasicManager::ImgVersion12PsswdBinaryLimitExceeded( std::vector< OUString >& _out_rModuleNames )
{
try
{
uno::Reference< container::XNameAccess > xScripts( GetScriptLibraryContainer(), uno::UNO_QUERY_THROW );
uno::Reference< script::XLibraryContainerPassword > xPassword( GetScriptLibraryContainer(), uno::UNO_QUERY_THROW );
const uno::Sequence< OUString > aNames( xScripts->getElementNames() );
for ( auto const & scriptElementName : aNames )
{
if( !xPassword->isLibraryPasswordProtected( scriptElementName ) )
continue;
StarBASIC* pBasicLib = GetLib( scriptElementName );
if ( !pBasicLib )
continue;
uno::Reference< container::XNameAccess > xScriptLibrary( xScripts->getByName( scriptElementName ), uno::UNO_QUERY_THROW );
const uno::Sequence< OUString > aElementNames( xScriptLibrary->getElementNames() );
std::vector<OUString> aBigModules;
for ( auto const & libraryElementName : aElementNames )
{
SbModule* pMod = pBasicLib->FindModule( libraryElementName );
if ( pMod && pMod->ExceedsImgVersion12ModuleSize() )
aBigModules.push_back(libraryElementName);
}
if (!aBigModules.empty())
{
_out_rModuleNames.swap(aBigModules);
return true;
}
}
}
catch( const uno::Exception& )
{
DBG_UNHANDLED_EXCEPTION("basic");
}
return false;
}
namespace
{
SbMethod* lcl_queryMacro( BasicManager* i_manager, OUString const& i_fullyQualifiedName )
{
sal_Int32 nLast = 0;
const OUString sLibName {i_fullyQualifiedName.getToken( 0, '.', nLast )};
const OUString sModule {i_fullyQualifiedName.getToken( 0, '.', nLast )};
OUString sMacro;
if(nLast >= 0)
{
sMacro = i_fullyQualifiedName.copy(nLast);
}
else
{
sMacro = i_fullyQualifiedName;
}
utl::TransliterationWrapper& rTransliteration = SbGlobal::GetTransliteration();
sal_uInt16 nLibCount = i_manager->GetLibCount();
for ( sal_uInt16 nLib = 0; nLib < nLibCount; ++nLib )
{
if ( rTransliteration.isEqual( i_manager->GetLibName( nLib ), sLibName ) )
{
StarBASIC* pLib = i_manager->GetLib( nLib );
if( !pLib )
{
bool const bLoaded = i_manager->LoadLib( nLib );
if (bLoaded)
{
pLib = i_manager->GetLib( nLib );
}
}
if( pLib )
{
for ( const auto& pMod: pLib->GetModules() )
{
if ( rTransliteration.isEqual( pMod->GetName(), sModule ) )
{
SbMethod* pMethod = static_cast<SbMethod*>(pMod->Find( sMacro, SbxClassType::Method ));
if( pMethod )
{
return pMethod;
}
}
}
}
}
}
return nullptr;
}
}
bool BasicManager::HasMacro( OUString const& i_fullyQualifiedName ) const
{
return ( lcl_queryMacro( const_cast< BasicManager* >( this ), i_fullyQualifiedName ) != nullptr );
}
ErrCode BasicManager::ExecuteMacro( OUString const& i_fullyQualifiedName, SbxArray* i_arguments, SbxValue* i_retValue )
{
SbMethod* pMethod = lcl_queryMacro( this, i_fullyQualifiedName );
ErrCode nError = ERRCODE_NONE;
if ( pMethod )
{
if ( i_arguments )
pMethod->SetParameters( i_arguments );
nError = pMethod->Call( i_retValue );
}
else
nError = ERRCODE_BASIC_PROC_UNDEFINED;
return nError;
}
ErrCode BasicManager::ExecuteMacro( OUString const& i_fullyQualifiedName, std::u16string_view i_commaSeparatedArgs, SbxValue* i_retValue )
{
SbMethod* pMethod = lcl_queryMacro( this, i_fullyQualifiedName );
if ( !pMethod )
{
return ERRCODE_BASIC_PROC_UNDEFINED;
}
// arguments must be quoted
OUString sQuotedArgs;
OUStringBuffer sArgs( i_commaSeparatedArgs );
if ( sArgs.getLength()<2 || sArgs[1] == '\"')
{
// no args or already quoted args
sQuotedArgs = sArgs.makeStringAndClear();
}
else
{
// quote parameters
sArgs.remove( 0, 1 );
sArgs.remove( sArgs.getLength() - 1, 1 );
OUStringBuffer aBuff;
OUString sArgs2 = sArgs.makeStringAndClear();
aBuff.append("(");
if (!sArgs2.isEmpty())
{
sal_Int32 nPos {0};
for (;;)
{
aBuff.append( OUString::Concat("\"")
+ o3tl::getToken(sArgs2, 0, ',', nPos)
+ "\"" );
if (nPos<0)
break;
aBuff.append( "," );
}
}
aBuff.append( ")" );
sQuotedArgs = aBuff.makeStringAndClear();
}
// add quoted arguments and do the call
OUString sCall = "["
+ pMethod->GetName()
+ sQuotedArgs
+ "]";
SbxVariable* pRet = pMethod->GetParent()->Execute( sCall );
if ( pRet && ( pRet != pMethod ) )
{
*i_retValue = *pRet;
}
return SbxBase::GetError();
}
namespace {
class ModuleInfo_Impl : public ModuleInfoHelper
{
OUString maName;
OUString maLanguage;
OUString maSource;
public:
ModuleInfo_Impl( OUString aName, OUString aLanguage, OUString aSource )
: maName(std::move( aName )), maLanguage(std::move( aLanguage)), maSource(std::move( aSource )) {}
// Methods XStarBasicModuleInfo
virtual OUString SAL_CALL getName() override
{ return maName; }
virtual OUString SAL_CALL getLanguage() override
{ return maLanguage; }
virtual OUString SAL_CALL getSource() override
{ return maSource; }
};
class DialogInfo_Impl : public WeakImplHelper< script::XStarBasicDialogInfo >
{
OUString maName;
uno::Sequence< sal_Int8 > mData;
public:
DialogInfo_Impl( OUString aName, const uno::Sequence< sal_Int8 >& Data )
: maName(std::move( aName )), mData( Data ) {}
// Methods XStarBasicDialogInfo
virtual OUString SAL_CALL getName() override
{ return maName; }
virtual uno::Sequence< sal_Int8 > SAL_CALL getData() override
{ return mData; }
};
class LibraryInfo_Impl : public WeakImplHelper< script::XStarBasicLibraryInfo >
{
OUString maName;
uno::Reference< container::XNameContainer > mxModuleContainer;
uno::Reference< container::XNameContainer > mxDialogContainer;
OUString maPassword;
OUString maExternaleSourceURL;
OUString maLinkTargetURL;
public:
LibraryInfo_Impl
(
OUString aName,
uno::Reference< container::XNameContainer > xModuleContainer,
uno::Reference< container::XNameContainer > xDialogContainer,
OUString aPassword,
OUString aExternaleSourceURL,
OUString aLinkTargetURL
)
: maName(std::move( aName ))
, mxModuleContainer(std::move( xModuleContainer ))
, mxDialogContainer(std::move( xDialogContainer ))
, maPassword(std::move( aPassword ))
, maExternaleSourceURL(std::move( aExternaleSourceURL ))
, maLinkTargetURL(std::move( aLinkTargetURL ))
{}
// Methods XStarBasicLibraryInfo
virtual OUString SAL_CALL getName() override
{ return maName; }
virtual uno::Reference< container::XNameContainer > SAL_CALL getModuleContainer() override
{ return mxModuleContainer; }
virtual uno::Reference< container::XNameContainer > SAL_CALL getDialogContainer() override
{ return mxDialogContainer; }
virtual OUString SAL_CALL getPassword() override
{ return maPassword; }
virtual OUString SAL_CALL getExternalSourceURL() override
{ return maExternaleSourceURL; }
virtual OUString SAL_CALL getLinkTargetURL() override
{ return maLinkTargetURL; }
};
class ModuleContainer_Impl : public NameContainerHelper
{
StarBASIC* mpLib;
public:
explicit ModuleContainer_Impl( StarBASIC* pLib )
:mpLib( pLib ) {}
// Methods XElementAccess
virtual uno::Type SAL_CALL getElementType() override;
virtual sal_Bool SAL_CALL hasElements() override;
// Methods XNameAccess
virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
// Methods XNameReplace
virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
// Methods XNameContainer
virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
virtual void SAL_CALL removeByName( const OUString& Name ) override;
};
}
// Methods XElementAccess
uno::Type ModuleContainer_Impl::getElementType()
{
uno::Type aModuleType = cppu::UnoType<script::XStarBasicModuleInfo>::get();
return aModuleType;
}
sal_Bool ModuleContainer_Impl::hasElements()
{
return mpLib && !mpLib->GetModules().empty();
}
// Methods XNameAccess
uno::Any ModuleContainer_Impl::getByName( const OUString& aName )
{
SbModule* pMod = mpLib ? mpLib->FindModule( aName ) : nullptr;
if( !pMod )
throw container::NoSuchElementException();
uno::Reference< script::XStarBasicModuleInfo > xMod = new ModuleInfo_Impl( aName, u"StarBasic"_ustr, pMod->GetSource32() );
uno::Any aRetAny;
aRetAny <<= xMod;
return aRetAny;
}
uno::Sequence< OUString > ModuleContainer_Impl::getElementNames()
{
sal_uInt16 nMods = mpLib ? mpLib->GetModules().size() : 0;
uno::Sequence< OUString > aRetSeq( nMods );
OUString* pRetSeq = aRetSeq.getArray();
for( sal_uInt16 i = 0 ; i < nMods ; i++ )
{
pRetSeq[i] = mpLib->GetModules()[i]->GetName();
}
return aRetSeq;
}
sal_Bool ModuleContainer_Impl::hasByName( const OUString& aName )
{
SbModule* pMod = mpLib ? mpLib->FindModule( aName ) : nullptr;
bool bRet = (pMod != nullptr);
return bRet;
}
// Methods XNameReplace
void ModuleContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
{
removeByName( aName );
insertByName( aName, aElement );
}
// Methods XNameContainer
void ModuleContainer_Impl::insertByName( const OUString& aName, const uno::Any& aElement )
{
uno::Type aModuleType = cppu::UnoType<script::XStarBasicModuleInfo>::get();
const uno::Type& aAnyType = aElement.getValueType();
if( aModuleType != aAnyType )
{
throw lang::IllegalArgumentException(u"types do not match"_ustr, getXWeak(), 2);
}
uno::Reference< script::XStarBasicModuleInfo > xMod;
aElement >>= xMod;
mpLib->MakeModule( aName, xMod->getSource() );
}
void ModuleContainer_Impl::removeByName( const OUString& Name )
{
SbModule* pMod = mpLib ? mpLib->FindModule( Name ) : nullptr;
if( !pMod )
{
throw container::NoSuchElementException();
}
mpLib->Remove( pMod );
}
static uno::Sequence< sal_Int8 > implGetDialogData( SbxObject* pDialog )
{
SvMemoryStream aMemStream;
pDialog->Store( aMemStream );
sal_Int32 nLen = aMemStream.Tell();
if (nLen < 0) { abort(); }
uno::Sequence< sal_Int8 > aData( nLen );
sal_Int8* pDestData = aData.getArray();
const sal_Int8* pSrcData = static_cast<const sal_Int8*>(aMemStream.GetData());
memcpy( pDestData, pSrcData, nLen );
return aData;
}
static SbxObjectRef implCreateDialog( const uno::Sequence< sal_Int8 >& aData )
{
sal_Int8* pData = const_cast< uno::Sequence< sal_Int8 >& >(aData).getArray();
SvMemoryStream aMemStream( pData, aData.getLength(), StreamMode::READ );
SbxBaseRef pBase = SbxBase::Load( aMemStream );
return dynamic_cast<SbxObject*>(pBase.get());
}
// HACK! Because this value is defined in basctl/inc/vcsbxdef.hxx
// which we can't include here, we have to use the value directly
#define SBXID_DIALOG 101
namespace {
class DialogContainer_Impl : public NameContainerHelper
{
StarBASIC* mpLib;
public:
explicit DialogContainer_Impl( StarBASIC* pLib )
:mpLib( pLib ) {}
// Methods XElementAccess
virtual uno::Type SAL_CALL getElementType() override;
virtual sal_Bool SAL_CALL hasElements() override;
// Methods XNameAccess
virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
// Methods XNameReplace
virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
// Methods XNameContainer
virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
virtual void SAL_CALL removeByName( const OUString& Name ) override;
};
}
// Methods XElementAccess
uno::Type DialogContainer_Impl::getElementType()
{
uno::Type aModuleType = cppu::UnoType<script::XStarBasicDialogInfo>::get();
return aModuleType;
}
sal_Bool DialogContainer_Impl::hasElements()
{
bool bRet = false;
sal_Int32 nCount = mpLib->GetObjects()->Count();
for( sal_Int32 nObj = 0; nObj < nCount ; nObj++ )
{
SbxVariable* pVar = mpLib->GetObjects()->Get( nObj );
SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
if ( pObj && (pObj->GetSbxId() == SBXID_DIALOG ) )
{
bRet = true;
break;
}
}
return bRet;
}
// Methods XNameAccess
uno::Any DialogContainer_Impl::getByName( const OUString& aName )
{
SbxVariable* pVar = mpLib->GetObjects()->Find( aName, SbxClassType::DontCare );
SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
if( !( pObj && pObj->GetSbxId() == SBXID_DIALOG ) )
{
throw container::NoSuchElementException();
}
uno::Reference< script::XStarBasicDialogInfo > xDialog =
new DialogInfo_Impl(aName, implGetDialogData(pObj));
uno::Any aRetAny;
aRetAny <<= xDialog;
return aRetAny;
}
uno::Sequence< OUString > DialogContainer_Impl::getElementNames()
{
sal_Int32 nCount = mpLib->GetObjects()->Count();
uno::Sequence< OUString > aRetSeq( nCount );
OUString* pRetSeq = aRetSeq.getArray();
sal_Int32 nDialogCounter = 0;
for( sal_Int32 nObj = 0; nObj < nCount ; nObj++ )
{
SbxVariable* pVar = mpLib->GetObjects()->Get( nObj );
SbxObject* pObj = dynamic_cast<SbxObject*> (pVar);
if ( pObj && ( pObj->GetSbxId() == SBXID_DIALOG ) )
{
pRetSeq[ nDialogCounter ] = pVar->GetName();
nDialogCounter++;
}
}
aRetSeq.realloc( nDialogCounter );
return aRetSeq;
}
sal_Bool DialogContainer_Impl::hasByName( const OUString& aName )
{
bool bRet = false;
SbxVariable* pVar = mpLib->GetObjects()->Find( aName, SbxClassType::DontCare );
SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
if( pObj && ( pObj->GetSbxId() == SBXID_DIALOG ) )
{
bRet = true;
}
return bRet;
}
// Methods XNameReplace
void DialogContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
{
removeByName( aName );
insertByName( aName, aElement );
}
// Methods XNameContainer
void DialogContainer_Impl::insertByName( const OUString&, const uno::Any& aElement )
{
uno::Type aModuleType = cppu::UnoType<script::XStarBasicDialogInfo>::get();
const uno::Type& aAnyType = aElement.getValueType();
if( aModuleType != aAnyType )
{
throw lang::IllegalArgumentException(u"types do not match"_ustr, getXWeak(), 2);
}
uno::Reference< script::XStarBasicDialogInfo > xMod;
aElement >>= xMod;
SbxObjectRef xDialog = implCreateDialog( xMod->getData() );
mpLib->Insert( xDialog.get() );
}
void DialogContainer_Impl::removeByName( const OUString& Name )
{
SbxVariable* pVar = mpLib->GetObjects()->Find( Name, SbxClassType::DontCare );
SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
if( !( pObj && ( pObj->GetSbxId() == SBXID_DIALOG ) ) )
{
throw container::NoSuchElementException();
}
mpLib->Remove( pVar );
}
class LibraryContainer_Impl : public NameContainerHelper
{
BasicManager* mpMgr;
public:
explicit LibraryContainer_Impl( BasicManager* pMgr )
:mpMgr( pMgr ) {}
// Methods XElementAccess
virtual uno::Type SAL_CALL getElementType() override;
virtual sal_Bool SAL_CALL hasElements() override;
// Methods XNameAccess
virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
// Methods XNameReplace
virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
// Methods XNameContainer
virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
virtual void SAL_CALL removeByName( const OUString& Name ) override;
};
// Methods XElementAccess
uno::Type LibraryContainer_Impl::getElementType()
{
uno::Type aType = cppu::UnoType<script::XStarBasicLibraryInfo>::get();
return aType;
}
sal_Bool LibraryContainer_Impl::hasElements()
{
sal_Int32 nLibs = mpMgr->GetLibCount();
bool bRet = (nLibs > 0);
return bRet;
}
// Methods XNameAccess
uno::Any LibraryContainer_Impl::getByName( const OUString& aName )
{
uno::Any aRetAny;
if( !mpMgr->HasLib( aName ) )
throw container::NoSuchElementException();
StarBASIC* pLib = mpMgr->GetLib( aName );
uno::Reference< container::XNameContainer > xModuleContainer =
new ModuleContainer_Impl( pLib );
uno::Reference< container::XNameContainer > xDialogContainer =
new DialogContainer_Impl( pLib );
BasicLibInfo* pLibInfo = mpMgr->FindLibInfo( pLib );
OUString aPassword = pLibInfo->GetPassword();
// TODO Only provide extern info!
OUString aExternaleSourceURL;
OUString aLinkTargetURL;
if( pLibInfo->IsReference() )
{
aLinkTargetURL = pLibInfo->GetStorageName();
}
else if( pLibInfo->IsExtern() )
{
aExternaleSourceURL = pLibInfo->GetStorageName();
}
uno::Reference< script::XStarBasicLibraryInfo > xLibInfo = new LibraryInfo_Impl
(
aName,
xModuleContainer,
xDialogContainer,
aPassword,
aExternaleSourceURL,
aLinkTargetURL
);
aRetAny <<= xLibInfo;
return aRetAny;
}
uno::Sequence< OUString > LibraryContainer_Impl::getElementNames()
{
sal_uInt16 nLibs = mpMgr->GetLibCount();
uno::Sequence< OUString > aRetSeq( nLibs );
OUString* pRetSeq = aRetSeq.getArray();
for( sal_uInt16 i = 0 ; i < nLibs ; i++ )
{
pRetSeq[i] = mpMgr->GetLibName( i );
}
return aRetSeq;
}
sal_Bool LibraryContainer_Impl::hasByName( const OUString& aName )
{
bool bRet = mpMgr->HasLib( aName );
return bRet;
}
// Methods XNameReplace
void LibraryContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
{
removeByName( aName );
insertByName( aName, aElement );
}
// Methods XNameContainer
void LibraryContainer_Impl::insertByName( const OUString&, const uno::Any& )
{
// TODO: Insert a complete Library?!
}
void LibraryContainer_Impl::removeByName( const OUString& Name )
{
StarBASIC* pLib = mpMgr->GetLib( Name );
if( !pLib )
{
throw container::NoSuchElementException();
}
sal_uInt16 nLibId = mpMgr->GetLibId( Name );
mpMgr->RemoveLib( nLibId );
}
typedef WeakImplHelper< script::XStarBasicAccess > StarBasicAccessHelper;
class StarBasicAccess_Impl : public StarBasicAccessHelper
{
BasicManager* mpMgr;
rtl::Reference< LibraryContainer_Impl > mxLibContainer;
public:
explicit StarBasicAccess_Impl( BasicManager* pMgr )
:mpMgr( pMgr ) {}
public:
// Methods
virtual uno::Reference< container::XNameContainer > SAL_CALL getLibraryContainer() override;
virtual void SAL_CALL createLibrary( const OUString& LibName, const OUString& Password,
const OUString& ExternalSourceURL, const OUString& LinkTargetURL ) override;
virtual void SAL_CALL addModule( const OUString& LibraryName, const OUString& ModuleName,
const OUString& Language, const OUString& Source ) override;
virtual void SAL_CALL addDialog( const OUString& LibraryName, const OUString& DialogName,
const uno::Sequence< sal_Int8 >& Data ) override;
};
uno::Reference< container::XNameContainer > SAL_CALL StarBasicAccess_Impl::getLibraryContainer()
{
if( !mxLibContainer.is() )
mxLibContainer = new LibraryContainer_Impl( mpMgr );
return mxLibContainer;
}
void SAL_CALL StarBasicAccess_Impl::createLibrary
(
const OUString& LibName,
const OUString& Password,
const OUString&,
const OUString& LinkTargetURL
)
{
StarBASIC* pLib = mpMgr->CreateLib( LibName, Password, LinkTargetURL );
DBG_ASSERT( pLib, "XML Import: Basic library could not be created");
}
void SAL_CALL StarBasicAccess_Impl::addModule
(
const OUString& LibraryName,
const OUString& ModuleName,
const OUString&,
const OUString& Source
)
{
StarBASIC* pLib = mpMgr->GetLib( LibraryName );
DBG_ASSERT( pLib, "XML Import: Lib for module unknown");
if( pLib )
{
pLib->MakeModule( ModuleName, Source );
}
}
void SAL_CALL StarBasicAccess_Impl::addDialog
(
const OUString&,
const OUString&,
const uno::Sequence< sal_Int8 >&
)
{}
// Basic XML Import/Export
uno::Reference< script::XStarBasicAccess > getStarBasicAccess( BasicManager* pMgr )
{
uno::Reference< script::XStarBasicAccess > xRet =
new StarBasicAccess_Impl( pMgr );
return xRet;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */