tdf#119457 - check for a valid range name and cell reference

Change-Id: If23eda52142ba5e59cfd354f2177b1ac1727efaa
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113341
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index bb524a2..f7c6cecc 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -58,7 +58,7 @@ public:
        AbsPos     = 0x0080
    };

    enum IsNameValidType
    enum class IsNameValidType
    {
        NAME_VALID,
        NAME_INVALID_CELL_REF,
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index 6779ffa..c276f30 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -467,15 +467,15 @@ ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, co
     * ScfTools::ConvertToScDefinedName needs to be changed too. */
    char const a('.');
    if (rName.indexOf(a) != -1)
        return NAME_INVALID_BAD_STRING;
        return IsNameValidType::NAME_INVALID_BAD_STRING;
    sal_Int32 nPos = 0;
    sal_Int32 nLen = rName.getLength();
    if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::CharName ) )
        return NAME_INVALID_BAD_STRING;
        return IsNameValidType::NAME_INVALID_BAD_STRING;
    while ( nPos < nLen )
    {
        if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::Name ) )
            return NAME_INVALID_BAD_STRING;
            return IsNameValidType::NAME_INVALID_BAD_STRING;
    }
    ScAddress aAddr;
    ScRange aRange;
@@ -487,10 +487,10 @@ ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, co
        if (aRange.Parse(rName, rDoc, details) != ScRefFlags::ZERO ||
             aAddr.Parse(rName, rDoc, details) != ScRefFlags::ZERO )
        {
            return NAME_INVALID_CELL_REF;
            return IsNameValidType::NAME_INVALID_CELL_REF;
        }
    }
    return NAME_VALID;
    return IsNameValidType::NAME_VALID;
}

FormulaError ScRangeData::GetErrCode() const
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
index d69aac2..6303541 100644
--- a/sc/source/ui/app/inputwin.cxx
+++ b/sc/source/ui/app/inputwin.cxx
@@ -2349,7 +2349,8 @@ static ScNameInputType lcl_GetInputType( const OUString& rText )
            eRet = SC_NAME_INPUT_ROW;
        else if ( rDoc.GetTable( rText, nNameTab ) )
            eRet = SC_NAME_INPUT_SHEET;
        else if ( ScRangeData::IsNameValid( rText, rDoc ) == ScRangeData::NAME_VALID )     // nothing found, create new range?
        else if (ScRangeData::IsNameValid(rText, rDoc)
                 == ScRangeData::IsNameValidType::NAME_VALID) // nothing found, create new range?
        {
            if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
                eRet = SC_NAME_INPUT_DEFINE;
diff --git a/sc/source/ui/dbgui/dbnamdlg.cxx b/sc/source/ui/dbgui/dbnamdlg.cxx
index 361a4ba..4939663 100644
--- a/sc/source/ui/dbgui/dbnamdlg.cxx
+++ b/sc/source/ui/dbgui/dbnamdlg.cxx
@@ -402,7 +402,8 @@ IMPL_LINK_NOARG(ScDbNameDlg, AddBtnHdl, weld::Button&, void)
    if ( aNewName.isEmpty() || aNewArea.isEmpty() )
        return;

    if ( ScRangeData::IsNameValid( aNewName, rDoc ) == ScRangeData::NAME_VALID && aNewName != STR_DB_LOCAL_NONAME )
    if (ScRangeData::IsNameValid(aNewName, rDoc) == ScRangeData::IsNameValidType::NAME_VALID
        && aNewName != STR_DB_LOCAL_NONAME)
    {
        //  because editing can be done now, parsing is needed first
        ScRange aTmpRange;
diff --git a/sc/source/ui/namedlg/namedefdlg.cxx b/sc/source/ui/namedlg/namedefdlg.cxx
index 3f0905e..25ff6e1 100644
--- a/sc/source/ui/namedlg/namedefdlg.cxx
+++ b/sc/source/ui/namedlg/namedefdlg.cxx
@@ -138,14 +138,15 @@ bool ScNameDefDlg::IsNameValid()
        m_xFtInfo->set_label(maStrInfoDefault);
        return false;
    }
    else if ((eType = ScRangeData::IsNameValid( aName, mrDoc )) != ScRangeData::NAME_VALID)
    else if ((eType = ScRangeData::IsNameValid(aName, mrDoc))
             != ScRangeData::IsNameValidType::NAME_VALID)
    {
        m_xFtInfo->set_label_type(weld::LabelType::Error);
        if (eType == ScRangeData::NAME_INVALID_BAD_STRING)
        if (eType == ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING)
        {
            m_xFtInfo->set_label(maErrInvalidNameStr);
        }
        else if (eType == ScRangeData::NAME_INVALID_CELL_REF)
        else if (eType == ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF)
        {
            m_xFtInfo->set_label(maErrInvalidNameCellRefStr);
        }
diff --git a/sc/source/ui/namedlg/namedlg.cxx b/sc/source/ui/namedlg/namedlg.cxx
index 1b76dfa..977abd5 100644
--- a/sc/source/ui/namedlg/namedlg.cxx
+++ b/sc/source/ui/namedlg/namedlg.cxx
@@ -248,7 +248,7 @@ bool ScNameDlg::IsNameValid()

    ScRangeName* pRangeName = GetRangeName( aScope );

    if (ScRangeData::IsNameValid( aName, mrDoc ) != ScRangeData::NAME_VALID)
    if (ScRangeData::IsNameValid(aName, mrDoc) != ScRangeData::IsNameValidType::NAME_VALID)
    {
        m_xFtInfo->set_label_type(weld::LabelType::Error);
        m_xFtInfo->set_label(maErrInvalidNameStr);
diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx
index bc15ba83..a9fa465 100644
--- a/sc/source/ui/unoobj/nameuno.cxx
+++ b/sc/source/ui/unoobj/nameuno.cxx
@@ -483,22 +483,38 @@ void SAL_CALL ScNamedRangesObj::addNewByName( const OUString& aName,
    if (pDocShell)
    {
        ScDocument& rDoc = pDocShell->GetDocument();
        ScRangeName* pNames = GetRangeName_Impl();
        if (pNames && !pNames->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(aName)))
        // tdf#119457 - check for a valid range name and cell reference
        switch (ScRangeData::IsNameValid(aName, rDoc))
        {
            std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName( *pNames ));
            // GRAM_API for API compatibility.
            ScRangeData* pNew = new ScRangeData( rDoc, aName, aContent,
                                                aPos, nNewType,formula::FormulaGrammar::GRAM_API );
            if ( pNewRanges->insert(pNew) )
            {
                pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
                bDone = true;
            }
            else
            {
                pNew = nullptr;
            }
            case ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF:
                throw uno::RuntimeException(
                    "Invalid name. Reference to a cell, or a range of cells not allowed",
                    uno::Reference<uno::XInterface>(static_cast<::cppu::OWeakObject*>(this)));
                break;
            case ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING:
                throw uno::RuntimeException(
                    "Invalid name. Start with a letter, use only letters, numbers and underscore",
                    uno::Reference<uno::XInterface>(static_cast<::cppu::OWeakObject*>(this)));
                break;
            case ScRangeData::IsNameValidType::NAME_VALID:
                if (ScRangeName* pNames = GetRangeName_Impl();
                    pNames
                    && !pNames->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(aName)))
                {
                    std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName( *pNames ));
                    // GRAM_API for API compatibility.
                    ScRangeData* pNew = new ScRangeData( rDoc, aName, aContent,
                                                        aPos, nNewType,formula::FormulaGrammar::GRAM_API );
                    if ( pNewRanges->insert(pNew) )
                    {
                        pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
                        bDone = true;
                    }
                    else
                    {
                        pNew = nullptr;
                    }
                }
        }
    }

