tdf#89281 fix performance regression of XLS import

The fix for Bug 76611 caused ~20% performance loss in XLS import.
With optional cloning of ScTokenArray of the shared XLS formulas
depending on the need of address wrapping, it is possible to gain
back near the original performance.

Note: The original patch for Bug 76611 has already got an unit test,
too (see wrapped-refs.xls), and that unit test works with this
improved patch, too.

Change-Id: Ibfb59d1543ef9c4b8a075d5c4e37f77ab451aaa0
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index ab1e941..d1a4bed 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -239,7 +239,7 @@ public:
     */
    OUString CreateString( sc::TokenStringContext& rCxt, const ScAddress& rPos ) const;

    void WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow );
    bool WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow, bool bQueryNeedWrap = false);

#if DEBUG_FORMULA_COMPILER
    void Dump() const;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index e7e6ece..563b2007 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -3994,17 +3994,27 @@ OUString ScTokenArray::CreateString( sc::TokenStringContext& rCxt, const ScAddre

namespace {

void wrapAddress( ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow )
bool wrapAddress( ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow, bool bQueryOnly )
{
    bool bChanged = false;
    if (rPos.Col() > nMaxCol)
        rPos.SetCol(rPos.Col() - nMaxCol - 1);
    {
        if (!bQueryOnly)
            rPos.SetCol(rPos.Col() - nMaxCol - 1);
        bChanged = true;
    }
    if (rPos.Row() > nMaxRow)
        rPos.SetRow(rPos.Row() - nMaxRow - 1);
    {
        if (!bQueryOnly)
            rPos.SetRow(rPos.Row() - nMaxRow - 1);
        bChanged = true;
    }
    return bChanged;
}

}

void ScTokenArray::WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow )
bool ScTokenArray::WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nMaxRow, bool bQueryNeedWrap)
{
    FormulaToken** p = pCode;
    FormulaToken** pEnd = p + static_cast<size_t>(nLen);
@@ -4017,8 +4027,12 @@ void ScTokenArray::WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nM
                formula::FormulaToken* pToken = *p;
                ScSingleRefData& rRef = *pToken->GetSingleRef();
                ScAddress aAbs = rRef.toAbs(rPos);
                wrapAddress(aAbs, nMaxCol, nMaxRow);
                rRef.SetAddress(aAbs, rPos);
                if (wrapAddress(aAbs, nMaxCol, nMaxRow, bQueryNeedWrap))
                {
                    if (bQueryNeedWrap)
                        return true;
                    rRef.SetAddress(aAbs, rPos);
                }
            }
            break;
            case svDoubleRef:
@@ -4026,16 +4040,22 @@ void ScTokenArray::WrapReference( const ScAddress& rPos, SCCOL nMaxCol, SCROW nM
                formula::FormulaToken* pToken = *p;
                ScComplexRefData& rRef = *pToken->GetDoubleRef();
                ScRange aAbs = rRef.toAbs(rPos);
                wrapAddress(aAbs.aStart, nMaxCol, nMaxRow);
                wrapAddress(aAbs.aEnd, nMaxCol, nMaxRow);
                aAbs.PutInOrder();
                rRef.SetRange(aAbs, rPos);
                bool bChanged = wrapAddress(aAbs.aStart, nMaxCol, nMaxRow, bQueryNeedWrap);
                bool bChanged2 = wrapAddress(aAbs.aEnd, nMaxCol, nMaxRow, bQueryNeedWrap);
                if (bChanged || bChanged2)
                {
                    if (bQueryNeedWrap)
                        return true;
                    aAbs.PutInOrder();
                    rRef.SetRange(aAbs, rPos);
                }
            }
            break;
            default:
                ;
        }
    }
    return false;
}

#if DEBUG_FORMULA_COMPILER
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx
index 22becd6c5..dec9a81 100644
--- a/sc/source/filter/excel/excform.cxx
+++ b/sc/source/filter/excel/excform.cxx
@@ -122,8 +122,13 @@ void ImportExcel::Formula(
            const ScTokenArray* pSharedCode = pFormConv->GetSharedFormula(aRefPos);
            if (pSharedCode)
            {
                ScFormulaCell* pCell = new ScFormulaCell(pD, aScPos, pSharedCode->Clone());
                pCell->GetCode()->WrapReference(aScPos, EXC_MAXCOL8, EXC_MAXROW8);
                ScFormulaCell* pCell = new ScFormulaCell(pD, aScPos, *pSharedCode);
                // Do we need to wrap the column or row indices? (tdf#76611)
                if (pCell->GetCode()->WrapReference(aScPos, EXC_MAXCOL8, EXC_MAXROW8, true))
                {
                    pCell = new ScFormulaCell(pD, aScPos, pSharedCode->Clone());
                    pCell->GetCode()->WrapReference(aScPos, EXC_MAXCOL8, EXC_MAXROW8);
                }
                rDoc.getDoc().EnsureTable(aScPos.Tab());
                rDoc.setFormulaCell(aScPos, pCell);
                pCell->SetNeedNumberFormat(false);