tdf#130476 - take into account trailing data type characters

For hex/octal literals take into account trailing suffix types
from GetSuffixType in basic/source/comp/scanner.cxx.

Change-Id: Id6c4bbf1296361879f7dec461a48bbdc5c683338
diff --git a/basic/qa/cppunit/test_scanner.cxx b/basic/qa/cppunit/test_scanner.cxx
index 42cd637..72e2f21 100644
--- a/basic/qa/cppunit/test_scanner.cxx
+++ b/basic/qa/cppunit/test_scanner.cxx
@@ -786,6 +786,7 @@ namespace
    const OUString source15("&H7FFF");
    const OUString source16("&H7FFFFFFF");

    sal_Int32 errors;
    std::vector<Symbol> symbols;

    symbols = getSymbols(source1);
@@ -816,7 +817,7 @@ namespace
    CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[0].type);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[1].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[1].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[1].type);
    CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[1].type);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(1.0, symbols[2].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[2].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[2].type);
@@ -832,7 +833,7 @@ namespace
    CPPUNIT_ASSERT_EQUAL(size_t(3), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[1].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString("O12"), symbols[1].text);
    CPPUNIT_ASSERT_EQUAL(SbxVARIANT, symbols[1].type);
@@ -923,6 +924,138 @@ namespace
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character % = SbxINTEGER
    symbols = getSymbols("&H0%");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character $ = SbxLONG
    symbols = getSymbols("&H0&");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character ! = SbxSINGLE
    symbols = getSymbols("&H0!");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character # = SbxDOUBLE
    symbols = getSymbols("&H0#");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character @ = SbxCURRENCY
    symbols = getSymbols("&H0@");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character $ = SbxSTRING
    symbols = getSymbols("&H0$");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character % = SbxINTEGER
    symbols = getSymbols("&O0%");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character $ = SbxLONG
    symbols = getSymbols("&O0&");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxLONG, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character ! = SbxSINGLE
    symbols = getSymbols("&O0!");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxSINGLE, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character # = SbxDOUBLE
    symbols = getSymbols("&O0#");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxDOUBLE, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character @ = SbxCURRENCY
    symbols = getSymbols("&O0@");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxCURRENCY, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - trailing data type character $ = SbxSTRING
    symbols = getSymbols("&O0$");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxSTRING, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - overflow for Integer data type (trailing data type character % = SbxINTEGER)
    symbols = getSymbols("&HFFFF%");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // tdf#130476 - overflow for Integer data type (trailing data type character % = SbxINTEGER)
    symbols = getSymbols("&H10000%", errors);
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
    // ERRCODE_BASIC_MATH_OVERFLOW
    CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));

    // overflow for Integer data type (trailing data type character % = SbxINTEGER)
    symbols = getSymbols("&O177777%");
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);

    // overflow for Integer data type (trailing data type character % = SbxINTEGER)
    symbols = getSymbols("&O200000%", errors);
    CPPUNIT_ASSERT_EQUAL(size_t(2), symbols.size());
    CPPUNIT_ASSERT_DOUBLES_EQUAL(0, symbols[0].number, 1E-12);
    CPPUNIT_ASSERT_EQUAL(OUString(), symbols[0].text);
    CPPUNIT_ASSERT_EQUAL(SbxINTEGER, symbols[0].type);
    CPPUNIT_ASSERT_EQUAL(cr, symbols[1].text);
    // ERRCODE_BASIC_MATH_OVERFLOW
    CPPUNIT_ASSERT_EQUAL(1u, static_cast<unsigned int>(errors));
  }

  void ScannerTest::testTdf103104()
diff --git a/basic/source/comp/scanner.cxx b/basic/source/comp/scanner.cxx
index 7c192b3..4f5f675 100644
--- a/basic/source/comp/scanner.cxx
+++ b/basic/source/comp/scanner.cxx
@@ -482,17 +482,44 @@ bool SbiScanner::NextSym()
                GenError( ERRCODE_BASIC_BAD_CHAR_IN_NUMBER );
            }
        }
        if(nCol < aLine.getLength() && aLine[nCol] == '&')

        // tdf#130476 - take into account trailing data type characters
        if( nCol < aLine.getLength() )
        {
            ++nLineIdx;
            ++nCol;
            SbxDataType t(GetSuffixType(aLine[nCol]));
            if( t != SbxVARIANT )
            {
                eScanType = t;
                ++nLineIdx;
                ++nCol;
            }
        }
        // tdf#62326 - If the value of the hex string lies within the range of 0x8000 (SbxMAXINT + 1)
        // and 0xFFFF (SbxMAXUINT) inclusive, cast the value to 16 bit in order to get
        // signed integers, e.g., SbxMININT through SbxMAXINT
        sal_Int32 ls = (lu > SbxMAXINT && lu <= SbxMAXUINT) ? static_cast<sal_Int16>(lu) : static_cast<sal_Int32>(lu);
        nVal = static_cast<double>(ls);
        eScanType = ( ls >= SbxMININT && ls <= SbxMAXINT ) ? SbxINTEGER : SbxLONG;

        // tdf#130476 - take into account trailing data type characters
        switch ( eScanType )
        {
            case SbxINTEGER:
                nVal = static_cast<double>( static_cast<sal_Int16>(lu) );
                if ( lu > SbxMAXUINT )
                {
                    bOverflow = true;
                }
                break;
            case SbxLONG: nVal = static_cast<double>( static_cast<sal_Int32>(lu) ); break;
            case SbxVARIANT:
            {
                // tdf#62326 - If the value of the hex string without explicit type character lies within
                // the range of 0x8000 (SbxMAXINT + 1) and 0xFFFF (SbxMAXUINT) inclusive, cast the value
                // to 16 bit in order to get signed integers, e.g., SbxMININT through SbxMAXINT
                sal_Int32 ls = (lu > SbxMAXINT && lu <= SbxMAXUINT) ? static_cast<sal_Int16>(lu) : static_cast<sal_Int32>(lu);
                eScanType = ( ls >= SbxMININT && ls <= SbxMAXINT ) ? SbxINTEGER : SbxLONG;
                nVal = static_cast<double>(ls);
                break;
            }
            default:
                nVal = static_cast<double>(lu);
                break;
        }
        if( bOverflow )
            GenError( ERRCODE_BASIC_MATH_OVERFLOW );
    }