summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/utils/String16.h2
-rw-r--r--include/utils/Unicode.h1
-rw-r--r--libutils/String16.cpp5
-rw-r--r--libutils/Unicode.cpp29
-rw-r--r--libutils/tests/Unicode_test.cpp35
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);
+}
+
}