[Libreoffice-commits] core.git: 2 commits - chart2/inc chart2/qa chart2/source compilerplugins/clang config_host/config_global.h.in configure.ac include/rtl sal/qa sal/rtl sal/util

Stephan Bergmann sbergman at redhat.com
Mon Aug 29 11:44:43 UTC 2016


 chart2/inc/SpecialUnicodes.hxx                               |    2 
 chart2/qa/extras/chart2_trendcalculators.cxx                 |    8 
 chart2/source/tools/ExponentialRegressionCurveCalculator.cxx |    4 
 chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx |    4 
 chart2/source/tools/PolynomialRegressionCurveCalculator.cxx  |    2 
 chart2/source/tools/PotentialRegressionCurveCalculator.cxx   |    2 
 compilerplugins/clang/stringstatic.cxx                       |    7 
 config_host/config_global.h.in                               |    1 
 configure.ac                                                 |   14 
 include/rtl/stringconcat.hxx                                 |   15 
 include/rtl/stringutils.hxx                                  |   54 -
 include/rtl/ustrbuf.hxx                                      |   74 +
 include/rtl/ustring.h                                        |  223 ++++
 include/rtl/ustring.hxx                                      |  520 +++++++++++
 sal/qa/rtl/strings/test_oustring_stringliterals.cxx          |   83 +
 sal/rtl/ustring.cxx                                          |  203 ++++
 sal/util/sal.map                                             |   11 
 17 files changed, 1179 insertions(+), 48 deletions(-)

New commits:
commit 2c10714426cc813c36aa82e4870b7b51c5c03050
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Sun Aug 28 09:47:27 2016 +0200

    Make OUStringLiteral1 a wrapper around UTF-16 instead of just ASCII
    
    ...not merely an ASCII character
    
    Change-Id: Id2b381b35fe3a15574728ed973d60263dfef7249
    Reviewed-on: https://gerrit.libreoffice.org/28446
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Stephan Bergmann <sbergman at redhat.com>

diff --git a/chart2/inc/SpecialUnicodes.hxx b/chart2/inc/SpecialUnicodes.hxx
index db6e3b6..22ddc35 100644
--- a/chart2/inc/SpecialUnicodes.hxx
+++ b/chart2/inc/SpecialUnicodes.hxx
@@ -10,7 +10,7 @@
 #ifndef INCLUDED_CHART2_INC_SPECIALUNICODES_HXX
 #define INCLUDED_CHART2_INC_SPECIALUNICODES_HXX
 
-const OUString aMinusSign ( sal_Unicode (0x2212) );
+const sal_Unicode aMinusSign = 0x2212;
 const OUString aNewLine ("\n");
 const OUString aHashString ("###");
 const sal_Unicode aSuperscriptFigures[10]={ 0x2070, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079 };
diff --git a/chart2/qa/extras/chart2_trendcalculators.cxx b/chart2/qa/extras/chart2_trendcalculators.cxx
index 738a6d6..dd79dad 100644
--- a/chart2/qa/extras/chart2_trendcalculators.cxx
+++ b/chart2/qa/extras/chart2_trendcalculators.cxx
@@ -136,7 +136,7 @@ void Chart2TrendCalculators::testPotentialRegression2()
         xValues[i] = d;
         yValues[i] = -2.0 * pow ( d, 3 );
     }
-    checkCalculator( xValues, yValues, "f(x) = "+ OUString(aMinusSign) +" 2 x^3");
+    checkCalculator( xValues, yValues, "f(x) = "+ OUStringLiteral1<aMinusSign>() +" 2 x^3");
 }
 
 // test y = - 2 X - 5
@@ -152,7 +152,7 @@ void Chart2TrendCalculators::testLinearRegression1()
         xValues[i] = d;
         yValues[i] = - 2.0 * d - 5.0 ;
     }
-    checkCalculator( xValues, yValues, "f(x) = "+ OUString(aMinusSign) +" 2x "+ OUString(aMinusSign) +" 5");
+    checkCalculator( xValues, yValues, "f(x) = "+ OUStringLiteral1<aMinusSign>() +" 2x "+ OUStringLiteral1<aMinusSign>() +" 5");
 }
 
 // test y = A x ^ B
@@ -168,7 +168,7 @@ void Chart2TrendCalculators::testPolynomialRegression1()
         xValues[i] = d;
         yValues[i] =  - 2.0 * d * d + 4 * d - 5;
     }
-    OUString sExpectedFormula( "f(x) = "+ OUString(aMinusSign) +" 2x" + OUString( aSuperscriptFigures[2] ) + " + 4x "+ OUString(aMinusSign) +" 5" );
+    OUString sExpectedFormula( "f(x) = "+ OUStringLiteral1<aMinusSign>() +" 2x" + OUString( aSuperscriptFigures[2] ) + " + 4x "+ OUStringLiteral1<aMinusSign>() +" 5" );
     checkCalculator( xValues, yValues, sExpectedFormula );
 }
 
@@ -199,7 +199,7 @@ void Chart2TrendCalculators::testExponentialRegression2()
         xValues[i] = d;
         yValues[i] = -2.0 * exp ( 0.3 * d );
     }
-    checkCalculator( xValues, yValues, "f(x) = "+ OUString(aMinusSign) + " 2 exp( 0.3 x )");
+    checkCalculator( xValues, yValues, "f(x) = "+ OUStringLiteral1<aMinusSign>() + " 2 exp( 0.3 x )");
 }
 
 
diff --git a/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx b/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx
index 9d3f105..35c85e3 100644
--- a/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx
+++ b/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx
@@ -185,7 +185,7 @@ OUString ExponentialRegressionCurveCalculator::ImplGetRepresentation(
         // if nValueLength not calculated then nullptr
     sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr;
     if ( m_fSign < 0.0 )
-        aTmpBuf.append( aMinusSign + " " );
+        aTmpBuf.append( OUStringLiteral1<aMinusSign>() + " " );
     if ( bHasIntercept )
     {
         OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fIntercept, pValueLength );
@@ -210,7 +210,7 @@ OUString ExponentialRegressionCurveCalculator::ImplGetRepresentation(
         }
     }
     if ( m_fLogSlope < 0.0 )
-        aTmpBuf.append( aMinusSign + " " );
+        aTmpBuf.append( OUStringLiteral1<aMinusSign>() + " " );
     if ( bHasLogSlope )
     {
         OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fLogSlope), pValueLength );
