tdf#148170 - Convert print range to an excel cell range

During export from Calc to XLS, ensure that the print range
is converted to a valid XLS print range. If the print range
exceeds XLS format limitations, it will be appropriately cropped
to fit within the constraints.

Change-Id: I2b233e4d57dfbe30f491448d2ee2972b8b717ea3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164469
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx
index 41d76cc..ff453d2 100644
--- a/sc/qa/unit/subsequent_export_test4.cxx
+++ b/sc/qa/unit/subsequent_export_test4.cxx
@@ -761,6 +761,26 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf51022_lostPrintRange)
    CPPUNIT_ASSERT_EQUAL(aRange2, *pDoc->GetPrintRange(0, 1));
}

CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf148170_ExceedXlsPrintRange)
{
    createScDoc();

    // Create print range that exceeds the xls limitations
    const auto aScSheeLimits = ScSheetLimits::CreateDefault();
    ScRange aCalcPrintRange(0, 0, 0, aScSheeLimits.MaxCol(), aScSheeLimits.MaxRow(), 0);
    ScDocument* pDoc = getScDoc();
    pDoc->AddPrintRange(0, aCalcPrintRange);

    saveAndReload("MS Excel 97");

    // Check if print range was shrunk to xls limitations
    pDoc = getScDoc();
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pDoc->GetPrintRangeCount(0));
    // Check sc/source/filter/inc/xlconst.hxx for xls limitations
    ScRange aXlsPrintRange(0, 0, 0, 16383, 65535, 0);
    CPPUNIT_ASSERT_EQUAL(aXlsPrintRange, *pDoc->GetPrintRange(0, 0));
}

CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf138741_externalLinkSkipUnusedsCrash)
{
    createScDoc("xlsx/tdf138741_externalLinkSkipUnusedsCrash.xlsx");
diff --git a/sc/source/filter/excel/xename.cxx b/sc/source/filter/excel/xename.cxx
index 84073da..8d97ffaa 100644
--- a/sc/source/filter/excel/xename.cxx
+++ b/sc/source/filter/excel/xename.cxx
@@ -36,6 +36,7 @@
#include <oox/export/utils.hxx>
#include <oox/token/tokens.hxx>
#include <com/sun/star/sheet/NamedRangeFlag.hdl>
#include <xihelper.hxx>

using namespace ::oox;
using namespace ::com::sun::star;
@@ -713,10 +714,17 @@ void XclExpNameManagerImpl::CreateBuiltInNames()
                    aRange.aStart.SetTab( nScTab );
                    aRange.aEnd.SetTab( nScTab );
                    aRange.PutInOrder();
                    aRangeList.push_back( aRange );

                    // tdf#148170 - convert print range to an excel cell range
                    XclRange aXclRange(ScAddress::UNINITIALIZED);
                    // create no warning if ranges are shrunken
                    if (GetAddressConverter().ConvertRange(aXclRange, aRange, false))
                    {
                        XclImpAddressConverter::FillRange(aXclRange, aRange);
                        aRangeList.push_back(aRange);
                    }
                }
                // create the NAME record (do not warn if ranges are shrunken)
                GetAddressConverter().ValidateRangeList( aRangeList, false );
                // create the NAME record
                if( !aRangeList.empty() )
                    GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTAREA, aRangeList );
            }
diff --git a/sc/source/filter/excel/xihelper.cxx b/sc/source/filter/excel/xihelper.cxx
index e095d22..2f05d67 100644
--- a/sc/source/filter/excel/xihelper.cxx
+++ b/sc/source/filter/excel/xihelper.cxx
@@ -98,6 +98,14 @@ ScAddress XclImpAddressConverter::CreateValidAddress(

// cell range -----------------------------------------------------------------

void XclImpAddressConverter::FillRange(const XclRange& rXclRange, ScRange& rScRange)
{
    const XclAddress aXclStartAdr = rXclRange.maFirst;
    lclFillAddress(rScRange.aStart, aXclStartAdr.mnCol, aXclStartAdr.mnRow, rScRange.aStart.Tab());
    const XclAddress aXclEndAdr = rXclRange.maLast;
    lclFillAddress(rScRange.aEnd, aXclEndAdr.mnCol, aXclEndAdr.mnRow, rScRange.aEnd.Tab());
}

bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
        const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
{
diff --git a/sc/source/filter/inc/xihelper.hxx b/sc/source/filter/inc/xihelper.hxx
index 746259e..fe6ba7c 100644
--- a/sc/source/filter/inc/xihelper.hxx
+++ b/sc/source/filter/inc/xihelper.hxx
@@ -71,6 +71,11 @@ public:

    // cell range -------------------------------------------------------------

    /** Fills the passed Calc cell range with the passed Excel cell range.
        @param XclRange  The Excel cell range to be transfered.
        @param ScRange  (Out) The filled Calc cell range. */
    static void FillRange(const XclRange& rXclRange, ScRange& rScRange);

    /** Converts the passed Excel cell range to a Calc cell range.
        @param rScRange  (Out) The converted Calc cell range, if valid.
        @param rXclRange  The Excel cell range to convert.