diff --git a/sc/source/ui/vba/vbanames.cxx b/sc/source/ui/vba/vbanames.cxx
index 79a7a80..7c145f8 100644
--- a/sc/source/ui/vba/vbanames.cxx
+++ b/sc/source/ui/vba/vbanames.cxx
@@ -104,12 +104,14 @@ ScVbaNames::Add( const css::uno::Any& Name ,
        NameLocal >>= sName;
    if ( !sName.isEmpty() )
    {
        if ( ScRangeData::IsNameValid( sName, getScDocument() )  != ScRangeData::NAME_VALID )
        if (ScRangeData::IsNameValid(sName, getScDocument())
            != ScRangeData::IsNameValidType::NAME_VALID)
        {
            const sal_Int32 nIndex{ sName.indexOf('!') };
            if (nIndex>=0)
                sName = sName.copy(nIndex+1);
            if ( ScRangeData::IsNameValid( sName, getScDocument() ) != ScRangeData::NAME_VALID )
            if (ScRangeData::IsNameValid(sName, getScDocument())
                != ScRangeData::IsNameValidType::NAME_VALID)
                throw uno::RuntimeException( "This Name is not valid ." );
        }
    }
diff --git a/test/source/sheet/xnamedranges.cxx b/test/source/sheet/xnamedranges.cxx
index 25726ca..e07911f 100644
--- a/test/source/sheet/xnamedranges.cxx
+++ b/test/source/sheet/xnamedranges.cxx
@@ -70,6 +70,13 @@ void XNamedRanges::testAddNewByName()
    xNamedRanges->addNewByName(aName5, "D5", aBaseAddress, nType);
    CPPUNIT_ASSERT_MESSAGE("Failed to create Namedrange Type ROW_HEADER",
                           xNamedRanges->hasByName(aName5));

    // tdf#119457 - check for a valid range name
    OUString aName6("type_INVALID_BAD_STRING.+:");
    CPPUNIT_ASSERT_THROW(xNamedRanges->addNewByName(aName6, "D6", aBaseAddress, 0),
                         uno::RuntimeException);
    CPPUNIT_ASSERT_MESSAGE("Created Namedrange with invalid name",
                           !xNamedRanges->hasByName(aName6));
}

void XNamedRanges::testAddNewFromTitles()