tdf#142460: properly handle boolean values in string pool

This makes sure that results of comparison of literals have proper boolean type,
and that this type is properly stored to/read from the string pool.

This introduces a new non-standard "type" character used in the pool: 'b'. It is
not a proper type character used in Basic (unlike '%'/'&'/'!'/'@'), but we have
to use this trick locally, because we need to pass the type that has no own type
character.

The change should be backward-compatible: older versions reading the value should
just ignore the 'b', and read the value as double.

Change-Id: Ibd4a70b366331342346eb171c8ed3c7026279596
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117655
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 5eedb3beeaeed88de0d1ebd041a9f15ceea7e78c)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117862
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/basic/qa/vba_tests/booltypename.vb b/basic/qa/vba_tests/booltypename.vb
new file mode 100644
index 0000000..8c1fd17
--- /dev/null
+++ b/basic/qa/vba_tests/booltypename.vb
@@ -0,0 +1,37 @@
'
' This file is part of the LibreOffice project.
'
' This Source Code Form is subject to the terms of the Mozilla Public
' License, v. 2.0. If a copy of the MPL was not distributed with this
' file, You can obtain one at http://mozilla.org/MPL/2.0/.
'

Option VBASupport 1
Option Explicit

Function doUnitTest() As String
    TestUtil.TestInit
    verify_testTypeNameBoolean
    doUnitTest = TestUtil.GetResult()
End Function

Sub verify_testTypeNameBoolean()
    On Error GoTo errorHandler

    TestUtil.AssertEqual(TypeName 1>2,       "Boolean",  "TypeName 1>2")
    TestUtil.AssertEqual(TypeName 2.0>1.0,   "Boolean",  "TypeName 2.0>1.0")
    TestUtil.AssertEqual(TypeName "A">"B",   "Boolean",  "TypeName ""A"">""B""")

    TestUtil.AssertEqual(Str(2>1), "True",  "Str(2>1)")
    TestUtil.AssertEqual(Str(1>2), "False", "Str(1>2)")

    TestUtil.AssertEqual(Str(2.0>1.0), "True",  "Str(2.0>1.0)")
    TestUtil.AssertEqual(Str(1.0>2.0), "False", "Str(1.0>2.0)")

    TestUtil.AssertEqual(Str("B">"A"), "True",  "Str(""B"">""A"")")
    TestUtil.AssertEqual(Str("A">"B"), "False", "Str(""A"">""B"")")

    Exit Sub
errorHandler:
    TestUtil.ReportErrorHandler("verify_testTypeNameBoolean", Err, Error$, Erl)
End Sub
diff --git a/basic/source/comp/exprnode.cxx b/basic/source/comp/exprnode.cxx
index 4192ceb..17bdbca 100644
--- a/basic/source/comp/exprnode.cxx
+++ b/basic/source/comp/exprnode.cxx
@@ -262,7 +262,7 @@ void SbiExprNode::FoldConstantsBinaryNode(SbiParser* pParser)
        }
        else
        {
            eType = SbxDOUBLE;
            eType = SbxBOOL;
            eNodeType = SbxNUMVAL;
            int eRes = rr.compareTo( rl );
            switch( eTok )
@@ -365,22 +365,22 @@ void SbiExprNode::FoldConstantsBinaryNode(SbiParser* pParser)
                nVal = nl - nr; break;
            case EQ:
                nVal = ( nl == nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case NE:
                nVal = ( nl != nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case LT:
                nVal = ( nl <  nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case GT:
                nVal = ( nl >  nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case LE:
                nVal = ( nl <= nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case GE:
                nVal = ( nl >= nr ) ? SbxTRUE : SbxFALSE;
                eType = SbxINTEGER; break;
                eType = SbxBOOL; break;
            case IDIV:
                if( !lr )
                {
diff --git a/basic/source/comp/symtbl.cxx b/basic/source/comp/symtbl.cxx
index d9e7fca..ed245a3 100644
--- a/basic/source/comp/symtbl.cxx
+++ b/basic/source/comp/symtbl.cxx
@@ -66,6 +66,8 @@ short SbiStringPool::Add( double n, SbxDataType t )
    char buf[40]{};
    switch( t )
    {
        // tdf#142460 - properly handle boolean values in string pool
        case SbxBOOL: snprintf( buf, sizeof(buf), "%db", static_cast<short>(n) ); break;
        // tdf#131296 - store numeric value including its type character
        // See GetSuffixType in basic/source/comp/scanner.cxx for type characters
        case SbxINTEGER: snprintf( buf, sizeof(buf), "%d%%", static_cast<short>(n) ); break;
diff --git a/basic/source/inc/filefmt.hxx b/basic/source/inc/filefmt.hxx
index 3460b1a..25ba647 100644
--- a/basic/source/inc/filefmt.hxx
+++ b/basic/source/inc/filefmt.hxx
@@ -40,6 +40,9 @@
// Version 13: tdf#94617 store methods nStart information greater than sal_Int16 limit
//             tdf#57113 store UTF-16 strings after legacy 1-byte-encoded strings in pool (no
//                       version number bump for backward compatibility; relies on magic number)
//             tdf#142460: properly handle boolean values in string pool (no
//                       version number bump for backward compatibility; relies on
//                       new integer type suffix 'b')
//

#define B_LEGACYVERSION 0x00000011
diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx
index 385f675..43e8eea 100644
--- a/basic/source/runtime/runtime.cxx
+++ b/basic/source/runtime/runtime.cxx
@@ -2840,6 +2840,8 @@ void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 )
            case '&': eType = SbxLONG; break;
            case '!': eType = SbxSINGLE; break;
            case '@': eType = SbxCURRENCY; break;
            // tdf#142460 - properly handle boolean values in string pool
            case 'b': eType = SbxBOOL; break;
        }
    }
    SbxVariable* p = new SbxVariable( eType );