tdf#147014 Image missing due to integer overflow

32-bit awt::Point/Size/Rectangle cannot fit size of 1M rows with
larger (eg. 5x the usual) height, and could overflow.

This causes problems in 64-bit Linux builds and, since the
following commit, in 64-bit Windows builds:
3d90997fb6f232d8008df4d166d7b97b869c200f

For now, clamp possibly overflowing values to 32-bit.

Change-Id: Ifda7265703388abdfb47f523da4f0c5822358404
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129876
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Reviewed-by: Aron Budea <aron.budea@collabora.com>
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132168
diff --git a/sc/qa/unit/data/xlsx/tdf147014.xlsx b/sc/qa/unit/data/xlsx/tdf147014.xlsx
new file mode 100644
index 0000000..df44287
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/tdf147014.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx b/sc/qa/unit/subsequent_filters_test2.cxx
index c40f26d..ac0b8d8 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -204,6 +204,7 @@ public:
    void testTdf129940();
    void testTdf139612();
    void testTdf144740();
    void testTdf147014();
    void testTdf139763ShapeAnchor();
    void testAutofilterNamedRangesXLSX();
    void testInvalidBareBiff5();
@@ -312,6 +313,7 @@ public:
    CPPUNIT_TEST(testTdf129940);
    CPPUNIT_TEST(testTdf139612);
    CPPUNIT_TEST(testTdf144740);
    CPPUNIT_TEST(testTdf147014);
    CPPUNIT_TEST(testTdf139763ShapeAnchor);
    CPPUNIT_TEST(testAutofilterNamedRangesXLSX);
    CPPUNIT_TEST(testInvalidBareBiff5);
@@ -2873,6 +2875,22 @@ void ScFiltersTest2::testTdf144740()
    xDocSh->DoClose();
}

void ScFiltersTest2::testTdf147014()
{
    ScDocShellRef xDocSh = loadDoc(u"tdf147014.", FORMAT_XLSX);
    CPPUNIT_ASSERT_MESSAGE("Failed to load tdf147014.xlsx", xDocSh.is());
    uno::Reference<frame::XModel> xModel = xDocSh->GetModel();
    uno::Reference<sheet::XSpreadsheetDocument> xDoc(xModel, uno::UNO_QUERY_THROW);
    uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), uno::UNO_QUERY_THROW);
    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xIA->getByIndex(0),
                                                                 uno::UNO_QUERY_THROW);
    xIA.set(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW);
    // The sheet has a single shape, without the fix it was not imported, except in 32-bit builds
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape not imported", static_cast<sal_Int32>(1), xIA->getCount());

    xDocSh->DoClose();
}

void ScFiltersTest2::testTdf139763ShapeAnchor()
{
    ScDocShellRef xDocSh = loadDoc(u"tdf139763ShapeAnchor.", FORMAT_XLSX);
diff --git a/sc/source/filter/oox/worksheethelper.cxx b/sc/source/filter/oox/worksheethelper.cxx
index 40a99cd..9562575 100644
--- a/sc/source/filter/oox/worksheethelper.cxx
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -75,7 +75,7 @@
#include <editeng/eeitem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/flditem.hxx>
#include <tools/UnitConversion.hxx>
#include <tools/gen.hxx>

namespace oox::xls {

@@ -96,6 +96,18 @@ void lclUpdateProgressBar( const ISegmentProgressBarRef& rxProgressBar, double f
        rxProgressBar->setPosition( fPosition );
}

// TODO Needed because input might be >32-bit (in 64-bit builds),
//  or a negative, already overflown value (in 32-bit builds)
sal_Int32 lclClampToNonNegativeInt32( tools::Long aVal )
{
    if ( aVal > SAL_MAX_INT32 || aVal < 0 )
    {
        SAL_WARN( "sc.filter", "Overflow detected, " << aVal << " does not fit into sal_Int32, or is negative." );
        return SAL_MAX_INT32;
    }
    return static_cast<sal_Int32>( aVal );
}

} // namespace

ColumnModel::ColumnModel() :
@@ -538,9 +550,9 @@ const awt::Size& WorksheetGlobals::getDrawPageSize() const

awt::Point WorksheetGlobals::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) const
{
    awt::Point aPoint;
    PropertySet aCellProp( getCell( ScAddress( nCol, nRow, getSheetIndex() ) ) );
    aCellProp.getProperty( aPoint, PROP_Position );
    const tools::Rectangle aMMRect( getScDocument().GetMMRect( nCol, nRow, nCol, nRow, getSheetIndex() ) );
    awt::Point aPoint( lclClampToNonNegativeInt32( aMMRect.Left() ),
                       lclClampToNonNegativeInt32( aMMRect.Top() ) );
    return aPoint;
}

@@ -1360,8 +1372,9 @@ void WorksheetGlobals::groupColumnsOrRows( sal_Int32 nFirstColRow, sal_Int32 nLa
void WorksheetGlobals::finalizeDrawings()
{
    // calculate the current drawing page size (after rows/columns are imported)
    PropertySet aRangeProp( getCellRange( ScRange( 0, 0, getSheetIndex(), mrMaxApiPos.Col(), mrMaxApiPos.Row(), getSheetIndex() ) ) );
    aRangeProp.getProperty( maDrawPageSize, PROP_Size );
    const Size aPageSize( getScDocument().GetMMRect( 0, 0, mrMaxApiPos.Col(), mrMaxApiPos.Row(), getSheetIndex() ).GetSize() );
    maDrawPageSize.Width = lclClampToNonNegativeInt32( aPageSize.Width() );
    maDrawPageSize.Height = lclClampToNonNegativeInt32( aPageSize.Height() );

    // import DML and VML
    if( !maDrawingPath.isEmpty() )