/* -*- 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 <scriptcont.hxx>
#include <com/sun/star/packages/WrongPasswordException.hpp>
#include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/io/XTruncate.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/task/ErrorCodeIOException.hpp>
#include <com/sun/star/script/ModuleType.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/storagehelper.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <sal/log.hxx>
#include <sot/storage.hxx>
// For password functionality
#include <tools/urlobj.hxx>
#include <o3tl/temporary.hxx>
#include <svtools/sfxecode.hxx>
#include <svtools/ehdl.hxx>
#include <basic/basmgr.hxx>
#include <basic/sbmod.hxx>
#include <basic/modsizeexceeded.hxx>
#include <xmlscript/xmlmod_imexp.hxx>
#include <com/sun/star/util/VetoException.hpp>
#include <memory>
namespace basic
{
using namespace com::sun::star::container;
using namespace com::sun::star::io;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
using namespace com::sun::star::lang;
using namespace com::sun::star::script;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star;
using namespace cppu;
// Implementation class SfxScriptLibraryContainer
OUString SfxScriptLibraryContainer::getInfoFileName() const
{
static constexpr OUStringLiteral script = u"script" ;
return script;
}
OUString SfxScriptLibraryContainer::getOldInfoFileName() const
{
static constexpr OUStringLiteral script = u"script" ;
return script;
}
OUString SfxScriptLibraryContainer::getLibElementFileExtension() const
{
static constexpr OUStringLiteral xba = u"xba" ;
return xba;
}
OUString SfxScriptLibraryContainer::getLibrariesDir() const
{
static constexpr OUStringLiteral sBasic = u"Basic" ;
return sBasic;
}
void SfxScriptLibraryContainer::setLibraryPassword( const OUString& rLibraryName, const OUString& rPassword )
{
try
{
SfxLibrary* pImplLib = getImplLib( rLibraryName );
if ( !rPassword.isEmpty() )
{
pImplLib->mbDoc50Password = true ;
pImplLib->mbPasswordProtected = true ;
pImplLib->maPassword = rPassword;
SfxScriptLibrary *const pSL(dynamic_cast <SfxScriptLibrary *>(pImplLib));
if (pSL && pSL->mbLoaded)
{
pSL->mbLoadedSource = true ; // must store source code now!
}
}
}
catch (const NoSuchElementException& ) {}
}
// Ctor for service
SfxScriptLibraryContainer::SfxScriptLibraryContainer()
{
// all initialisation has to be done
// by calling XInitialization::initialize
}
SfxScriptLibraryContainer::SfxScriptLibraryContainer( const uno::Reference< embed::XStorage >& xStorage )
{
init(OUString(), xStorage, o3tl::temporary(std::unique_lock(m_aMutex)));
}
// Methods to get library instances of the correct type
rtl::Reference<SfxLibrary> SfxScriptLibraryContainer::implCreateLibrary( const OUString& )
{
return new SfxScriptLibrary( maModifiable, mxSFI );
}
rtl::Reference<SfxLibrary> SfxScriptLibraryContainer::implCreateLibraryLink( const OUString&,
const OUString& aLibInfoFileURL,
const OUString& StorageURL,
bool ReadOnly )
{
return new SfxScriptLibrary( maModifiable, mxSFI,
aLibInfoFileURL, StorageURL, ReadOnly );
}
Any SfxScriptLibraryContainer::createEmptyLibraryElement()
{
Any aRetAny;
aRetAny <<= OUString();
return aRetAny;
}
bool SfxScriptLibraryContainer::isLibraryElementValid(const Any& rElement) const
{
return SfxScriptLibrary::containsValidModule(rElement);
}
void SfxScriptLibraryContainer::writeLibraryElement( const Reference < XNameContainer >& xLib,
const OUString& aElementName,
const Reference< XOutputStream >& xOutput)
{
// Create sax writer
Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
Reference< XTruncate > xTruncate( xOutput, UNO_QUERY );
OSL_ENSURE( xTruncate.is(), "Currently only the streams that can be truncated are expected!" );
if ( xTruncate.is() )
{
xTruncate->truncate();
}
xWriter->setOutputStream( xOutput );
xmlscript::ModuleDescriptor aMod;
aMod.aName = aElementName;
aMod.aLanguage = "StarBasic" ;
Any aElement = xLib->getByName( aElementName );
aElement >>= aMod.aCode;
Reference< script::vba::XVBAModuleInfo > xModInfo( xLib, UNO_QUERY );
if ( xModInfo.is() && xModInfo->hasModuleInfo( aElementName ) )
{
script::ModuleInfo aModInfo = xModInfo->getModuleInfo( aElementName );
switch ( aModInfo.ModuleType )
{
case ModuleType::NORMAL:
aMod.aModuleType = "normal" ;
break ;
case ModuleType::CLASS :
aMod.aModuleType ="class" ;
break ;
case ModuleType::FORM:
aMod.aModuleType = "form" ;
break ;
case ModuleType::DOCUMENT:
aMod.aModuleType = "document" ;
break ;
case ModuleType::UNKNOWN:
// nothing
break ;
}
}
xmlscript::exportScriptModule( xWriter, aMod );
}
Any SfxScriptLibraryContainer::importLibraryElement
( const Reference < XNameContainer >& xLib,
const OUString& aElementName, const OUString& aFile,
const uno::Reference< io::XInputStream >& xInStream )
{
Any aRetAny;
Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
// Read from storage?
bool bStorage = xInStream.is();
Reference< XInputStream > xInput;
if ( bStorage )
{
xInput = xInStream;
}
else
{
try
{
xInput = mxSFI->openFileRead( aFile );
}
catch (const Exception& )
//catch( Exception& e )
{
// TODO:
//throw WrappedTargetException( e );
}
}
if ( !xInput.is() )
return aRetAny;
InputSource source;
source.aInputStream = std::move(xInput);
source.sSystemId = aFile;
// start parsing
xmlscript::ModuleDescriptor aMod;
try
{
xParser->setDocumentHandler( ::xmlscript::importScriptModule( aMod ) );
xParser->parseStream( source );
}
catch (const Exception& )
{
SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFile );
ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
}
aRetAny <<= aMod.aCode;
// TODO: Check language
// aMod.aLanguage
// aMod.aName ignored
if ( !aMod.aModuleType.isEmpty() )
{
/* If in VBA compatibility mode, force creation of the VBA Globals
object . Each application will create an instance of its own
implementation and store it in its Basic manager . Implementations
will do all necessary additional initialization , such as
registering the global " This * * * Doc " UNO constant , starting the
document events processor etc .
*/
if ( getVBACompatibilityMode() ) try
{
Reference< frame::XModel > xModel( mxOwnerDocument ); // weak-ref -> ref
Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
xFactory->createInstance(u"ooo.vba.VBAGlobals" _ustr);
}
catch (const Exception& )
{
}
script::ModuleInfo aModInfo;
aModInfo.ModuleType = ModuleType::UNKNOWN;
if ( aMod.aModuleType == "normal" )
{
aModInfo.ModuleType = ModuleType::NORMAL;
}
else if ( aMod.aModuleType == "class" )
{
aModInfo.ModuleType = ModuleType::CLASS ;
}
else if ( aMod.aModuleType == "form" )
{
aModInfo.ModuleType = ModuleType::FORM;
aModInfo.ModuleObject = mxOwnerDocument;
}
else if ( aMod.aModuleType == "document" )
{
aModInfo.ModuleType = ModuleType::DOCUMENT;
// #163691# use the same codename access instance for all document modules
if ( !mxCodeNameAccess.is() ) try
{
Reference<frame::XModel > xModel( mxOwnerDocument );
Reference< XMultiServiceFactory> xSF( xModel, UNO_QUERY_THROW );
mxCodeNameAccess.set( xSF->createInstance(u"ooo.vba.VBAObjectModuleObjectProvider" _ustr), UNO_QUERY );
}
catch (const Exception& ) {}
if ( mxCodeNameAccess.is() )
{
try
{
aModInfo.ModuleObject.set( mxCodeNameAccess->getByName( aElementName), uno::UNO_QUERY );
}
catch (const uno::Exception&)
{
SAL_WARN("basic" , "Failed to get document object for " << aElementName );
}
}
}
Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
if ( xVBAModuleInfo.is() )
{
if ( xVBAModuleInfo->hasModuleInfo( aElementName ) )
{
xVBAModuleInfo->removeModuleInfo( aElementName );
}
xVBAModuleInfo->insertModuleInfo( aElementName, aModInfo );
}
}
return aRetAny;
}
rtl::Reference<SfxLibraryContainer> SfxScriptLibraryContainer::createInstanceImpl()
{
return new SfxScriptLibraryContainer();
}
void SfxScriptLibraryContainer::importFromOldStorage( const OUString& aFile )
{
// TODO: move loading from old storage to binary filters?
rtl::Reference<SotStorage> xStorage(new SotStorage(false , aFile));
if ( xStorage->GetError() == ERRCODE_NONE )
{
BasicManager aBasicManager( *xStorage, aFile );
// Set info
LibraryContainerInfo aInfo( this , nullptr, this );
aBasicManager.SetLibraryContainerInfo( aInfo );
}
}
// Storing with password encryption
// Methods XLibraryContainerPassword
sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordProtected( const OUString& Name )
{
LibraryContainerMethodGuard aGuard( *this );
SfxLibrary* pImplLib = getImplLib( Name );
bool bRet = pImplLib->mbPasswordProtected;
return bRet;
}
sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordVerified( const OUString& Name )
{
LibraryContainerMethodGuard aGuard( *this );
SfxLibrary* pImplLib = getImplLib( Name );
if ( !pImplLib->mbPasswordProtected )
{
throw IllegalArgumentException(u"!passwordProtected" _ustr, getXWeak(), 1 );
}
bool bRet = pImplLib->mbPasswordVerified;
return bRet;
}
sal_Bool SAL_CALL SfxScriptLibraryContainer::verifyLibraryPassword
( const OUString& Name, const OUString& Password )
{
LibraryContainerMethodGuard aGuard( *this );
std::unique_lock guard(m_aMutex);
SfxLibrary* pImplLib = getImplLib( Name );
if ( !pImplLib->mbPasswordProtected || pImplLib->mbPasswordVerified )
{
throw IllegalArgumentException(u"!PasswordProtected || PasswordVerified" _ustr, getXWeak(), 1 );
}
// Test password
bool bSuccess = false ;
if ( pImplLib->mbDoc50Password )
{
bSuccess = ( Password == pImplLib->maPassword );
if ( bSuccess )
{
pImplLib->mbPasswordVerified = true ;
}
}
else
{
pImplLib->maPassword = Password;
bSuccess = implLoadPasswordLibrary( pImplLib, Name, true , guard);
if ( bSuccess )
{
// The library gets modified by verifying the password, because other-
// wise for saving the storage would be copied and that doesn't work
// with mtg's storages when the password is verified
pImplLib->implSetModified(true , guard);
pImplLib->mbPasswordVerified = true ;
// Reload library to get source
if ( pImplLib->mbLoaded )
{
implLoadPasswordLibrary( pImplLib, Name, false , guard);
}
}
}
return bSuccess;
}
void SAL_CALL SfxScriptLibraryContainer::changeLibraryPassword( const OUString& Name,
const OUString& OldPassword,
const OUString& NewPassword )
{
LibraryContainerMethodGuard aGuard( *this );
SfxLibrary* pImplLib = getImplLib( Name );
if ( OldPassword == NewPassword )
{
return ;
}
bool bOldPassword = !OldPassword.isEmpty();
bool bNewPassword = !NewPassword.isEmpty();
bool bStorage = mxStorage.is() && !pImplLib->mbLink;
if ( pImplLib->mbReadOnly || (bOldPassword && !pImplLib->mbPasswordProtected) )
{
throw IllegalArgumentException();
}
// Library must be loaded
loadLibrary( Name );
bool bKillCryptedFiles = false ;
bool bKillUnencryptedFiles = false ;
// Remove or change password?
if ( bOldPassword )
{
if ( isLibraryPasswordVerified( Name ) )
{
if ( pImplLib->maPassword != OldPassword )
{
throw IllegalArgumentException();
}
}
else
{
if ( !verifyLibraryPassword( Name, OldPassword ) )
{
throw IllegalArgumentException();
}
// Reload library to get source
// Should be done in verifyLibraryPassword loadLibrary( Name );
}
if ( !bNewPassword )
{
pImplLib->mbPasswordProtected = false ;
pImplLib->mbPasswordVerified = false ;
pImplLib->maPassword.clear();
std::unique_lock guard(m_aMutex);
maModifiable.setModified(true , guard);
pImplLib->implSetModified(true , guard);
if ( !bStorage && !pImplLib->mbDoc50Password )
{
// Store application basic unencrypted
uno::Reference< embed::XStorage > xStorage;
storeLibraries_Impl(xStorage, false , guard);
bKillCryptedFiles = true ;
}
}
}
// Set new password?
if ( bNewPassword )
{
pImplLib->mbPasswordProtected = true ;
pImplLib->mbPasswordVerified = true ;
pImplLib->maPassword = NewPassword;
SfxScriptLibrary *const pSL(dynamic_cast <SfxScriptLibrary *>(pImplLib));
if (pSL && pSL->mbLoaded)
{
pSL->mbLoadedSource = true ; // must store source code now!
}
std::unique_lock guard(m_aMutex);
maModifiable.setModified(true , guard);
pImplLib->implSetModified(true , guard);
if ( !bStorage && !pImplLib->mbDoc50Password )
{
// Store application basic crypted
uno::Reference< embed::XStorage > xStorage;
storeLibraries_Impl(xStorage, false , guard);
bKillUnencryptedFiles = true ;
}
}
if ( !(bKillCryptedFiles || bKillUnencryptedFiles) )
return ;
Sequence< OUString > aElementNames = pImplLib->getElementNames();
sal_Int32 nNameCount = aElementNames.getLength();
const OUString* pNames = aElementNames.getConstArray();
OUString aLibDirPath = createAppLibraryFolder( pImplLib, Name );
try
{
for ( sal_Int32 i = 0 ; i < nNameCount ; i++ )
{
OUString aElementName = pNames[ i ];
INetURLObject aElementInetObj( aLibDirPath );
aElementInetObj.insertName( aElementName, false ,
INetURLObject::LAST_SEGMENT,
INetURLObject::EncodeMechanism::All );
if ( bKillUnencryptedFiles )
{
aElementInetObj.setExtension( maLibElementFileExtension );
}
else
{
aElementInetObj.setExtension( u"pba" );
}
OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
if ( mxSFI->exists( aElementPath ) )
{
mxSFI->kill( aElementPath );
}
}
}
catch (const Exception& ) {}
}
static void setStreamKey( const uno::Reference< io::XStream >& xStream, const OUString& aPass )
{
uno::Reference< embed::XEncryptionProtectedSource > xEncrStream( xStream, uno::UNO_QUERY );
if ( xEncrStream.is() )
{
xEncrStream->setEncryptionPassword( aPass );
}
}
// Impl methods
bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib,
const OUString& aName,
const uno::Reference< embed::XStorage >& xStorage,
const css::uno::Reference< css::task::XInteractionHandler >& xHandler )
{
Reference< XSimpleFileAccess3 > xDummySFA;
return implStorePasswordLibrary( pLib, aName, xStorage, OUString(), xDummySFA, xHandler );
}
bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib, const OUString& aName,
const css::uno::Reference< css::embed::XStorage >& xStorage,
const OUString& aTargetURL,
const Reference< XSimpleFileAccess3 >& rToUseSFI,
const css::uno::Reference< css::task::XInteractionHandler >& xHandler )
{
bool bExport = !aTargetURL.isEmpty();
BasicManager* pBasicMgr = getBasicManager();
OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implStorePasswordLibrary: cannot do this without a BasicManager!" );
if ( !pBasicMgr )
{
return false ;
}
// Only need to handle the export case here,
// save/saveas etc are handled in sfxbasemodel::storeSelf &
// sfxbasemodel::impl_store
std::vector<OUString> aNames;
if ( bExport && pBasicMgr->ImgVersion12PsswdBinaryLimitExceeded(aNames) )
{
if ( xHandler.is() )
{
rtl::Reference<ModuleSizeExceeded> pReq = new ModuleSizeExceeded( aNames );
xHandler->handle( pReq );
if ( pReq->isAbort() )
{
throw util::VetoException();
}
}
}
StarBASIC* pBasicLib = pBasicMgr->GetLib( aName );
if ( !pBasicLib )
{
return false ;
}
Sequence< OUString > aElementNames = pLib->getElementNames();
sal_Int32 nNameCount = aElementNames.getLength();
const OUString* pNames = aElementNames.getConstArray();
bool bLink = pLib->mbLink;
bool bStorage = xStorage.is() && !bLink;
if ( bStorage )
{
for ( sal_Int32 i = 0 ; i < nNameCount ; i++ )
{
OUString aElementName = pNames[ i ];
// Write binary image stream
SbModule* pMod = pBasicLib->FindModule( aElementName );
if ( pMod )
{
OUString aCodeStreamName = aElementName + ".bin" ;
try
{
uno::Reference< io::XStream > xCodeStream = xStorage->openStreamElement(
aCodeStreamName,
embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
if ( !xCodeStream.is() )
{
throw uno::RuntimeException(u"null returned from openStreamElement" _ustr);
}
SvMemoryStream aMemStream;
/*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
sal_Int32 const nSize = aMemStream.Tell();
if (nSize < 0 ) { abort(); }
Sequence< sal_Int8 > aBinSeq( nSize );
sal_Int8* pData = aBinSeq.getArray();
memcpy( pData, aMemStream.GetData(), nSize );
Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
if ( !xOut.is() )
{
throw io::IOException(); // access denied because the stream is readonly
}
xOut->writeBytes( aBinSeq );
xOut->closeOutput();
}
catch (const uno::Exception& )
{
// TODO: handle error
}
}
if ( pLib->mbPasswordVerified || pLib->mbDoc50Password )
{
if ( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
{
SAL_WARN( "basic" , "invalid library element '" << aElementName << "'." );
continue ;
}
OUString aSourceStreamName = aElementName + ".xml" ;
try
{
uno::Reference< io::XStream > xSourceStream = xStorage->openStreamElement(
aSourceStreamName,
embed::ElementModes::READWRITE );
uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY_THROW );
xProps->setPropertyValue(u"MediaType" _ustr, uno::Any( u"text/xml" _ustr ) );
// Set encryption key
setStreamKey( xSourceStream, pLib->maPassword );
Reference< XOutputStream > xOutput = xSourceStream->getOutputStream();
Reference< XNameContainer > xLib( pLib );
writeLibraryElement( xLib, aElementName, xOutput );
}
catch (const uno::Exception& )
{
OSL_FAIL( "Problem on storing of password library!" );
// TODO: error handling
}
}
else // !mbPasswordVerified
{
// TODO
// What to do if not verified?! In any case it's already loaded here
}
}
}
// Application libraries have only to be saved if the password
// is verified because otherwise they can't be modified
else if ( pLib->mbPasswordVerified || bExport )
{
try
{
Reference< XSimpleFileAccess3 > xSFI = mxSFI;
if ( rToUseSFI.is() )
{
xSFI = rToUseSFI;
}
OUString aLibDirPath;
if ( bExport )
{
INetURLObject aInetObj( aTargetURL );
aInetObj.insertName( aName, true , INetURLObject::LAST_SEGMENT,
INetURLObject::EncodeMechanism::All );
aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
if ( !xSFI->isFolder( aLibDirPath ) )
{
xSFI->createFolder( aLibDirPath );
}
}
else
{
aLibDirPath = createAppLibraryFolder( pLib, aName );
}
for ( sal_Int32 i = 0 ; i < nNameCount ; i++ )
{
OUString aElementName = pNames[ i ];
INetURLObject aElementInetObj( aLibDirPath );
aElementInetObj.insertName( aElementName, false ,
INetURLObject::LAST_SEGMENT,
INetURLObject::EncodeMechanism::All );
aElementInetObj.setExtension( u"pba" );
OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
if ( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
{
SAL_WARN( "basic" , "invalid library element '" << aElementName << "'." );
continue ;
}
try
{
uno::Reference< embed::XStorage > xElementRootStorage =
::comphelper::OStorageHelper::GetStorageFromURL(
aElementPath,
embed::ElementModes::READWRITE );
if ( !xElementRootStorage.is() )
{
throw uno::RuntimeException(u"null returned from GetStorageFromURL" _ustr);
}
// Write binary image stream
SbModule* pMod = pBasicLib->FindModule( aElementName );
if ( pMod )
{
uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
u"code.bin" _ustr,
embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
SvMemoryStream aMemStream;
/*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
sal_Int32 const nSize = aMemStream.Tell();
if (nSize < 0 ) { abort(); }
Sequence< sal_Int8 > aBinSeq( nSize );
sal_Int8* pData = aBinSeq.getArray();
memcpy( pData, aMemStream.GetData(), nSize );
Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
if ( xOut.is() )
{
xOut->writeBytes( aBinSeq );
xOut->closeOutput();
}
}
// Write encrypted source stream
OUString aSourceStreamName( u"source.xml" _ustr );
uno::Reference< io::XStream > xSourceStream;
try
{
xSourceStream = xElementRootStorage->openStreamElement(
aSourceStreamName,
embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
// #87671 Allow encryption
uno::Reference< embed::XEncryptionProtectedSource > xEncr( xSourceStream, uno::UNO_QUERY_THROW );
xEncr->setEncryptionPassword( pLib->maPassword );
}
catch (const css::packages::WrongPasswordException& )
{
xSourceStream = xElementRootStorage->openEncryptedStreamElement(
aSourceStreamName,
embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE,
pLib->maPassword );
}
uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY_THROW );
xProps->setPropertyValue(u"MediaType" _ustr, uno::Any( u"text/xml" _ustr ) );
Reference< XOutputStream > xOut = xSourceStream->getOutputStream();
Reference< XNameContainer > xLib( pLib );
writeLibraryElement( xLib, aElementName, xOut );
// i50568: sax writer already closes stream
// xOut->closeOutput();
uno::Reference< embed::XTransactedObject > xTransact( xElementRootStorage, uno::UNO_QUERY_THROW );
xTransact->commit();
}
catch (const uno::Exception& )
{
// TODO: handle error
}
}
}
catch (const Exception& )
{
}
}
return true ;
}
bool SfxScriptLibraryContainer::implLoadPasswordLibrary
( SfxLibrary* pLib, const OUString& Name, bool bVerifyPasswordOnly, std::unique_lock<std::mutex>& guard )
{
bool bRet = true ;
bool bLink = pLib->mbLink;
bool bStorage = mxStorage.is() && !bLink;
// Already loaded? Then only verifiedPassword can change something
SfxScriptLibrary* pScriptLib = static_cast < SfxScriptLibrary* >( pLib );
if ( pScriptLib->mbLoaded )
{
if ( pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly &&
(pScriptLib->mbLoadedSource || !pLib->mbPasswordVerified) )
{
return false ;
}
}
StarBASIC* pBasicLib = nullptr;
bool bLoadBinary = false ;
if ( !pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly && !pLib->mbPasswordVerified )
{
BasicManager* pBasicMgr = getBasicManager();
OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implLoadPasswordLibrary: cannot do this without a BasicManager!" );
bool bLoaded = pScriptLib->mbLoaded;
pScriptLib->mbLoaded = true ; // Necessary to get lib
pBasicLib = pBasicMgr ? pBasicMgr->GetLib( Name ) : nullptr;
pScriptLib->mbLoaded = bLoaded; // Restore flag
if ( !pBasicLib )
{
return false ;
}
bLoadBinary = true ;
pScriptLib->mbLoadedBinary = true ;
}
bool bLoadSource = false ;
if ( !pScriptLib->mbLoadedSource && pLib->mbPasswordVerified && !bVerifyPasswordOnly )
{
bLoadSource = true ;
pScriptLib->mbLoadedSource = true ;
}
Sequence< OUString > aElementNames = pLib->getElementNames();
sal_Int32 nNameCount = aElementNames.getLength();
const OUString* pNames = aElementNames.getConstArray();
if ( bStorage )
{
uno::Reference< embed::XStorage > xLibrariesStor;
uno::Reference< embed::XStorage > xLibraryStor;
try {
xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
if ( !xLibrariesStor.is() )
{
throw uno::RuntimeException(u"null returned from openStorageElement" _ustr);
}
xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
if ( !xLibraryStor.is() )
{
throw uno::RuntimeException(u"null returned from openStorageElement" _ustr);
}
}
catch (const uno::Exception& )
{
OSL_FAIL( "### couldn't open sub storage for library" );
return false ;
}
for ( sal_Int32 i = 0 ; i < nNameCount ; i++ )
{
OUString aElementName = pNames[ i ];
// Load binary
if ( bLoadBinary )
{
SbModule* pMod = pBasicLib->FindModule( aElementName );
if ( !pMod )
{
pMod = pBasicLib->MakeModule( aElementName, OUString() );
pBasicLib->SetModified( false );
}
OUString aCodeStreamName= aElementName + ".bin" ;
try
{
uno::Reference< io::XStream > xCodeStream = xLibraryStor->openStreamElement(
aCodeStreamName,
embed::ElementModes::READ );
if ( !xCodeStream.is() )
{
throw uno::RuntimeException(u"null returned from openStreamElement" _ustr);
}
std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
if ( !pStream || pStream->GetError() )
{
sal_uInt32 nError = sal_uInt32(pStream ? pStream->GetError() : ERRCODE_IO_GENERAL);
throw task::ErrorCodeIOException(
("utl::UcbStreamHelper::CreateStream failed for \" "
+ aCodeStreamName + "\" : 0 x"
+ OUString::number(nError, 16 )),
uno::Reference< uno::XInterface >(), nError);
}
/*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
// TODO: Check return value
}
catch (const uno::Exception& )
{
// TODO: error handling
}
}
// Load source
if ( bLoadSource || bVerifyPasswordOnly )
{
// Access encrypted source stream
OUString aSourceStreamName = aElementName + ".xml" ;
try
{
uno::Reference< io::XStream > xSourceStream = xLibraryStor->openEncryptedStreamElement(
aSourceStreamName,
embed::ElementModes::READ,
pLib->maPassword );
if ( !xSourceStream.is() )
{
throw uno::RuntimeException(u"null returned from openEncryptedStreamElement" _ustr);
}
// if this point is reached then the password is correct
if ( !bVerifyPasswordOnly )
{
uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
if ( !xInStream.is() )
{
throw io::IOException(); // read access denied, seems to be impossible
}
Reference< XNameContainer > xLib( pLib );
Any aAny = importLibraryElement( xLib,
aElementName, aSourceStreamName,
xInStream );
if ( pLib->hasByName( aElementName ) )
{
if ( aAny.hasValue() )
{
pLib->maNameContainer.replaceByName(aElementName, aAny, guard);
}
}
else
{
pLib->maNameContainer.insertByName(aElementName, aAny, guard);
}
}
}
catch (const uno::Exception& )
{
bRet = false ;
}
}
}
}
else
{
try
{
OUString aLibDirPath = createAppLibraryFolder( pLib, Name );
for ( sal_Int32 i = 0 ; i < nNameCount ; i++ )
{
OUString aElementName = pNames[ i ];
INetURLObject aElementInetObj( aLibDirPath );
aElementInetObj.insertName( aElementName, false ,
INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
aElementInetObj.setExtension( u"pba" );
OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
uno::Reference< embed::XStorage > xElementRootStorage;
try
{
xElementRootStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
aElementPath,
embed::ElementModes::READ );
} catch (const uno::Exception& )
{
// TODO: error handling
}
if ( xElementRootStorage.is() )
{
// Load binary
if ( bLoadBinary )
{
SbModule* pMod = pBasicLib->FindModule( aElementName );
if ( !pMod )
{
pMod = pBasicLib->MakeModule( aElementName, OUString() );
pBasicLib->SetModified( false );
}
try
{
uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
u"code.bin" _ustr,
embed::ElementModes::READ );
std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
if ( !pStream || pStream->GetError() )
{
sal_uInt32 nError = sal_uInt32(pStream ? pStream->GetError() : ERRCODE_IO_GENERAL);
throw task::ErrorCodeIOException(
("utl::UcbStreamHelper::CreateStream failed"
" for code.bin: 0x"
+ OUString::number(nError, 16 )),
uno::Reference< uno::XInterface >(),
nError);
}
/*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
// TODO: Check return value
}
catch (const uno::Exception& )
{
// TODO: error handling
}
}
// Load source
if ( bLoadSource || bVerifyPasswordOnly )
{
// Access encrypted source stream
try
{
OUString aSourceStreamName( u"source.xml" _ustr );
uno::Reference< io::XStream > xSourceStream = xElementRootStorage->openEncryptedStreamElement(
aSourceStreamName,
embed::ElementModes::READ,
pLib->maPassword );
if ( !xSourceStream.is() )
{
throw uno::RuntimeException(u"null returned from openEncryptedStreamElement" _ustr);
}
if ( !bVerifyPasswordOnly )
{
uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
if ( !xInStream.is() )
{
throw io::IOException(); // read access denied, seems to be impossible
}
Reference< XNameContainer > xLib( pLib );
Any aAny = importLibraryElement( xLib,
aElementName,
aSourceStreamName,
xInStream );
if ( pLib->hasByName( aElementName ) )
{
if ( aAny.hasValue() )
{
pLib->maNameContainer.replaceByName(aElementName, aAny,
guard);
}
}
else
{
pLib->maNameContainer.insertByName(aElementName, aAny, guard);
}
}
}
catch (const uno::Exception& )
{
bRet = false ;
}
}
}
}
}
catch (const Exception& )
{
// TODO
//throw e;
}
}
return bRet;
}
void SfxScriptLibraryContainer::onNewRootStorage()
{
}
sal_Bool SAL_CALL SfxScriptLibraryContainer:: HasExecutableCode( const OUString& Library )
{
BasicManager* pBasicMgr = getBasicManager();
OSL_ENSURE( pBasicMgr, "we need a basicmanager, really we do" );
if ( pBasicMgr )
{
return pBasicMgr->HasExeCode( Library ); // need to change this to take name
}
// default to it has code if we can't decide
return true ;
}
// Service
OUString SAL_CALL SfxScriptLibraryContainer::getImplementationName( )
{
return u"com.sun.star.comp.sfx2.ScriptLibraryContainer" _ustr;
}
Sequence< OUString > SAL_CALL SfxScriptLibraryContainer::getSupportedServiceNames( )
{
return {u"com.sun.star.script.DocumentScriptLibraryContainer" _ustr,
u"com.sun.star.script.ScriptLibraryContainer" _ustr}; // for compatibility
}
// Implementation class SfxScriptLibrary
// Ctor
SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
const Reference< XSimpleFileAccess3 >& xSFI )
: SfxScriptLibrary_BASE(_rModifiable, cppu::UnoType<OUString>::get(), xSFI)
, mbLoadedSource( false )
, mbLoadedBinary( false )
{
}
SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
const Reference< XSimpleFileAccess3 >& xSFI,
const OUString& aLibInfoFileURL,
const OUString& aStorageURL,
bool ReadOnly )
: SfxScriptLibrary_BASE(_rModifiable, cppu::UnoType<OUString>::get(), xSFI,
aLibInfoFileURL, aStorageURL, ReadOnly)
, mbLoadedSource( false )
, mbLoadedBinary( false )
{
}
bool SfxScriptLibrary::isLoadedStorable()
{
// note: mbLoadedSource can only be true for password-protected lib!
return SfxLibrary::isLoadedStorable() && (!isPasswordProtected() || mbLoadedSource);
}
// Provide modify state including resources
bool SfxScriptLibrary::isModified()
{
return implIsModified(); // No resources
}
void SfxScriptLibrary::storeResources()
{
// No resources
}
void SfxScriptLibrary::storeResourcesToURL( const OUString&,
const Reference< task::XInteractionHandler >& )
{}
void SfxScriptLibrary::storeResourcesAsURL
( const OUString&, const OUString& )
{}
void SfxScriptLibrary::storeResourcesToStorage( const css::uno::Reference
< css::embed::XStorage >& )
{
// No resources
}
bool SfxScriptLibrary::containsValidModule(const Any& rElement)
{
OUString sModuleText;
rElement >>= sModuleText;
return ( !sModuleText.isEmpty() );
}
bool SfxScriptLibrary::isLibraryElementValid(const css::uno::Any& rElement) const
{
return SfxScriptLibrary::containsValidModule(rElement);
}
script::ModuleInfo SAL_CALL SfxScriptLibrary::getModuleInfo( const OUString& ModuleName )
{
if ( !hasModuleInfo( ModuleName ) )
{
throw NoSuchElementException();
}
return mModuleInfo[ ModuleName ];
}
sal_Bool SAL_CALL SfxScriptLibrary::hasModuleInfo( const OUString& ModuleName )
{
bool bRes = false ;
ModuleInfoMap::iterator it = mModuleInfo.find( ModuleName );
if ( it != mModuleInfo.end() )
{
bRes = true ;
}
return bRes;
}
void SAL_CALL SfxScriptLibrary::insertModuleInfo( const OUString& ModuleName, const script::ModuleInfo& ModuleInfo )
{
if ( hasModuleInfo( ModuleName ) )
{
throw ElementExistException();
}
mModuleInfo[ ModuleName ] = ModuleInfo;
}
void SAL_CALL SfxScriptLibrary::removeModuleInfo( const OUString& ModuleName )
{
// #FIXME add NoSuchElementException to the spec
if ( mModuleInfo.erase( ModuleName ) == 0 )
throw NoSuchElementException();
}
} // namespace basic
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_sfx2_ScriptLibraryContainer_get_implementation(css::uno::XComponentContext*,
css::uno::Sequence<css::uno::Any> const &)
{
return cppu::acquire(new basic::SfxScriptLibraryContainer());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=96 H=98 G=96
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland