From 0c8fa58a2d73702770687ed15b98822d09f96ac3 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Sat, 27 Aug 2016 21:27:38 +0200 Subject: 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 Reviewed-by: Stephan Bergmann --- config_host/config_global.h.in | 1 + configure.ac | 14 + include/rtl/stringconcat.hxx | 9 + include/rtl/stringutils.hxx | 13 + include/rtl/ustrbuf.hxx | 74 +++ include/rtl/ustring.h | 223 +++++++++ include/rtl/ustring.hxx | 520 +++++++++++++++++++++ .../rtl/strings/test_oustring_stringliterals.cxx | 73 +++ sal/rtl/ustring.cxx | 203 ++++++++ sal/util/sal.map | 11 + 10 files changed, 1141 insertions(+) diff --git a/config_host/config_global.h.in b/config_host/config_global.h.in index dd959a9fd170..e70cd5a28905 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 0cf2dba4cb09..6b2808354e14 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 f381786eae4b..5a32bf930019 100644 --- a/include/rtl/stringconcat.hxx +++ b/include/rtl/stringconcat.hxx @@ -12,6 +12,7 @@ #include +#include #include #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING" @@ -141,6 +142,14 @@ struct ToStringHelper< const char[ N ] > static const bool allowOUStringConcat = true; }; +template struct ToStringHelper { + 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 struct ToStringHelper> { static int length(OUStringLiteral1_) { return 1; } static char * addData(char * buffer, OUStringLiteral1_ literal) diff --git a/include/rtl/stringutils.hxx b/include/rtl/stringutils.hxx index 23cad71a00b3..1e5761f0fab4 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 +struct ConstCharArrayDetector { + 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 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 +struct ExceptConstCharArrayDetector {}; template 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 struct ExceptCharArrayDetector {}; +template struct ExceptCharArrayDetector {}; template struct ExceptCharArrayDetector> {}; #endif diff --git a/include/rtl/ustrbuf.hxx b/include/rtl/ustrbuf.hxx index 1b1067977a38..8cfcabe043b4 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 + OUStringBuffer( + T & literal, + typename libreoffice_internal::ConstCharArrayDetector< + T, libreoffice_internal::Dummy>::TypeUtf16 + = libreoffice_internal::Dummy()): + pData(nullptr), + nCapacity(libreoffice_internal::ConstCharArrayDetector::length + 16) + { + rtl_uStringbuffer_newFromStr_WithLength( + &pData, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector< + T, OUStringBuffer &>::TypeUtf16 + append(T & literal) { + rtl_uStringbuffer_insert( + &pData, &nCapacity, getLength(), + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector< + T, OUStringBuffer &>::TypeUtf16 + insert(sal_Int32 offset, T & literal) { + rtl_uStringbuffer_insert( + &pData, &nCapacity, offset, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::length); + return *this; + } +#endif + /** Inserts the string representation of the sal_Bool 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 + libreoffice_internal::ConstCharArrayDetector::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::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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::length); } +#if defined LIBO_INTERNAL_ONLY + /** @overload @since LibreOffice 5.3 */ + template + typename + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + lastIndexOf(T & literal) const { + return rtl_ustr_lastIndexOfStr_WithLength( + pData->buffer, pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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 aa58e5814911..831ecd66d9be 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 8ac988232a13..5c097656c917 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 OUString( + T & literal, + typename libreoffice_internal::ConstCharArrayDetector< + T, libreoffice_internal::Dummy>::TypeUtf16 + = libreoffice_internal::Dummy()): + pData(nullptr) + { + if (libreoffice_internal::ConstCharArrayDetector::length == 0) { + rtl_uString_new(&pData); + } else { + rtl_uString_newFromStr_WithLength( + &pData, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::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 + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator =(T & literal) { + if (libreoffice_internal::ConstCharArrayDetector::length == 0) { + rtl_uString_new(&pData); + } else { + rtl_uString_newFromStr_WithLength( + &pData, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::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 + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator +=(T & literal) +#if HAVE_CXX11_REF_QUALIFIER + & +#endif + { + rtl_uString_newConcatUtf16L( + &pData, pData, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::length); + return *this; + } +#if HAVE_CXX11_REF_QUALIFIER + template + typename + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator +=(T &) && = delete; +#endif +#endif + #ifdef LIBO_INTERNAL_ONLY // "RTL_FAST_STRING" /** @overload @@ -651,6 +715,19 @@ public: libreoffice_internal::ConstCharArrayDetector::length); } +#if defined LIBO_INTERNAL_ONLY + /** @overload @since LibreOffice 5.3 */ + template + typename + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + reverseCompareTo(T & literal) const { + return rtl_ustr_reverseCompare_WithLength( + pData->buffer, pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + equalIgnoreAsciiCase(T & literal) const { + return + rtl_ustr_compareIgnoreAsciiCase_WithLength( + pData->buffer, pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::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::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::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::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + startsWith(T & literal, OUString * rest = nullptr) const { + bool b + = (libreoffice_internal::ConstCharArrayDetector::length + <= sal_uInt32(pData->length)) + && (rtl_ustr_reverseCompare_WithLength( + pData->buffer, + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + == 0); + if (b && rest != nullptr) { + *rest = copy( + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + startsWithIgnoreAsciiCase(T & literal, OUString * rest = nullptr) const { + bool b + = (libreoffice_internal::ConstCharArrayDetector::length + <= sal_uInt32(pData->length)) + && (rtl_ustr_compareIgnoreAsciiCase_WithLength( + pData->buffer, + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + == 0); + if (b && rest != nullptr) { + *rest = copy( + libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + endsWith(T & literal, OUString * rest = nullptr) const { + bool b + = (libreoffice_internal::ConstCharArrayDetector::length + <= sal_uInt32(pData->length)) + && (rtl_ustr_reverseCompare_WithLength( + (pData->buffer + pData->length + - libreoffice_internal::ConstCharArrayDetector::length), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + == 0); + if (b && rest != nullptr) { + *rest = copy( + 0, + (getLength() + - libreoffice_internal::ConstCharArrayDetector::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 libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + endsWithIgnoreAsciiCase(T & literal, OUString * rest = nullptr) const { + bool b + = (libreoffice_internal::ConstCharArrayDetector::length + <= sal_uInt32(pData->length)) + && (rtl_ustr_compareIgnoreAsciiCase_WithLength( + (pData->buffer + pData->length + - libreoffice_internal::ConstCharArrayDetector::length), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + == 0); + if (b && rest != nullptr) { + *rest = copy( + 0, + (getLength() + - libreoffice_internal::ConstCharArrayDetector::length)); + } + return b; + } +#endif + /** Check whether this string ends with a given ASCII string, ignoring the case of ASCII letters. @@ -1438,6 +1662,57 @@ public: libreoffice_internal::ConstCharArrayDetector::length); } +#if defined LIBO_INTERNAL_ONLY + /** @overload @since LibreOffice 5.3 */ + template friend inline + typename libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator ==(OUString & string, T & literal) { + return + rtl_ustr_reverseCompare_WithLength( + string.pData->buffer, string.pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + == 0; + } + /** @overload @since LibreOffice 5.3 */ + template friend inline + typename libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator ==(T & literal, OUString & string) { + return + rtl_ustr_reverseCompare_WithLength( + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length, + string.pData->buffer, string.pData->length) + == 0; + } + /** @overload @since LibreOffice 5.3 */ + template friend inline + typename libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator !=(OUString & string, T & literal) { + return + rtl_ustr_reverseCompare_WithLength( + string.pData->buffer, string.pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length) + != 0; + } + /** @overload @since LibreOffice 5.3 */ + template friend inline + typename libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + operator !=(T & literal, OUString & string) { + return + rtl_ustr_reverseCompare_WithLength( + libreoffice_internal::ConstCharArrayDetector::toPointer( + literal), + libreoffice_internal::ConstCharArrayDetector::length, + string.pData->buffer, string.pData->length) + != 0; + } +#endif + #if defined LIBO_INTERNAL_ONLY /// @cond INTERNAL @@ -1622,6 +1897,21 @@ public: return n < 0 ? n : n + fromIndex; } +#if defined LIBO_INTERNAL_ONLY + /** @overload @since LibreOffice 5.3 */ + template + typename + libreoffice_internal::ConstCharArrayDetector::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::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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::length); } +#if defined LIBO_INTERNAL_ONLY + /** @overload @since LibreOffice 5.3 */ + template + typename + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + lastIndexOf(T & literal) const { + return rtl_ustr_lastIndexOfStr_WithLength( + pData->buffer, pData->length, + libreoffice_internal::ConstCharArrayDetector::toPointer(literal), + libreoffice_internal::ConstCharArrayDetector::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 SAL_WARN_UNUSED_RESULT + typename + libreoffice_internal::ConstCharArrayDetector::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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::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 SAL_WARN_UNUSED_RESULT + typename + libreoffice_internal::ConstCharArrayDetector::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::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 SAL_WARN_UNUSED_RESULT + typename + libreoffice_internal::ConstCharArrayDetector::TypeUtf16 + replaceAll(T & from, OUString const & to) const { + rtl_uString * s = nullptr; + rtl_uString_newReplaceAllUtf16LUtf16L( + &s, pData, + libreoffice_internal::ConstCharArrayDetector::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::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 SAL_WARN_UNUSED_RESULT + typename + libreoffice_internal::ConstCharArrayDetector::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::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 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::toPointer(from), + libreoffice_internal::ConstCharArrayDetector::length, + libreoffice_internal::ConstCharArrayDetector::toPointer(to), + libreoffice_internal::ConstCharArrayDetector::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 df9aecd4fb21..aa496a4779f1 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 #include +#include #include #include #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 b00c9c80ef76..b1fb82a375dd 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::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 1ccac615b67f..d9995e1e4cae 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; -- cgit