tdf#139840 - Use utl::TextSearch to implement the InStr function

In addtion, fixed a crash if the start position is greater than the
length of the string being searched.

Change-Id: I9bcda1131324bdfac6957018e91b3a36dd2dc3d6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118996
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
diff --git a/basic/qa/basic_coverage/test_instr_method.bas b/basic/qa/basic_coverage/test_instr_method.bas
index ff763cb..9e4545b 100644
--- a/basic/qa/basic_coverage/test_instr_method.bas
+++ b/basic/qa/basic_coverage/test_instr_method.bas
@@ -18,6 +18,12 @@ Function doUnitTest as String

    ' tdf#139840 - case-insensitive operation for non-ASCII characters
    If (InStr(1, "α", "Α", 1) <> 1) Then Exit Function
    ' tdf#139840 - German Eszett is uppercased to a two-character 'SS'.
    ' This test should fail after tdf#110003 has been fixed.
    If (InStr(2, "Straße", "s", 1) <> 5) Then Exit Function

    ' Start position is greater than the length of the string being searched.
    If (InStr(2, "α", "Α", 1) <> 0) Then Exit Function

    doUnitTest = "OK"

diff --git a/basic/qa/vba_tests/instr.vb b/basic/qa/vba_tests/instr.vb
index 3ced2a0..cda1971 100644
--- a/basic/qa/vba_tests/instr.vb
+++ b/basic/qa/vba_tests/instr.vb
@@ -32,6 +32,12 @@ Sub verify_testInStr()

    ' tdf#139840 - case-insensitive operation for non-ASCII characters
    TestUtil.AssertEqual(InStr(1, "α", "Α", 1), 1, "InStr(1, ""α"", ""Α"", 1)")
    ' tdf#139840 - German Eszett is uppercased to a two-character 'SS'.
    ' This test should fail after tdf#110003 has been fixed.
    TestUtil.AssertEqual(InStr(2, "Straße", "s", 1), 5, "InStr(2, ""Straße"", ""s"", 1)")

    ' Start position is greater than the length of the string being searched.
    TestUtil.AssertEqual(InStr(2, "α", "Α", 1), 0, "InStr(2, ""α"", ""Α"", 1)")

    Exit Sub
errorHandler:
diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx
index e745fa2..1055aab 100644
--- a/basic/source/runtime/methods.cxx
+++ b/basic/source/runtime/methods.cxx
@@ -885,25 +885,32 @@ void SbRtl_InStr(StarBASIC *, SbxArray & rPar, bool)
        }
        else
        {
            if( !bTextMode )
            const OUString& rStr1 = rPar.Get(nFirstStringPos)->GetOUString();
            const sal_Int32 nrStr1Len = rStr1.getLength();
            if (nStartPos > nrStr1Len)
            {
                const OUString& rStr1 = rPar.Get(nFirstStringPos)->GetOUString();
                nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1;
                // Start position is greater than the string being searched
                nPos = 0;
            }
            else
            {
                OUString aStr1 = rPar.Get(nFirstStringPos)->GetOUString();
                OUString aToken = rToken;
                if( !bTextMode )
                {
                    nPos = rStr1.indexOf( rToken, nStartPos - 1 ) + 1;
                }
                else
                {
                    // tdf#139840 - case-insensitive operation for non-ASCII characters
                    i18nutil::SearchOptions2 aSearchOptions;
                    aSearchOptions.searchString = rToken;
                    aSearchOptions.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
                    aSearchOptions.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
                    utl::TextSearch textSearch(aSearchOptions);

                // tdf#139840 - case-insensitive operation for non-ASCII characters
                const css::lang::Locale& rLocale
                    = Application::GetSettings().GetLanguageTag().getLocale();
                css::uno::Reference<i18n::XCharacterClassification> xCharClass
                    = vcl::unohelper::CreateCharacterClassification();
                aStr1 = xCharClass->toUpper(aStr1, 0, aStr1.getLength(), rLocale);
                aToken = xCharClass->toUpper(aToken, 0, aToken.getLength(), rLocale);

                nPos = aStr1.indexOf( aToken, nStartPos-1 ) + 1;
                    sal_Int32 nStart = nStartPos - 1;
                    sal_Int32 nEnd = nrStr1Len;
                    nPos = textSearch.SearchForward(rStr1, &nStart, &nEnd) ? nStart + 1 : 0;
                }
            }
        }
        rPar.Get(0)->PutLong(nPos);