don't load the document Basic to parse formula names during ODF import

While macros are not yet allowed, a called name is kept as a macro
call if the document has Basic libraries at all.

A cell macro call now decides the macro mode before it loads the
document Basic.

Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: I2f33b51490db8515cd74d5e753bb9a18c5e6a587
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/13626
Reviewed-by: Noel Grandin <noel.grandin@collabora.com>
(cherry picked from commit d17fd31994d71c28f503bb3cc93471c307756627)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211523
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Caolán McNamara
2026-09-30 08:44:12 +02:00
committed by Xisco Fauli
parent b693937e99
commit 51744f6265
5 changed files with 69 additions and 27 deletions
+3
View File
@@ -438,6 +438,9 @@ public:
*/
bool AdjustMacroMode();
/// whether macros from this document are already allowed to run, without asking
bool IsMacroExecutionAllowed() const;
static bool UnTrustedScript(const OUString& rScriptURL);
/// Check if script URL whitelist exists, and if so, if current script url is part of it
+1 -1
View File
@@ -362,7 +362,7 @@ private:
bool ParseDoubleReference( const OUString& rSymbol, const OUString* pErrRef = nullptr );
bool ParsePredetectedReference( const OUString& rSymbol );
bool ParsePredetectedErrRefReference( const OUString& rName, const OUString* pErrRef );
bool ParseMacro( const OUString& );
bool ParseMacro( const OUString&, bool bParenFollows );
bool ParseNamedRange( const OUString&, bool onlyCheck = false );
bool ParseLocalName( const OUString& );
bool ParseExternalNamedRange( const OUString& rSymbol, bool& rbInvalidExternalNameRange );
+7 -2
View File
@@ -62,8 +62,13 @@ ScMacroFunction::ScMacroFunction(const ScInterpreter& rInterpreter, const OUStri
return;
}
// The macro security prompt is not raised here. CallBasic checks it when
// the macro actually runs.
// The macro mode is decided before the document's Basic is loaded.
if (!mpDocShell->AdjustMacroMode())
{
mbInvalid = true;
mnError = FormulaError::NoMacro;
return;
}
// Find the Basic method by name, then keep the library and macro name
// strings that CallBasic needs to invoke it.
+53 -24
View File
@@ -25,6 +25,7 @@
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <sfx2/app.hxx>
#include <sfx2/docmacromode.hxx>
#include <sfx2/objsh.hxx>
#include <basic/sbmeth.hxx>
#include <basic/sbstar.hxx>
@@ -3753,10 +3754,30 @@ bool ScCompiler::ParseReference( const OUString& rName, const OUString* pErrRef
return false;
}
bool ScCompiler::ParseMacro( const OUString& rName )
#if HAVE_FEATURE_SCRIPTING
static bool lcl_IsBasicFunction( StarBASIC& rBasic, const OUString& rName )
{
SbxMethod* pMeth = static_cast<SbxMethod*>(rBasic.Find( rName, SbxClassType::Method ));
if( !pMeth )
{
return false;
}
// It really should be a BASIC function!
if( pMeth->GetType() == SbxVOID
|| ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
|| dynamic_cast<const SbMethod*>( pMeth) == nullptr )
{
return false;
}
return true;
}
#endif
bool ScCompiler::ParseMacro( const OUString& rName, bool bParenFollows )
{
#if !HAVE_FEATURE_SCRIPTING
(void) rName;
(void) bParenFollows;
return false;
#else
@@ -3780,9 +3801,36 @@ bool ScCompiler::ParseMacro( const OUString& rName )
}
OUString aName( rName);
// ODFF recommends to store user-defined functions prefixed with "USER.",
// use only unprefixed name if encountered. BASIC doesn't allow '.' in a
// function name so a function "USER.FOO" could not exist, and macro check
// is assigned the lowest priority in function name check.
if (FormulaGrammar::isODFF( GetGrammar()) && aName.startsWithIgnoreAsciiCase("USER."))
aName = aName.copy(5);
StarBASIC* pObj = nullptr;
ScDocShell* pDocSh = rDoc.GetDocumentShell();
// During ODF import the Basic of a document whose macros are not allowed yet stays unloaded.
// A called name that is not an application Basic function may be one of the document's own
// macros only if the document has Basic libraries. Such a call is kept as a macro call, and the
// document is flagged as calling macros.
if (pDocSh && rDoc.IsImportingXML() && !pDocSh->IsMacroExecutionAllowed())
{
if (!bParenFollows)
return false;
StarBASIC* pAppBasic = SfxApplication::GetBasic();
if (!pAppBasic || !lcl_IsBasicFunction(*pAppBasic, aName))
{
if (!sfx2::DocumentMacroMode::containerHasBasicMacros(pDocSh->GetBasicContainer()))
return false;
pDocSh->SetMacroCallsSeenWhileLoading();
}
maRawToken.SetExternal( aName );
maRawToken.eOp = ocMacro;
return true;
}
try
{
if( pDocSh )//XXX
@@ -3795,28 +3843,9 @@ bool ScCompiler::ParseMacro( const OUString& rName )
return false;
}
if (!pObj)
if (!pObj || !lcl_IsBasicFunction(*pObj, aName))
return false;
// ODFF recommends to store user-defined functions prefixed with "USER.",
// use only unprefixed name if encountered. BASIC doesn't allow '.' in a
// function name so a function "USER.FOO" could not exist, and macro check
// is assigned the lowest priority in function name check.
if (FormulaGrammar::isODFF( GetGrammar()) && aName.startsWithIgnoreAsciiCase("USER."))
aName = aName.copy(5);
SbxMethod* pMeth = static_cast<SbxMethod*>(pObj->Find( aName, SbxClassType::Method ));
if( !pMeth )
{
return false;
}
// It really should be a BASIC function!
if( pMeth->GetType() == SbxVOID
|| ( pMeth->IsFixed() && pMeth->GetType() == SbxEMPTY )
|| dynamic_cast<const SbMethod*>( pMeth) == nullptr )
{
return false;
}
maRawToken.SetExternal( aName );
maRawToken.eOp = ocMacro;
return true;
@@ -4960,7 +4989,7 @@ Label_Rewind:
if (!bParenFollows && ParseColRowName( aUpper ))
return true;
if (ParseMacro( aUpper ))
if (ParseMacro( aUpper, bParenFollows ))
return true;
if (ParseOpCode( aUpper, bInArray ))
@@ -5047,7 +5076,7 @@ Label_Rewind:
// the same user-defined function, so in the call position the macro
// takes priority over a same-named defined name. A plain name
// reference still resolves as the named range.
if (bMayBeName && bParenFollows && ParseMacro(aUpper))
if (bMayBeName && bParenFollows && ParseMacro(aUpper, bParenFollows))
return true;
if (ParseNamedRange( aUpper ))
@@ -5084,7 +5113,7 @@ Label_Rewind:
if (bMayBeName)
{
if (ParseMacro( aUpper ))
if (ParseMacro( aUpper, bParenFollows ))
return true;
if (ParseLocalName( aOrg ))
+5
View File
@@ -1742,6 +1742,11 @@ bool SfxObjectShell::AdjustMacroMode()
return pImpl->aMacroMode.adjustMacroMode( xInteraction );
}
bool SfxObjectShell::IsMacroExecutionAllowed() const
{
return pImpl->getCurrentMacroExecMode() == MacroExecMode::ALWAYS_EXECUTE_NO_WARN;
}
css::uno::Reference<css::awt::XWindow> SfxObjectShell::GetDialogParent( SfxMedium const * pLoadingMedium )
{
css::uno::Reference<css::awt::XWindow> xWindow;