diff options
-rw-r--r-- | include/utils/String16.h | 2 | ||||
-rw-r--r-- | include/utils/Unicode.h | 1 | ||||
-rw-r--r-- | libutils/String16.cpp | 5 | ||||
-rw-r--r-- | libutils/Unicode.cpp | 29 | ||||
-rw-r--r-- | libutils/tests/Unicode_test.cpp | 35 |
5 files changed, 69 insertions, 3 deletions
diff --git a/include/utils/String16.h b/include/utils/String16.h index 4a5874a4c..07c4de746 100644 --- a/include/utils/String16.h +++ b/include/utils/String16.h @@ -94,6 +94,8 @@ public: bool startsWith(const String16& prefix) const; bool startsWith(const char16_t* prefix) const; + bool contains(const char16_t* chrs) const; + status_t makeLower(); status_t replaceAll(char16_t replaceThis, diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h index b76a5e268..a006082b0 100644 --- a/include/utils/Unicode.h +++ b/include/utils/Unicode.h @@ -29,6 +29,7 @@ size_t strlen16(const char16_t *); size_t strnlen16(const char16_t *, size_t); char16_t *strcpy16(char16_t *, const char16_t *); char16_t *strncpy16(char16_t *, const char16_t *, size_t); +char16_t *strstr16(const char16_t*, const char16_t*); // Version of comparison that supports embedded nulls. // This is different than strncmp() because we don't stop diff --git a/libutils/String16.cpp b/libutils/String16.cpp index 87eda1b35..ac12d8aa7 100644 --- a/libutils/String16.cpp +++ b/libutils/String16.cpp @@ -344,6 +344,11 @@ bool String16::startsWith(const char16_t* prefix) const return strncmp16(mString, prefix, ps) == 0; } +bool String16::contains(const char16_t* chrs) const +{ + return strstr16(mString, chrs) != nullptr; +} + status_t String16::makeLower() { const size_t N = size(); diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index 6f4b72176..ade896a02 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -222,11 +222,16 @@ int strncmp16(const char16_t *s1, const char16_t *s2, size_t n) char16_t ch; int d = 0; - while ( n-- ) { + if (n == 0) { + return 0; + } + + do { d = (int)(ch = *s1++) - (int)*s2++; - if ( d || !ch ) + if ( d || !ch ) { break; - } + } + } while (--n); return d; } @@ -284,6 +289,24 @@ size_t strnlen16(const char16_t *s, size_t maxlen) return ss-s; } +char16_t* strstr16(const char16_t* src, const char16_t* target) +{ + const char16_t needle = *target++; + if (needle != '\0') { + do { + do { + if (*src == '\0') { + return nullptr; + } + } while (*src++ != needle); + } while (strcmp16(src, target) != 0); + src--; + } + + return (char16_t*)src; +} + + int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2) { const char16_t* e1 = s1+n1; diff --git a/libutils/tests/Unicode_test.cpp b/libutils/tests/Unicode_test.cpp index 18c130c55..c263f75e2 100644 --- a/libutils/tests/Unicode_test.cpp +++ b/libutils/tests/Unicode_test.cpp @@ -29,6 +29,8 @@ protected: virtual void TearDown() { } + + char16_t const * const kSearchString = u"I am a leaf on the wind."; }; TEST_F(UnicodeTest, UTF8toUTF16ZeroLength) { @@ -112,4 +114,37 @@ TEST_F(UnicodeTest, UTF8toUTF16Normal) { << "should be NULL terminated"; } +TEST_F(UnicodeTest, strstr16EmptyTarget) { + EXPECT_EQ(strstr16(kSearchString, u""), kSearchString) + << "should return the original pointer"; +} + +TEST_F(UnicodeTest, strstr16SameString) { + const char16_t* result = strstr16(kSearchString, kSearchString); + EXPECT_EQ(kSearchString, result) + << "should return the original pointer"; +} + +TEST_F(UnicodeTest, strstr16TargetStartOfString) { + const char16_t* result = strstr16(kSearchString, u"I am"); + EXPECT_EQ(kSearchString, result) + << "should return the original pointer"; +} + + +TEST_F(UnicodeTest, strstr16TargetEndOfString) { + const char16_t* result = strstr16(kSearchString, u"wind."); + EXPECT_EQ(kSearchString+19, result); +} + +TEST_F(UnicodeTest, strstr16TargetWithinString) { + const char16_t* result = strstr16(kSearchString, u"leaf"); + EXPECT_EQ(kSearchString+7, result); +} + +TEST_F(UnicodeTest, strstr16TargetNotPresent) { + const char16_t* result = strstr16(kSearchString, u"soar"); + EXPECT_EQ(nullptr, result); +} + } |