diff options
author | Andreas Heinisch <andreas.heinisch@yahoo.de> | 2020-03-21 14:59:27 +0100 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2020-03-24 09:30:38 +0100 |
commit | 16b0bbb671a8080655e27542e576478486810404 (patch) | |
tree | e52bdd72fbc33308ba9ced4dfdaf0a0258dacc35 | |
parent | 2846686272931cd8bb0bcd452dd0e8b5b52064b1 (diff) |
tdf#131296: get numeric value with its data type in StepLOADNC
In order to load numeric values, generate SbiOpcode::NUMBER_ opcodes
including the numeric value and its data type instead of SbiOpcode::CONST_.
The numeric value and its data type will be restored in
SbiRuntime::StepLOADNC. When the new compiled code is stored in documents,
e.g. password-protected libraries, leagcy LO versions will just read up to
non-numeric characters, thus correctly obtaining number value and ignoring
the type, so the change is backward-compatible.
To interpret legacy compiled code, old treatment of SbiRuntime::StepLOADI
is restored, reverting commit 0b4f8bf571baf2ccd5a8aafdc4deb41867420be3.
This change reimplements the fix for tdf#129596.
Change-Id: I46ebfc77f9bea69479968950c0fb7264e4a7ab27
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90858
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | basic/source/comp/exprgen.cxx | 8 | ||||
-rw-r--r-- | basic/source/comp/symtbl.cxx | 11 | ||||
-rw-r--r-- | basic/source/runtime/runtime.cxx | 35 | ||||
-rw-r--r-- | sc/qa/extras/macros-test.cxx | 83 | ||||
-rw-r--r-- | sc/qa/extras/testdocuments/tdf131296_legacy.ods | bin | 0 -> 15932 bytes | |||
-rw-r--r-- | sc/qa/extras/testdocuments/tdf131296_new.ods | bin | 0 -> 16734 bytes |
6 files changed, 113 insertions, 24 deletions
diff --git a/basic/source/comp/exprgen.cxx b/basic/source/comp/exprgen.cxx index 3981bef2fb5e..6c60c02b0d7e 100644 --- a/basic/source/comp/exprgen.cxx +++ b/basic/source/comp/exprgen.cxx @@ -72,16 +72,14 @@ void SbiExprNode::Gen( SbiCodeGen& rGen, RecursiveMode eRecMode ) case SbxEMPTY: rGen.Gen( SbiOpcode::EMPTY_ ); break; - case SbxLONG: - case SbxINTEGER: - nStringId = rGen.GetParser()->aGblStrings.Add(nVal, eType); - rGen.Gen( SbiOpcode::CONST_, nStringId ); - break; case SbxSTRING: nStringId = rGen.GetParser()->aGblStrings.Add( aStrVal ); rGen.Gen( SbiOpcode::SCONST_, nStringId ); break; default: + // tdf#131296 - generate SbiOpcode::NUMBER_ instead of SbiOpcode::CONST_ + // for SbxINTEGER and SbxLONG including their numeric value and its data type, + // which will be restored in SbiRuntime::StepLOADNC. nStringId = rGen.GetParser()->aGblStrings.Add( nVal, eType ); rGen.Gen( SbiOpcode::NUMBER_, nStringId ); break; diff --git a/basic/source/comp/symtbl.cxx b/basic/source/comp/symtbl.cxx index b05575adfdfb..ac6f1ecd29da 100644 --- a/basic/source/comp/symtbl.cxx +++ b/basic/source/comp/symtbl.cxx @@ -66,10 +66,13 @@ short SbiStringPool::Add( double n, SbxDataType t ) char buf[ 40 ]; switch( t ) { - case SbxINTEGER: snprintf( buf, sizeof(buf), "%d", static_cast<short>(n) ); break; - case SbxLONG: snprintf( buf, sizeof(buf), "%ld", static_cast<long>(n) ); break; - case SbxSINGLE: snprintf( buf, sizeof(buf), "%.6g", static_cast<float>(n) ); break; - case SbxDOUBLE: snprintf( buf, sizeof(buf), "%.16g", 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; + case SbxLONG: snprintf( buf, sizeof(buf), "%ld&", static_cast<long>(n) ); break; + case SbxSINGLE: snprintf( buf, sizeof(buf), "%.6g!", static_cast<float>(n) ); break; + case SbxDOUBLE: snprintf( buf, sizeof(buf), "%.16g", n ); break; // default processing in SbiRuntime::StepLOADNC - no type character + case SbxCURRENCY: snprintf(buf, sizeof(buf), "%.16g@", n); break; default: break; } return Add( OUString::createFromAscii( buf ) ); diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx index ffd03f28b7cf..15b45ec736a0 100644 --- a/basic/source/runtime/runtime.cxx +++ b/basic/source/runtime/runtime.cxx @@ -2773,8 +2773,6 @@ void SbiRuntime::StepERROR() void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 ) { - SbxVariable* p = new SbxVariable( SbxDOUBLE ); - // #57844 use localized function OUString aStr = pImg->GetString( static_cast<short>( nOp1 ) ); // also allow , !!! @@ -2783,8 +2781,24 @@ void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 ) { aStr = aStr.replaceAt(iComma, 1, "."); } - double n = ::rtl::math::stringToDouble( aStr, '.', ',' ); + sal_Int32 nParseEnd = 0; + rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; + double n = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd ); + // tdf#131296 - retrieve data type put in SbiExprNode::Gen + SbxDataType eType = SbxDOUBLE; + if ( nParseEnd < aStr.getLength() ) + { + switch ( aStr[nParseEnd] ) + { + // See GetSuffixType in basic/source/comp/scanner.cxx for type characters + case '%': eType = SbxINTEGER; break; + case '&': eType = SbxLONG; break; + case '!': eType = SbxSINGLE; break; + case '@': eType = SbxCURRENCY; break; + } + } + SbxVariable* p = new SbxVariable( eType ); p->PutDouble( n ); PushVar( p ); } @@ -2799,22 +2813,13 @@ void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 ) } // Immediate Load (+value) +// The opcode is not generated in SbiExprNode::Gen anymore; used for legacy images void SbiRuntime::StepLOADI( sal_uInt32 nOp1 ) { SbxVariable* p = new SbxVariable; - - OUString aStr = pImg->GetString(static_cast<short>(nOp1)); - double n = ::rtl::math::stringToDouble(aStr, '.', ','); - if (n >= SbxMININT && n <= SbxMAXINT) - { - p->PutInteger(static_cast<sal_Int16>(n)); - } - else - { - p->PutLong(static_cast<sal_Int32>(n)); - } - PushVar(p); + p->PutInteger( static_cast<sal_Int16>( nOp1 ) ); + PushVar( p ); } // store a named argument in Argv (+Arg-no. from 1!) diff --git a/sc/qa/extras/macros-test.cxx b/sc/qa/extras/macros-test.cxx index f887a95f7223..3801a9998895 100644 --- a/sc/qa/extras/macros-test.cxx +++ b/sc/qa/extras/macros-test.cxx @@ -37,6 +37,8 @@ public: void testPasswordProtectedStarBasic(); void testRowColumn(); void testPasswordProtectedUnicodeString(); + void testTdf131296_legacy(); + void testTdf131296_new(); CPPUNIT_TEST_SUITE(ScMacrosTest); CPPUNIT_TEST(testStarBasic); @@ -45,6 +47,8 @@ public: CPPUNIT_TEST(testPasswordProtectedStarBasic); CPPUNIT_TEST(testRowColumn); CPPUNIT_TEST(testPasswordProtectedUnicodeString); + CPPUNIT_TEST(testTdf131296_legacy); + CPPUNIT_TEST(testTdf131296_new); CPPUNIT_TEST_SUITE_END(); }; @@ -453,6 +457,85 @@ void ScMacrosTest::testPasswordProtectedUnicodeString() xCloseable->close(true); } +void ScMacrosTest::testTdf131296_legacy() +{ + // For legacy password-protected library images, we must correctly get the constants' values, + // and also - for Integer - the type. + const std::vector<std::pair<OUString, OUString>> aTests({ + { "TestIntConst", "Integer: 123" }, + { "TestLongConst", "Double: 123" }, + { "TestSingleConst", "Double: 123" }, + { "TestDoubleConst", "Double: 123" }, + }); + + OUString aFileName; + createFileURL("tdf131296_legacy.ods", aFileName); + auto xComponent = loadFromDesktop(aFileName, "com.sun.star.sheet.SpreadsheetDocument"); + CPPUNIT_ASSERT(xComponent); + + { + Any aRet; + Sequence<sal_Int16> aOutParamIndex; + Sequence<Any> aOutParam; + Sequence<uno::Any> aParams; + + for (auto& [sTestName, sExpected] : aTests) + { + SfxObjectShell::CallXScript(xComponent, + "vnd.sun.Star.script:Protected.Module1." + sTestName + + "?language=Basic&location=document", + aParams, aRet, aOutParamIndex, aOutParam); + + OUString aReturnValue; + aRet >>= aReturnValue; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestName.toUtf8().getStr(), sExpected, aReturnValue); + } + } + + css::uno::Reference<css::util::XCloseable> xCloseable(xComponent, css::uno::UNO_QUERY_THROW); + xCloseable->close(true); +} + +void ScMacrosTest::testTdf131296_new() +{ + // For new password-protected library images, we must correctly get both the constants' values + // and their types. + const std::vector<std::pair<OUString, OUString>> aTests({ + { "TestIntConst", "Integer: 123" }, + { "TestLongConst", "Long: 123" }, + { "TestSingleConst", "Single: 123" }, + { "TestDoubleConst", "Double: 123" }, + { "TestCurrencyConst", "Currency: 123.0000" }, + }); + + OUString aFileName; + createFileURL("tdf131296_new.ods", aFileName); + auto xComponent = loadFromDesktop(aFileName, "com.sun.star.sheet.SpreadsheetDocument"); + CPPUNIT_ASSERT(xComponent); + + { + Any aRet; + Sequence<sal_Int16> aOutParamIndex; + Sequence<Any> aOutParam; + Sequence<uno::Any> aParams; + + for (auto& [sTestName, sExpected] : aTests) + { + SfxObjectShell::CallXScript(xComponent, + "vnd.sun.Star.script:Protected.Module1." + sTestName + + "?language=Basic&location=document", + aParams, aRet, aOutParamIndex, aOutParam); + + OUString aReturnValue; + aRet >>= aReturnValue; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestName.toUtf8().getStr(), sExpected, aReturnValue); + } + } + + css::uno::Reference<css::util::XCloseable> xCloseable(xComponent, css::uno::UNO_QUERY_THROW); + xCloseable->close(true); +} + ScMacrosTest::ScMacrosTest() : UnoApiTest("/sc/qa/extras/testdocuments") { diff --git a/sc/qa/extras/testdocuments/tdf131296_legacy.ods b/sc/qa/extras/testdocuments/tdf131296_legacy.ods Binary files differnew file mode 100644 index 000000000000..43ebdeb24f67 --- /dev/null +++ b/sc/qa/extras/testdocuments/tdf131296_legacy.ods diff --git a/sc/qa/extras/testdocuments/tdf131296_new.ods b/sc/qa/extras/testdocuments/tdf131296_new.ods Binary files differnew file mode 100644 index 000000000000..9c0161c40ccd --- /dev/null +++ b/sc/qa/extras/testdocuments/tdf131296_new.ods |