diff --git a/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx b/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx
index b3d5e8f..93cbf3a 100644
--- a/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx
+++ b/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx
@@ -162,7 +162,7 @@ OUString LogarithmicRegressionCurveCalculator::ImplGetRepresentation(
     {
         if( m_fSlope < 0.0 )
         {
-            aTmpBuf.append( aMinusSign + " " );
+            aTmpBuf.append( OUStringLiteral1<aMinusSign>() + " " );
         }
         if( bHasSlope )
         {
@@ -181,7 +181,7 @@ OUString LogarithmicRegressionCurveCalculator::ImplGetRepresentation(
     }
              // add intercept value
     if( m_fIntercept < 0.0 )
-        aTmpBuf.append( aMinusSign+" " );
+        aTmpBuf.append( OUStringLiteral1<aMinusSign>()+" " );
     OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fIntercept), pValueLength );
     if ( aValueString != "0" )  // aValueString may be rounded to 0 if nValueLength is small
     {
diff --git a/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx
index c4976a5..120c33e 100644
--- a/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx
+++ b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx
@@ -278,7 +278,7 @@ OUString PolynomialRegressionCurveCalculator::ImplGetRepresentation(
         {
             if ( bFindValue ) // if it is not the first aValue
                 aTmpBuf.append( " " );
-            aTmpBuf.append( aMinusSign + " ");
+            aTmpBuf.append( OUStringLiteral1<aMinusSign>() + " ");
             aValue = - aValue;
         }
         else
diff --git a/chart2/source/tools/PotentialRegressionCurveCalculator.cxx b/chart2/source/tools/PotentialRegressionCurveCalculator.cxx
index aea4e68..b767412 100644
--- a/chart2/source/tools/PotentialRegressionCurveCalculator.cxx
+++ b/chart2/source/tools/PotentialRegressionCurveCalculator.cxx
@@ -176,7 +176,7 @@ OUString PotentialRegressionCurveCalculator::ImplGetRepresentation(
         // if nValueLength not calculated then nullptr
         sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr;
         if ( m_fIntercept < 0.0 )    // add intercept value
-             aTmpBuf.append( aMinusSign+" " );
+             aTmpBuf.append( OUStringLiteral1<aMinusSign>()+" " );
         if( bHasIntercept )
         {
             OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fIntercept), pValueLength );
diff --git a/compilerplugins/clang/stringstatic.cxx b/compilerplugins/clang/stringstatic.cxx
index 4ddac65..823fc7b 100644
--- a/compilerplugins/clang/stringstatic.cxx
+++ b/compilerplugins/clang/stringstatic.cxx
@@ -66,13 +66,6 @@ bool StringStatic::VisitVarDecl(VarDecl const* varDecl)
     if (ignoreLocation(varDecl)) {
         return true;
     }
-    // We could use OUStringLiteral1 here, but we'd need to update OUStringLiteral1 to allow BMP chars first:
-    if (compiler.getSourceManager().getFilename(varDecl->getLocation())
-        == SRCDIR "/chart2/inc/SpecialUnicodes.hxx")
-    {
-        return true;
-    }
-
     QualType qt = varDecl->getType();
     if (!varDecl->hasGlobalStorage()
         || !varDecl->isThisDeclarationADefinition()
diff --git a/include/rtl/stringconcat.hxx b/include/rtl/stringconcat.hxx
index 5a32bf9..ff8ad95 100644
--- a/include/rtl/stringconcat.hxx
+++ b/include/rtl/stringconcat.hxx
@@ -150,13 +150,11 @@ template<std::size_t N> struct ToStringHelper<sal_Unicode const[N]> {
     static bool const allowOUStringConcat = true;
 };
 
-template<char C> struct ToStringHelper<OUStringLiteral1_<C>> {
+template<sal_Unicode C> struct ToStringHelper<OUStringLiteral1_<C>> {
     static int length(OUStringLiteral1_<C>) { return 1; }
-    static char * addData(char * buffer, OUStringLiteral1_<C> literal)
-    { return addDataHelper(buffer, &literal.c, 1); }
     static sal_Unicode * addData(
         sal_Unicode * buffer, OUStringLiteral1_<C> literal)
-    { return addDataLiteral(buffer, &literal.c, 1); }
+    { return addDataHelper(buffer, &literal.c, 1); }
     static bool const allowOStringConcat = false;
     static bool const allowOUStringConcat = true;
 };
diff --git a/include/rtl/stringutils.hxx b/include/rtl/stringutils.hxx
index 1e5761f..6965347 100644
--- a/include/rtl/stringutils.hxx
+++ b/include/rtl/stringutils.hxx
@@ -36,13 +36,13 @@ namespace rtl
 #if defined LIBO_INTERNAL_ONLY
 /// @cond INTERNAL
 
-/** A simple wrapper around an ASCII character literal.
+/** A simple wrapper around a sal_Unicode character literal.
 
-    Can be useful to pass a char constant with ASCII value into a
-    OUString-related function that is optimized for ASCII string literal
-    arguments.  That is, instead of
+    Can be useful to pass a sal_Unicode constant into an OUString-related
+    function that is optimized for UTF-16 string literal arguments.  That is,
+    instead of
 
-      char const WILDCARD = '%';
+      sal_Unicode const WILDCARD = '%';
       ...
       if (s[i] == WILDCARD) ...
       ...
@@ -50,7 +50,7 @@ namespace rtl
 
     use
 
-      char const WILDCARD = '%';
+      sal_Unicode const WILDCARD = '%';
       ...
       if (s[i] == WILDCARD) ...
       ...
@@ -58,7 +58,7 @@ namespace rtl
 
     to avoid creating a temporary OUString instance, and instead pick the
     endsWith overload actually designed to take an argument of type
-    char const[N].
+    sal_Unicode const[N].
 
     Instances of OUStringLiteral1 need to be const, as those literal-optimized
     functions take the literal argument by non-const lvalue reference, for
@@ -71,18 +71,15 @@ namespace rtl
 
     @since LibreOffice 5.0
 */
-template<char C> struct SAL_WARN_UNUSED OUStringLiteral1_ {
-    static_assert(
-        static_cast<unsigned char>(C) < 0x80,
-        "non-ASCII character in OUStringLiteral1");
-    char const c = C;
+template<sal_Unicode C> struct SAL_WARN_UNUSED OUStringLiteral1_ {
+    sal_Unicode const c = C;
 };
 #if defined _MSC_VER && _MSC_VER <= 1900 && !defined __clang__
     // Visual Studio 2015
-template<char C> using OUStringLiteral1 = OUStringLiteral1_<C>;
+template<sal_Unicode C> using OUStringLiteral1 = OUStringLiteral1_<C>;
 #pragma warning(disable: 4239)
 #else
-template<char C> using OUStringLiteral1 = OUStringLiteral1_<C> const;
+template<sal_Unicode C> using OUStringLiteral1 = OUStringLiteral1_<C> const;
 #endif
 
 /// @endcond
@@ -181,7 +178,7 @@ struct ConstCharArrayDetector<sal_Unicode const [N], T> {
         sal_Unicode const (& literal)[N])
     { return literal; }
 };
-template<char C, typename T> struct ConstCharArrayDetector<
+template<sal_Unicode C, typename T> struct ConstCharArrayDetector<
 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
         && !defined __clang__
     OUStringLiteral1_<C> const,
@@ -190,11 +187,11 @@ template<char C, typename T> struct ConstCharArrayDetector<
 #endif
     T>
 {
-    typedef T Type;
-    static const std::size_t length = 1;
-    static const bool ok = true;
-    static bool isValid(OUStringLiteral1_<C>) { return true; }
-    static char const * toPointer(OUStringLiteral1_<C> const & literal)
+    using TypeUtf16 = T;
+    static SAL_CONSTEXPR bool const ok = true;
+    static SAL_CONSTEXPR std::size_t const length = 1;
+    static SAL_CONSTEXPR sal_Unicode const * toPointer(
+        OUStringLiteral1_<C> const & literal)
     { return &literal.c; }
 };
 #endif
@@ -212,7 +209,7 @@ struct ExceptConstCharArrayDetector< const char[ N ] >
 #if defined LIBO_INTERNAL_ONLY
 template<std::size_t N>
 struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
-template<char C> struct ExceptConstCharArrayDetector<
+template<sal_Unicode C> struct ExceptConstCharArrayDetector<
 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
         && !defined __clang__
     OUStringLiteral1_<C> const
@@ -243,7 +240,7 @@ struct ExceptCharArrayDetector< const char[ N ] >
 #if defined LIBO_INTERNAL_ONLY
 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
 template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
-template<char C> struct ExceptCharArrayDetector<OUStringLiteral1_<C>> {};
+template<sal_Unicode C> struct ExceptCharArrayDetector<OUStringLiteral1_<C>> {};
 #endif
 
 template< typename T1, typename T2 = void >
diff --git a/sal/qa/rtl/strings/test_oustring_stringliterals.cxx b/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
index aa496a4..ec4bbe2 100644
--- a/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
+++ b/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
@@ -218,18 +218,20 @@ void test::oustring::StringLiterals::checkOUStringLiteral()
 void test::oustring::StringLiterals::checkOUStringLiteral1()
 {
     auto l1 = rtlunittest::OUStringLiteral1<'A'>();
-    CPPUNIT_ASSERT_EQUAL('A', l1.c);
+    CPPUNIT_ASSERT_EQUAL(sal_Unicode('A'), l1.c);
 
     char const c2 = 'A';
     auto l2 = rtlunittest::OUStringLiteral1<c2>();
-    CPPUNIT_ASSERT_EQUAL('A', l2.c);
+    CPPUNIT_ASSERT_EQUAL(sal_Unicode('A'), l2.c);
 
     // char c3 = 'A'; auto l3 = rtlunittest::OUStringLiteral1<c3>();
 
     auto l4 = rtlunittest::OUStringLiteral1<sal_Unicode('A')>();
-    CPPUNIT_ASSERT_EQUAL('A', l4.c);
+    CPPUNIT_ASSERT_EQUAL(sal_Unicode('A'), l4.c);
 
-    // auto l5 = rtlunittest::OUStringLiteral1<sal_Unicode(0x100)>();
+    sal_Unicode const c5 = 0x100;
+    auto l5 = rtlunittest::OUStringLiteral1<c5>();
+    CPPUNIT_ASSERT_EQUAL(c5, l5.c);
 
     rtl::OUString s1{rtlunittest::OUStringLiteral1<'A'>()};
     CPPUNIT_ASSERT_EQUAL(sal_Int32(1), s1.getLength());
commit 0c8fa58a2d73702770687ed15b98822d09f96ac3
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Sat Aug 27 21:27:38 2016 +0200

    Support ConstCharArrayDetector also for UTF-16 arrays
    
    The long-term benefit will be support of C++11 char16_t string literals (for
    cases of string literals with non-ASCII content) once we drop any compilers that
    don't support those yet.  The short-term benefit is support for an improved
    OUStringLiteral1 that accepts any sal_Unicode value, not just ASCII ones (see
    next commit).
    
    Change-Id: I3f8f6697d7eb62b5176b7e812b5a5113c53b83a4
    Reviewed-on: https://gerrit.libreoffice.org/28445
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Stephan Bergmann <sbergman at redhat.com>

diff --git a/config_host/config_global.h.in b/config_host/config_global.h.in
index dd959a9..e70cd5a 100644
--- a/config_host/config_global.h.in
+++ b/config_host/config_global.h.in
@@ -15,6 +15,7 @@ Any change in this header will cause a rebuild of almost everything.
 #define HAVE_CXX11_CONSTEXPR 0
 #define HAVE_CXX14_CONSTEXPR 0
 #define HAVE_CXX11_REF_QUALIFIER 0
+#define HAVE_CXX11_UTF16_STRING_LITERAL 0
 #define HAVE_CXX14_SIZED_DEALLOCATION 0
 #define HAVE_GCC_BUILTIN_ATOMIC 0
 /* _Pragma */
diff --git a/configure.ac b/configure.ac
index 0cf2dba..6b28083 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6390,6 +6390,20 @@ if test "$cxx11_ref_qualifier" = yes; then
     AC_DEFINE([HAVE_CXX11_REF_QUALIFIER])
 fi
 
+AC_MSG_CHECKING([whether $CXX supports C++11 char16_t string literals])
+save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="$CXXFLAGS $CXXFLAGS_CXX11"
+AC_LANG_PUSH([C++])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+    auto s = u"";
+    ]])], [cxx11_utf16_string_literal=yes], [cxx11_utf16_string_literal=no])
+AC_LANG_POP([C++])
+CXXFLAGS=$save_CXXFLAGS
+AC_MSG_RESULT([$cxx11_utf16_string_literal])
+if test "$cxx11_utf16_string_literal" = yes; then
+    AC_DEFINE([HAVE_CXX11_UTF16_STRING_LITERAL])
+fi
+
 AC_MSG_CHECKING([whether $CXX supports C++14 sized deallocation])
 dnl At least Clang -fsanitize=address causes "multiple definition of
 dnl `operator delete(void*, unsigned long)'" also defined in
diff --git a/include/rtl/stringconcat.hxx b/include/rtl/stringconcat.hxx
index f381786..5a32bf9 100644
--- a/include/rtl/stringconcat.hxx
+++ b/include/rtl/stringconcat.hxx
@@ -12,6 +12,7 @@
 
 #include <rtl/stringutils.hxx>
 
+#include <cstddef>
 #include <string.h>
 
 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
@@ -141,6 +142,14 @@ struct ToStringHelper< const char[ N ] >
     static const bool allowOUStringConcat = true;
     };
 
+template<std::size_t N> struct ToStringHelper<sal_Unicode const[N]> {
+    static int length(sal_Unicode const[N]) { return N - 1; }
+    static sal_Unicode * addData(sal_Unicode * buffer, sal_Unicode const str[N])
+    { return addDataHelper(buffer, str, N - 1); }
+    static bool const allowOStringConcat = false;
+    static bool const allowOUStringConcat = true;
+};
+
 template<char C> struct ToStringHelper<OUStringLiteral1_<C>> {
     static int length(OUStringLiteral1_<C>) { return 1; }
     static char * addData(char * buffer, OUStringLiteral1_<C> literal)
diff --git a/include/rtl/stringutils.hxx b/include/rtl/stringutils.hxx
index 23cad71..1e5761f 100644
--- a/include/rtl/stringutils.hxx
+++ b/include/rtl/stringutils.hxx
@@ -172,6 +172,15 @@ struct ConstCharArrayDetector< const char[ N ], T >
     static char const * toPointer(char const (& literal)[N]) { return literal; }
 };
 #if defined LIBO_INTERNAL_ONLY
+template<std::size_t N, typename T>
+struct ConstCharArrayDetector<sal_Unicode const [N], T> {
+    using TypeUtf16 = T;
+    static SAL_CONSTEXPR bool const ok = true;
+    static SAL_CONSTEXPR std::size_t const length = N - 1;
+    static SAL_CONSTEXPR sal_Unicode const * toPointer(
+        sal_Unicode const (& literal)[N])
+    { return literal; }
+};
 template<char C, typename T> struct ConstCharArrayDetector<
 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
         && !defined __clang__
@@ -201,6 +210,8 @@ struct ExceptConstCharArrayDetector< const char[ N ] >
 {
 };
 #if defined LIBO_INTERNAL_ONLY
+template<std::size_t N>
+struct ExceptConstCharArrayDetector<sal_Unicode const[N]> {};
 template<char C> struct ExceptConstCharArrayDetector<
 #if defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ <= 8 \
         && !defined __clang__
@@ -230,6 +241,8 @@ struct ExceptCharArrayDetector< const char[ N ] >
 {
 };
 #if defined LIBO_INTERNAL_ONLY
+template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode[N]> {};
+template<std::size_t N> struct ExceptCharArrayDetector<sal_Unicode const[N]> {};
 template<char C> struct ExceptCharArrayDetector<OUStringLiteral1_<C>> {};
 #endif
 
diff --git a/include/rtl/ustrbuf.hxx b/include/rtl/ustrbuf.hxx
index 1b10679..8cfcabe 100644
--- a/include/rtl/ustrbuf.hxx
+++ b/include/rtl/ustrbuf.hxx
@@ -146,6 +146,24 @@ public:
 #endif
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    OUStringBuffer(
+        T & literal,
+        typename libreoffice_internal::ConstCharArrayDetector<
+            T, libreoffice_internal::Dummy>::TypeUtf16
+                = libreoffice_internal::Dummy()):
+        pData(nullptr),
+        nCapacity(libreoffice_internal::ConstCharArrayDetector<T>::length + 16)
+    {
+        rtl_uStringbuffer_newFromStr_WithLength(
+            &pData,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+    }
+#endif
+
 #ifdef RTL_STRING_UNITTEST
     /**
      * Only used by unittests to detect incorrect conversions.
@@ -484,6 +502,20 @@ public:
         return *this;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<
+        T, OUStringBuffer &>::TypeUtf16
+    append(T & literal) {
+        rtl_uStringbuffer_insert(
+            &pData, &nCapacity, getLength(),
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        return *this;
+    }
+#endif
+
 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
     /**
      @overload
@@ -836,6 +868,20 @@ public:
         return *this;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<
+        T, OUStringBuffer &>::TypeUtf16
+    insert(sal_Int32 offset, T & literal) {
+        rtl_uStringbuffer_insert(
+            &pData, &nCapacity, offset,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        return *this;
+    }
+#endif
+
     /**
         Inserts the string representation of the <code>sal_Bool</code>
         argument into this string buffer.
@@ -1225,6 +1271,21 @@ public:
         return n < 0 ? n : n + fromIndex;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
+    indexOf(T & literal, sal_Int32 fromIndex = 0) const {
+        assert(fromIndex >= 0);
+        auto n = rtl_ustr_indexOfStr_WithLength(
+            pData->buffer + fromIndex, pData->length - fromIndex,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        return n < 0 ? n : n + fromIndex;
+    }
+#endif
+
     /**
        Returns the index within this string of the last occurrence of
        the specified substring, searching backward starting at the end.
@@ -1290,6 +1351,19 @@ public:
             libreoffice_internal::ConstCharArrayDetector<T>::length);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
+    lastIndexOf(T & literal) const {
+        return rtl_ustr_lastIndexOfStr_WithLength(
+            pData->buffer, pData->length,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+    }
+#endif
+
     /**
        Strip the given character from the start of the buffer.
 
diff --git a/include/rtl/ustring.h b/include/rtl/ustring.h
index aa58e58..831ecd6 100644
--- a/include/rtl/ustring.h
+++ b/include/rtl/ustring.h
@@ -1458,6 +1458,28 @@ SAL_DLLPUBLIC void SAL_CALL rtl_uString_newConcatAsciiL(
     rtl_uString ** newString, rtl_uString * left, char const * right,
     sal_Int32 rightLength);
 
+/** Create a new string that is the concatenation of two other strings.
+
+    The new string does not necessarily have a reference count of 1 (in cases
+    where the UTF-16 string is empty), so it must not be modified without
+    checking the reference count.
+
+    @param newString pointer to the new string. The pointed-to data must be null
+    or a valid string.
+
+    @param left a valid string.
+
+    @param right must not be null and must point to memory of at least
+    \p rightLength UTF-16 code units
+
+    @param rightLength the length of the \p right string; must be non-negative
+
+    @since LibreOffice 5.3
+ */
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newConcatUtf16L(
+    rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
+    sal_Int32 rightLength);
+
 /** Create a new string by replacing a substring of another string.
 
     The new string results from replacing a number of characters (count),
@@ -1632,6 +1654,114 @@ SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceFirstAsciiLAsciiL(
     sal_Int32 fromLength, char const * to, sal_Int32 toLength,
     sal_Int32 * index) SAL_THROW_EXTERN_C();
 
+/** Create a new string by replacing the first occurrence of a given substring
+    with another substring.
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength ASCII bytes
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength UTF-16 code units
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @param[in,out] index  pointer to a start index, must not be null; upon entry
+    to the function its value is the index into the original string at which to
+    start searching for the \p from substring, the value must be non-negative
+    and not greater than the original string's length; upon exit from the
+    function its value is the index into the original string at which the
+    replacement took place (or would have taken place if \p newStr points to
+    null upon return) or -1 if no replacement took place
+
+    @since LibreOffice 5.3
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceFirstAsciiLUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, char const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C();
+
+/** Create a new string by replacing the first occurrence of a given substring
+    with another substring.
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength UTF-16 code units
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength ASCII bytes
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @param[in,out] index  pointer to a start index, must not be null; upon entry
+    to the function its value is the index into the original string at which to
+    start searching for the \p from substring, the value must be non-negative
+    and not greater than the original string's length; upon exit from the
+    function its value is the index into the original string at which the
+    replacement took place (or would have taken place if \p newStr points to
+    null upon return) or -1 if no replacement took place
+
+    @since LibreOffice 5.3
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceFirstUtf16LAsciiL(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, char const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C();
+
+/** Create a new string by replacing the first occurrence of a given substring
+    with another substring.
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength UTF-16 code units
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength UTF-16 code units
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @param[in,out] index  pointer to a start index, must not be null; upon entry
+    to the function its value is the index into the original string at which to
+    start searching for the \p from substring, the value must be non-negative
+    and not greater than the original string's length; upon exit from the
+    function its value is the index into the original string at which the
+    replacement took place (or would have taken place if \p newStr points to
+    null upon return) or -1 if no replacement took place
+
+    @since LibreOffice 5.3
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceFirstUtf16LUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C();
+
 /** Create a new string by replacing all occurrences of a given substring with
     another substring.
 
@@ -1752,6 +1882,99 @@ SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceAllAsciiLAsciiL(
     sal_Int32 fromLength, char const * to, sal_Int32 toLength)
     SAL_THROW_EXTERN_C();
 
+/** Create a new string by replacing all occurrences of a given substring with
+    another substring.
+
+    Replacing subsequent occurrences picks up only after a given replacement.
+    That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength ASCII bytes
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength UTF-16 code units
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @since LibreOffice 3.6
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceAllAsciiLUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, char const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C();
+
+/** Create a new string by replacing all occurrences of a given substring with
+    another substring.
+
+    Replacing subsequent occurrences picks up only after a given replacement.
+    That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength UTF-16 code units
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength ASCII bytes
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @since LibreOffice 3.6
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceAllUtf16LAsciiL(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, char const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C();
+
+/** Create a new string by replacing all occurrences of a given substring with
+    another substring.
+
+    Replacing subsequent occurrences picks up only after a given replacement.
+    That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
+
+    @param[in, out] newStr  pointer to the new string; must not be null; must
+    point to null or a valid rtl_uString; upon return, points to the newly
+    allocated string or to null if there was either an out-of-memory condition
+    or the resulting number of UTF-16 code units would have been larger than
+    SAL_MAX_INT32
+
+    @param str  pointer to the original string; must not be null
+
+    @param from  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p fromLength UTF-16 code units
+
+    @param fromLength  the length of the \p from substring; must be non-negative
+
+    @param to  pointer to the substring to be replaced; must not be null and
+    must point to memory of at least \p toLength UTF-16 code units
+
+    @param toLength  the length of the \p to substring; must be non-negative
+
+    @since LibreOffice 3.6
+*/
+SAL_DLLPUBLIC void SAL_CALL rtl_uString_newReplaceAllUtf16LUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C();
+
 /** Create a new string by converting all ASCII uppercase letters to lowercase
     within another string.
 
diff --git a/include/rtl/ustring.hxx b/include/rtl/ustring.hxx
index 8ac9882..5c09765 100644
--- a/include/rtl/ustring.hxx
+++ b/include/rtl/ustring.hxx
@@ -251,6 +251,27 @@ public:
 #endif
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> OUString(
+        T & literal,
+        typename libreoffice_internal::ConstCharArrayDetector<
+            T, libreoffice_internal::Dummy>::TypeUtf16
+                = libreoffice_internal::Dummy()):
+        pData(nullptr)
+    {
+        if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
+            rtl_uString_new(&pData);
+        } else {
+            rtl_uString_newFromStr_WithLength(
+                &pData,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length);
+        }
+    }
+#endif
+
 #ifdef RTL_STRING_UNITTEST
     /**
      * Only used by unittests to detect incorrect conversions.
@@ -451,6 +472,25 @@ public:
         return *this;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
+    operator =(T & literal) {
+        if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
+            rtl_uString_new(&pData);
+        } else {
+            rtl_uString_newFromStr_WithLength(
+                &pData,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length);
+        }
+        return *this;
+    }
+#endif
+
     /**
       Append a string to this string.
 
@@ -495,6 +535,30 @@ public:
     operator +=(T &) && = delete;
 #endif
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
+    operator +=(T & literal)
+#if HAVE_CXX11_REF_QUALIFIER
+        &
+#endif
+    {
+        rtl_uString_newConcatUtf16L(
+            &pData, pData,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        return *this;
+    }
+#if HAVE_CXX11_REF_QUALIFIER
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
+    operator +=(T &) && = delete;
+#endif
+#endif
+
 #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING"
     /**
      @overload
@@ -651,6 +715,19 @@ public:
             libreoffice_internal::ConstCharArrayDetector<T>::length);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
+    reverseCompareTo(T & literal) const {
+        return rtl_ustr_reverseCompare_WithLength(
+            pData->buffer, pData->length,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+    }
+#endif
+
     /**
       Perform a comparison of two strings.
 
@@ -738,6 +815,21 @@ public:
                 == 0);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    equalIgnoreAsciiCase(T & literal) const {
+        return
+            rtl_ustr_compareIgnoreAsciiCase_WithLength(
+                pData->buffer, pData->length,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length)
+            == 0;
+    }
+#endif
+
    /**
       Match against a substring appearing in this string.
 
@@ -778,6 +870,23 @@ public:
             == 0;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    match(T & literal, sal_Int32 fromIndex = 0) const {
+        assert(fromIndex >= 0);
+        return
+            rtl_ustr_shortenedCompare_WithLength(
+                pData->buffer + fromIndex, pData->length - fromIndex,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length,
+                libreoffice_internal::ConstCharArrayDetector<T>::length)
+            == 0;
+    }
+#endif
+
     /**
       Match against a substring appearing in this string, ignoring the case of
       ASCII letters.
@@ -822,6 +931,23 @@ public:
             == 0;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    matchIgnoreAsciiCase(T & literal, sal_Int32 fromIndex = 0) const {
+        assert(fromIndex >= 0);
+        return
+            rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength(
+                pData->buffer + fromIndex, pData->length - fromIndex,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length,
+                libreoffice_internal::ConstCharArrayDetector<T>::length)
+            == 0;
+    }
+#endif
+
     /**
       Compares two strings.
 
@@ -1141,6 +1267,29 @@ public:
         return b;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    startsWith(T & literal, OUString * rest = nullptr) const {
+        bool b
+            = (libreoffice_internal::ConstCharArrayDetector<T>::length
+               <= sal_uInt32(pData->length))
+            && (rtl_ustr_reverseCompare_WithLength(
+                    pData->buffer,
+                    libreoffice_internal::ConstCharArrayDetector<T>::length,
+                    libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                        literal),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length)
+                == 0);
+        if (b && rest != nullptr) {
+            *rest = copy(
+                libreoffice_internal::ConstCharArrayDetector<T>::length);
+        }
+        return b;
+    }
+#endif
+
     /**
       Check whether this string starts with a given string, ignoring the case of
       ASCII letters.
@@ -1197,6 +1346,29 @@ public:
         return b;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    startsWithIgnoreAsciiCase(T & literal, OUString * rest = nullptr) const {
+        bool b
+            = (libreoffice_internal::ConstCharArrayDetector<T>::length
+               <= sal_uInt32(pData->length))
+            && (rtl_ustr_compareIgnoreAsciiCase_WithLength(
+                    pData->buffer,
+                    libreoffice_internal::ConstCharArrayDetector<T>::length,
+                    libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                        literal),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length)
+                == 0);
+        if (b && rest != nullptr) {
+            *rest = copy(
+                libreoffice_internal::ConstCharArrayDetector<T>::length);
+        }
+        return b;
+    }
+#endif
+
     /**
       Check whether this string ends with a given substring.
 
@@ -1249,6 +1421,32 @@ public:
         return b;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    endsWith(T & literal, OUString * rest = nullptr) const {
+        bool b
+            = (libreoffice_internal::ConstCharArrayDetector<T>::length
+               <= sal_uInt32(pData->length))
+            && (rtl_ustr_reverseCompare_WithLength(
+                    (pData->buffer + pData->length
+                     - libreoffice_internal::ConstCharArrayDetector<T>::length),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length,
+                    libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                        literal),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length)
+                == 0);
+        if (b && rest != nullptr) {
+            *rest = copy(
+                0,
+                (getLength()
+                 - libreoffice_internal::ConstCharArrayDetector<T>::length));
+        }
+        return b;
+    }
+#endif
+
     /**
       Check whether this string ends with a given ASCII string.
 
@@ -1330,6 +1528,32 @@ public:
         return b;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    endsWithIgnoreAsciiCase(T & literal, OUString * rest = nullptr) const {
+        bool b
+            = (libreoffice_internal::ConstCharArrayDetector<T>::length
+               <= sal_uInt32(pData->length))
+            && (rtl_ustr_compareIgnoreAsciiCase_WithLength(
+                    (pData->buffer + pData->length
+                     - libreoffice_internal::ConstCharArrayDetector<T>::length),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length,
+                    libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                        literal),
+                    libreoffice_internal::ConstCharArrayDetector<T>::length)
+                == 0);
+        if (b && rest != nullptr) {
+            *rest = copy(
+                0,
+                (getLength()
+                 - libreoffice_internal::ConstCharArrayDetector<T>::length));
+        }
+        return b;
+    }
+#endif
+
     /**
       Check whether this string ends with a given ASCII string, ignoring the
       case of ASCII letters.
@@ -1439,6 +1663,57 @@ public:
     }
 
 #if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> friend inline
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    operator ==(OUString & string, T & literal) {
+        return
+            rtl_ustr_reverseCompare_WithLength(
+                string.pData->buffer, string.pData->length,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length)
+            == 0;
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> friend inline
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    operator ==(T & literal, OUString & string) {
+        return
+            rtl_ustr_reverseCompare_WithLength(
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length,
+                string.pData->buffer, string.pData->length)
+            == 0;
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> friend inline
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    operator !=(OUString & string, T & literal) {
+        return
+            rtl_ustr_reverseCompare_WithLength(
+                string.pData->buffer, string.pData->length,
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length)
+            != 0;
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> friend inline
+    typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
+    operator !=(T & literal, OUString & string) {
+        return
+            rtl_ustr_reverseCompare_WithLength(
+                libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
+                    literal),
+                libreoffice_internal::ConstCharArrayDetector<T>::length,
+                string.pData->buffer, string.pData->length)
+            != 0;
+    }
+#endif
+
+#if defined LIBO_INTERNAL_ONLY
     /// @cond INTERNAL
 
     /* Comparison between OUString and OUStringLiteral.
@@ -1622,6 +1897,21 @@ public:
         return n < 0 ? n : n + fromIndex;
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
+    indexOf(T & literal, sal_Int32 fromIndex = 0) const {
+        assert(fromIndex >= 0);
+        auto n = rtl_ustr_indexOfStr_WithLength(
+            pData->buffer + fromIndex, pData->length - fromIndex,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        return n < 0 ? n : n + fromIndex;
+    }
+#endif
+
     /**
        Returns the index within this string of the first occurrence of the
        specified ASCII substring, starting at the specified index.
@@ -1721,6 +2011,19 @@ public:
             libreoffice_internal::ConstCharArrayDetector<T>::length);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T>
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, sal_Int32>::TypeUtf16
+    lastIndexOf(T & literal) const {
+        return rtl_ustr_lastIndexOfStr_WithLength(
+            pData->buffer, pData->length,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+    }
+#endif
+
     /**
        Returns the index within this string of the last occurrence of the
        specified ASCII substring.
@@ -1974,6 +2277,121 @@ public:
         return OUString(s, SAL_NO_ACQUIRE);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString>::TypeUtf16
+    replaceFirst(T & from, OUString const & to, sal_Int32 * index = nullptr)
+        const
+    {
+        rtl_uString * s = nullptr;
+        sal_Int32 i = 0;
+        rtl_uString_newReplaceFirstUtf16LUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T>::length,
+            to.pData->buffer, to.pData->length, index == nullptr ? &i : index);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString>::TypeUtf16
+    replaceFirst(OUString const & from, T & to, sal_Int32 * index = nullptr)
+        const
+    {
+        rtl_uString * s = nullptr;
+        sal_Int32 i = 0;
+        rtl_uString_newReplaceFirstUtf16LUtf16L(
+            &s, pData, from.pData->buffer, from.pData->length,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T>::length,
+            index == nullptr ? &i : index);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::TypeUtf16
+        >::TypeUtf16
+    replaceFirst(T1 & from, T2 & to, sal_Int32 * index = nullptr) const {
+        rtl_uString * s = nullptr;
+        sal_Int32 i = 0;
+        rtl_uString_newReplaceFirstUtf16LUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length,
+            index == nullptr ? &i : index);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::Type
+        >::TypeUtf16
+    replaceFirst(T1 & from, T2 & to, sal_Int32 * index = nullptr) const {
+        rtl_uString * s = nullptr;
+        sal_Int32 i = 0;
+        rtl_uString_newReplaceFirstUtf16LAsciiL(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length,
+            index == nullptr ? &i : index);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::TypeUtf16
+        >::Type
+    replaceFirst(T1 & from, T2 & to, sal_Int32 * index = nullptr) const {
+        rtl_uString * s = nullptr;
+        sal_Int32 i = 0;
+        rtl_uString_newReplaceFirstAsciiLUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length,
+            index == nullptr ? &i : index);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+#endif
+
     /**
       Returns a new string resulting from replacing all occurrences of a given
       substring with another substring.
@@ -2076,6 +2494,108 @@ public:
         return OUString(s, SAL_NO_ACQUIRE);
     }
 
+#if defined LIBO_INTERNAL_ONLY
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString>::TypeUtf16
+    replaceAll(T & from, OUString const & to) const {
+        rtl_uString * s = nullptr;
+        rtl_uString_newReplaceAllUtf16LUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T>::length,
+            to.pData->buffer, to.pData->length);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<T, OUString>::TypeUtf16
+    replaceAll(OUString const & from, T & to) const {
+        rtl_uString * s = nullptr;
+        rtl_uString_newReplaceAllUtf16LUtf16L(
+            &s, pData, from.pData->buffer, from.pData->length,
+            libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T>::length);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::TypeUtf16
+        >::TypeUtf16
+    replaceAll(T1 & from, T2 & to) const {
+        rtl_uString * s = nullptr;
+        rtl_uString_newReplaceAllUtf16LUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::Type
+        >::TypeUtf16
+    replaceAll(T1 & from, T2 & to) const {
+        rtl_uString * s = nullptr;
+        rtl_uString_newReplaceAllUtf16LAsciiL(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+    /** @overload @since LibreOffice 5.3 */
+    template<typename T1, typename T2> SAL_WARN_UNUSED_RESULT
+    typename
+        libreoffice_internal::ConstCharArrayDetector<
+            T1,
+            typename libreoffice_internal::ConstCharArrayDetector<
+                T2, OUString>::TypeUtf16
+        >::Type
+    replaceAll(T1 & from, T2 & to) const {
+        rtl_uString * s = nullptr;
+        rtl_uString_newReplaceAllAsciiLUtf16L(
+            &s, pData,
+            libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
+            libreoffice_internal::ConstCharArrayDetector<T1>::length,
+            libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
+            libreoffice_internal::ConstCharArrayDetector<T2>::length);
+        if (s == nullptr) {
+            throw std::bad_alloc();
+                // should be std::length_error if resulting would be too large
+        }
+        return OUString(s, SAL_NO_ACQUIRE);
+    }
+#endif
+
     /**
       Converts from this string all ASCII uppercase characters (65-90)
       to ASCII lowercase characters (97-122).
diff --git a/sal/qa/rtl/strings/test_oustring_stringliterals.cxx b/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
index df9aecd..aa496a4 100644
--- a/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
+++ b/sal/qa/rtl/strings/test_oustring_stringliterals.cxx
@@ -19,6 +19,7 @@ extern bool rtl_string_unittest_non_const_literal_function;
 #include <utility>
 
 #include <sal/types.h>
+#include <config_global.h>
 #include <cppunit/TestFixture.h>
 #include <cppunit/extensions/HelperMacros.h>
 #include "rtl/string.h"
@@ -37,6 +38,7 @@ private:
     void checkBuffer();
     void checkOUStringLiteral();
     void checkOUStringLiteral1();
+    void checkUtf16();
 
     void testcall( const char str[] );
 
@@ -48,6 +50,7 @@ CPPUNIT_TEST(checkNonconstChar);
 CPPUNIT_TEST(checkBuffer);
 CPPUNIT_TEST(checkOUStringLiteral);
 CPPUNIT_TEST(checkOUStringLiteral1);
+CPPUNIT_TEST(checkUtf16);
 CPPUNIT_TEST_SUITE_END();
 };
 
@@ -247,6 +250,76 @@ void test::oustring::StringLiterals::checkOUStringLiteral1()
     CPPUNIT_ASSERT_EQUAL(sal_Unicode('b'), s2[1]);
 }
 
+void test::oustring::StringLiterals::checkUtf16() {
+#if HAVE_CXX11_UTF16_STRING_LITERAL
+    rtl::OUString s1(u"abc");
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("abc"), s1);
+    s1 = u"de";
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("de"), s1);
+    s1 += u"fde";
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("defde"), s1);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), s1.reverseCompareTo(u"defde"));
+    CPPUNIT_ASSERT(s1.equalIgnoreAsciiCase(u"DEFDE"));
+    CPPUNIT_ASSERT(s1.match(u"fde", 2));
+    CPPUNIT_ASSERT(s1.matchIgnoreAsciiCase(u"FDE", 2));
+    rtl::OUString s2;
+    CPPUNIT_ASSERT(s1.startsWith(u"de", &s2));
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"fde"), s2);
+    CPPUNIT_ASSERT(s1.startsWithIgnoreAsciiCase(u"DEFD", &s2));
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"e"), s2);
+    CPPUNIT_ASSERT(s1.endsWith(u"de", &s2));
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"def"), s2);
+    CPPUNIT_ASSERT(s1.endsWithIgnoreAsciiCase(u"EFDE", &s2));
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString(u"d"), s2);
+    CPPUNIT_ASSERT(s1 == u"defde");
+    CPPUNIT_ASSERT(u"defde" == s1);
+    CPPUNIT_ASSERT(s1 != u"abc");
+    CPPUNIT_ASSERT(u"abc" != s1);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), s1.indexOf(u"de", 1));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), s1.lastIndexOf(u"de"));
+    sal_Int32 i = 0;
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfde"),
+        s1.replaceFirst(u"de", rtl::OUString("abc"), &i));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfde"),
+        s1.replaceFirst(rtl::OUString("de"), u"abc", &i));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfde"), s1.replaceFirst(u"de", u"abc", &i));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfde"), s1.replaceFirst(u"de", "abc", &i));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfde"), s1.replaceFirst("de", u"abc", &i));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), i);
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", rtl::OUString("abc")));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfabc"), s1.replaceAll(rtl::OUString("de"), u"abc"));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", u"abc"));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfabc"), s1.replaceAll(u"de", "abc"));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString(u"abcfabc"), s1.replaceAll("de", u"abc"));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString("abcdef"), rtl::OUString(rtl::OUString("abc") + u"def"));
+    CPPUNIT_ASSERT_EQUAL(
+        rtl::OUString("abcdef"), rtl::OUString(u"abc" + rtl::OUString("def")));
+    rtl::OUStringBuffer b(u"abc");
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("abc"), b.toString());
+    b.append(u"def");
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("abcdef"), b.toString());
+    b.insert(2, u"gabab");
+    CPPUNIT_ASSERT_EQUAL(rtl::OUString("abgababcdef"), b.toString());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), b.indexOf(u"ab", 1));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), b.lastIndexOf(u"ab"));
+#endif
+}
+
 }} // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(test::oustring::StringLiterals);
diff --git a/sal/rtl/ustring.cxx b/sal/rtl/ustring.cxx
index b00c9c8..b1fb82a 100644
--- a/sal/rtl/ustring.cxx
+++ b/sal/rtl/ustring.cxx
@@ -631,6 +631,27 @@ void rtl_uString_newConcatAsciiL(
     (*newString)->length = n;
 }
 
+void rtl_uString_newConcatUtf16L(
+    rtl_uString ** newString, rtl_uString * left, sal_Unicode const * right,
+    sal_Int32 rightLength)
+{
+    assert(newString != nullptr);
+    assert(left != nullptr);
+    assert(right != nullptr);
+    assert(rightLength >= 0);
+    if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
+        throw std::length_error("rtl_uString_newConcatUtf16L");
+    }
+    sal_Int32 n = left->length + rightLength;
+    rtl_uString_assign(newString, left);
+    rtl_uString_ensureCapacity(newString, n);
+    memcpy(
+        (*newString)->buffer + (*newString)->length, right,
+        rightLength * sizeof (sal_Unicode));
+    (*newString)->buffer[n] = 0;
+    (*newString)->length = n;
+}
+
 /* ======================================================================= */
 
 static int rtl_ImplGetFastUTF8UnicodeLen( const sal_Char* pStr, sal_Int32 nLen, bool * ascii )
@@ -1296,6 +1317,140 @@ void rtl_uString_newReplaceFirstAsciiLAsciiL(
     *index = i;
 }
 
+void rtl_uString_newReplaceFirstAsciiLUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, char const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+    assert(str != nullptr);
+    assert(index != nullptr);
+    assert(*index >= 0 && *index <= str->length);
+    assert(fromLength >= 0);
+    assert(to != nullptr);
+    assert(toLength >= 0);
+    sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
+        str->buffer + *index, str->length - *index, from, fromLength);
+    if (i == -1) {
+        rtl_uString_assign(newStr, str);
+    } else {
+        assert(i <= str->length - *index);
+        i += *index;
+        assert(fromLength <= str->length);
+        if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+            rtl_uString_release(*newStr);
+            *newStr = nullptr;
+        } else {
+            sal_Int32 n = str->length - fromLength + toLength;
+            rtl_uString_acquire(str); // in case *newStr == str
+            rtl_uString_new_WithLength(newStr, n);
+            if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+                (*newStr)->length = n;
+                assert(i >= 0 && i < str->length);
+                memcpy(
+                    (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+                memcpy(
+                    (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
+                memcpy(
+                    (*newStr)->buffer + i + toLength,
+                    str->buffer + i + fromLength,
+                    (str->length - i - fromLength) * sizeof (sal_Unicode));
+            }
+            rtl_uString_release(str);
+        }
+    }
+    *index = i;
+}
+
+void rtl_uString_newReplaceFirstUtf16LAsciiL(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, char const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+    assert(str != nullptr);
+    assert(index != nullptr);
+    assert(*index >= 0 && *index <= str->length);
+    assert(fromLength >= 0);
+    assert(to != nullptr);
+    assert(toLength >= 0);
+    sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+        str->buffer + *index, str->length - *index, from, fromLength);
+    if (i == -1) {
+        rtl_uString_assign(newStr, str);
+    } else {
+        assert(i <= str->length - *index);
+        i += *index;
+        assert(fromLength <= str->length);
+        if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+            rtl_uString_release(*newStr);
+            *newStr = nullptr;
+        } else {
+            sal_Int32 n = str->length - fromLength + toLength;
+            rtl_uString_acquire(str); // in case *newStr == str
+            rtl_uString_new_WithLength(newStr, n);
+            if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+                (*newStr)->length = n;
+                assert(i >= 0 && i < str->length);
+                memcpy(
+                    (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+                for (sal_Int32 j = 0; j != toLength; ++j) {
+                    assert(static_cast< unsigned char >(to[j]) <= 0x7F);
+                    (*newStr)->buffer[i + j] = to[j];
+                }
+                memcpy(
+                    (*newStr)->buffer + i + toLength,
+                    str->buffer + i + fromLength,
+                    (str->length - i - fromLength) * sizeof (sal_Unicode));
+            }
+            rtl_uString_release(str);
+        }
+    }
+    *index = i;
+}
+
+void rtl_uString_newReplaceFirstUtf16LUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength,
+    sal_Int32 * index) SAL_THROW_EXTERN_C()
+{
+    assert(str != nullptr);
+    assert(index != nullptr);
+    assert(*index >= 0 && *index <= str->length);
+    assert(fromLength >= 0);
+    assert(to != nullptr);
+    assert(toLength >= 0);
+    sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
+        str->buffer + *index, str->length - *index, from, fromLength);
+    if (i == -1) {
+        rtl_uString_assign(newStr, str);
+    } else {
+        assert(i <= str->length - *index);
+        i += *index;
+        assert(fromLength <= str->length);
+        if (str->length - fromLength > SAL_MAX_INT32 - toLength) {
+            rtl_uString_release(*newStr);
+            *newStr = nullptr;
+        } else {
+            sal_Int32 n = str->length - fromLength + toLength;
+            rtl_uString_acquire(str); // in case *newStr == str
+            rtl_uString_new_WithLength(newStr, n);
+            if (n != 0 && /*TODO:*/ *newStr != nullptr) {
+                (*newStr)->length = n;
+                assert(i >= 0 && i < str->length);
+                memcpy(
+                    (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
+                memcpy(
+                    (*newStr)->buffer + i, to, toLength * sizeof (sal_Unicode));
+                memcpy(
+                    (*newStr)->buffer + i + toLength,
+                    str->buffer + i + fromLength,
+                    (str->length - i - fromLength) * sizeof (sal_Unicode));
+            }
+            rtl_uString_release(str);
+        }
+    }
+    *index = i;
+}
+
 void rtl_uString_newReplaceAll(
     rtl_uString ** newStr, rtl_uString * str, rtl_uString const * from,
     rtl_uString const * to) SAL_THROW_EXTERN_C()
@@ -1364,4 +1519,52 @@ void rtl_uString_newReplaceAllAsciiLAsciiL(
     }
 }
 
+void rtl_uString_newReplaceAllAsciiLUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, char const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C()
+{
+    assert(toLength >= 0);
+    rtl_uString_assign(newStr, str);
+    for (sal_Int32 i = 0;; i += toLength) {
+        rtl_uString_newReplaceFirstAsciiLUtf16L(
+            newStr, *newStr, from, fromLength, to, toLength, &i);
+        if (i == -1 || *newStr == nullptr) {
+            break;
+        }
+    }
+}
+
+void rtl_uString_newReplaceAllUtf16LAsciiL(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, char const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C()
+{
+    assert(toLength >= 0);
+    rtl_uString_assign(newStr, str);
+    for (sal_Int32 i = 0;; i += toLength) {
+        rtl_uString_newReplaceFirstUtf16LAsciiL(
+            newStr, *newStr, from, fromLength, to, toLength, &i);
+        if (i == -1 || *newStr == nullptr) {
+            break;
+        }
+    }
+}
+
+void rtl_uString_newReplaceAllUtf16LUtf16L(
+    rtl_uString ** newStr, rtl_uString * str, sal_Unicode const * from,
+    sal_Int32 fromLength, sal_Unicode const * to, sal_Int32 toLength)
+    SAL_THROW_EXTERN_C()
+{
+    assert(toLength >= 0);
+    rtl_uString_assign(newStr, str);
+    for (sal_Int32 i = 0;; i += toLength) {
+        rtl_uString_newReplaceFirstUtf16LUtf16L(
+            newStr, *newStr, from, fromLength, to, toLength, &i);
+        if (i == -1 || *newStr == nullptr) {
+            break;
+        }
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/util/sal.map b/sal/util/sal.map
index 1ccac61..d9995e1e 100644
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -695,6 +695,17 @@ LIBO_UDK_5.2 { # symbols available in >= LibO 5.2
         osl_getShortUserName;
 } LIBO_UDK_5.1;
 
+LIBO_UDK_5.3 { # symbols available in >= LibO 5.3
+    global:
+        rtl_uString_newConcatUtf16L;
+        rtl_uString_newReplaceAllAsciiLUtf16L;
+        rtl_uString_newReplaceAllUtf16LAsciiL;
+        rtl_uString_newReplaceAllUtf16LUtf16L;
+        rtl_uString_newReplaceFirstAsciiLUtf16L;
+        rtl_uString_newReplaceFirstUtf16LAsciiL;
+        rtl_uString_newReplaceFirstUtf16LUtf16L;
+} LIBO_UDK_5.2;
+
 PRIVATE_1.0 {
     global:
         osl_detail_ObjectRegistry_storeAddresses;


More information about the Libreoffice-commits mailing list