Commit 7fa62c99 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

src: Clean up string utlity functions

parent 3e271481
......@@ -123,8 +123,11 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_inp_strlower",
shrpx::test_util_inp_strlower) ||
!CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) ||
!CU_add_test(pSuite, "util_to_token68", shrpx::test_util_to_token68) ||
!CU_add_test(pSuite, "util_percent_encode_token",
shrpx::test_util_percent_encode_token) ||
!CU_add_test(pSuite, "util_percent_decode",
shrpx::test_util_percent_decode) ||
!CU_add_test(pSuite, "util_quote_string",
shrpx::test_util_quote_string) ||
!CU_add_test(pSuite, "util_utox", shrpx::test_util_utox) ||
......@@ -145,6 +148,8 @@ int main(int argc, char *argv[]) {
shrpx::test_util_duration_str) ||
!CU_add_test(pSuite, "util_format_duration",
shrpx::test_util_format_duration) ||
!CU_add_test(pSuite, "util_starts_with", shrpx::test_util_starts_with) ||
!CU_add_test(pSuite, "util_ends_with", shrpx::test_util_ends_with) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
......
......@@ -123,6 +123,19 @@ std::string percent_encode_token(const std::string &target) {
return dest;
}
uint32_t hex_to_uint(char c) {
if (c <= '9') {
return c - '0';
}
if (c <= 'Z') {
return c - 'A' + 10;
}
if (c <= 'z') {
return c - 'a' + 10;
}
return c;
}
std::string percentDecode(std::string::const_iterator first,
std::string::const_iterator last) {
std::string result;
......@@ -130,15 +143,14 @@ std::string percentDecode(std::string::const_iterator first,
if (*first == '%') {
if (first + 1 != last && first + 2 != last && isHexDigit(*(first + 1)) &&
isHexDigit(*(first + 2))) {
std::string numstr(first + 1, first + 3);
result += strtol(numstr.c_str(), 0, 16);
result += (hex_to_uint(*(first + 1)) << 4) + hex_to_uint(*(first + 2));
first += 2;
} else {
result += *first;
continue;
}
} else {
result += *first;
continue;
}
result += *first;
}
return result;
}
......@@ -353,14 +365,6 @@ time_t parse_http_date(const std::string &s) {
return timegm(&tm);
}
bool startsWith(const std::string &a, const std::string &b) {
return startsWith(a.begin(), a.end(), b.begin(), b.end());
}
bool istartsWith(const std::string &a, const std::string &b) {
return istartsWith(a.begin(), a.end(), b.begin(), b.end());
}
namespace {
void streq_advance(const char **ap, const char **bp) {
for (; **ap && **bp && lowcase(**ap) == lowcase(**bp); ++*ap, ++*bp)
......@@ -376,24 +380,11 @@ bool istartsWith(const char *a, const char *b) {
return !*b;
}
bool istartsWith(const char *a, size_t n, const char *b) {
return istartsWith(a, a + n, b, b + strlen(b));
}
bool endsWith(const std::string &a, const std::string &b) {
return endsWith(a.begin(), a.end(), b.begin(), b.end());
}
bool strieq(const std::string &a, const std::string &b) {
if (a.size() != b.size()) {
return false;
}
for (size_t i = 0; i < a.size(); ++i) {
if (lowcase(a[i]) != lowcase(b[i])) {
return false;
}
}
return true;
return std::equal(std::begin(a), std::end(a), std::begin(b), CaseCmp());
}
bool strieq(const char *a, const char *b) {
......@@ -405,20 +396,6 @@ bool strieq(const char *a, const char *b) {
return !*a && !*b;
}
bool strieq(const char *a, const uint8_t *b, size_t bn) {
if (!a || !b) {
return false;
}
const uint8_t *blast = b + bn;
for (; *a && b != blast && lowcase(*a) == lowcase(*b); ++a, ++b)
;
return !*a && b == blast;
}
bool strieq(const char *a, const char *b, size_t bn) {
return strieq(a, reinterpret_cast<const uint8_t *>(b), bn);
}
int strcompare(const char *a, const uint8_t *b, size_t bn) {
assert(a && b);
const uint8_t *blast = b + bn;
......@@ -479,47 +456,38 @@ std::string format_hex(const unsigned char *s, size_t len) {
}
void to_token68(std::string &base64str) {
for (auto i = std::begin(base64str); i != std::end(base64str); ++i) {
switch (*i) {
std::transform(std::begin(base64str), std::end(base64str),
std::begin(base64str), [](char c) {
switch (c) {
case '+':
*i = '-';
break;
return '-';
case '/':
*i = '_';
break;
case '=':
base64str.erase(i, std::end(base64str));
return;
return '_';
default:
return c;
}
}
return;
});
base64str.erase(std::find(std::begin(base64str), std::end(base64str), '='));
}
void to_base64(std::string &token68str) {
for (auto i = std::begin(token68str); i != std::end(token68str); ++i) {
switch (*i) {
std::transform(std::begin(token68str), std::end(token68str),
std::begin(token68str), [](char c) {
switch (c) {
case '-':
*i = '+';
break;
return '+';
case '_':
*i = '/';
break;
return '/';
default:
return c;
}
}
});
if (token68str.size() & 0x3) {
token68str.append(4 - (token68str.size() & 0x3), '=');
}
return;
}
void inp_strlower(std::string &s) {
for (auto i = std::begin(s); i != std::end(s); ++i) {
if ('A' <= *i && *i <= 'Z') {
*i = (*i) - 'A' + 'a';
}
}
}
namespace {
// Calculates Damerau–Levenshtein distance between c-string a and b
// with given costs. swapcost, subcost, addcost and delcost are cost
......
......@@ -165,6 +165,10 @@ bool in_token(char c);
bool in_attr_char(char c);
// Returns integer corresponding to hex notation |c|. It is undefined
// if isHexDigit(c) is false.
uint32_t hex_to_uint(char c);
std::string percentEncode(const unsigned char *target, size_t len);
std::string percentEncode(const std::string &target);
......@@ -193,6 +197,32 @@ std::string iso8601_date(int64_t ms);
time_t parse_http_date(const std::string &s);
char upcase(char c);
inline char lowcase(char c) {
static unsigned char tbl[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z', 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255,
};
return tbl[static_cast<unsigned char>(c)];
}
template <typename InputIterator1, typename InputIterator2>
bool startsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
......@@ -202,17 +232,13 @@ bool startsWith(InputIterator1 first1, InputIterator1 last1,
return std::equal(first2, last2, first1);
}
bool startsWith(const std::string &a, const std::string &b);
inline bool startsWith(const std::string &a, const std::string &b) {
return startsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
struct CaseCmp {
bool operator()(char lhs, char rhs) const {
if ('A' <= lhs && lhs <= 'Z') {
lhs += 'a' - 'A';
}
if ('A' <= rhs && rhs <= 'Z') {
rhs += 'a' - 'A';
}
return lhs == rhs;
return lowcase(lhs) == lowcase(rhs);
}
};
......@@ -225,9 +251,16 @@ bool istartsWith(InputIterator1 first1, InputIterator1 last1,
return std::equal(first2, last2, first1, CaseCmp());
}
bool istartsWith(const std::string &a, const std::string &b);
inline bool istartsWith(const std::string &a, const std::string &b) {
return istartsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
template <typename InputIt>
bool istartsWith(InputIt a, size_t an, const char *b) {
return istartsWith(a, a + an, b, b + strlen(b));
}
bool istartsWith(const char *a, const char *b);
bool istartsWith(const char *a, size_t n, const char *b);
template <typename InputIterator1, typename InputIterator2>
bool endsWith(InputIterator1 first1, InputIterator1 last1,
......@@ -238,6 +271,10 @@ bool endsWith(InputIterator1 first1, InputIterator1 last1,
return std::equal(first2, last2, last1 - (last2 - first2));
}
inline bool endsWith(const std::string &a, const std::string &b) {
return endsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
template <typename InputIterator1, typename InputIterator2>
bool iendsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
......@@ -247,21 +284,28 @@ bool iendsWith(InputIterator1 first1, InputIterator1 last1,
return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());
}
bool endsWith(const std::string &a, const std::string &b);
inline bool iendsWith(const std::string &a, const std::string &b) {
return iendsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
int strcompare(const char *a, const uint8_t *b, size_t n);
template <typename InputIt> bool strieq(const char *a, InputIt b, size_t bn) {
if (!a) {
return false;
}
auto blast = b + bn;
for (; *a && b != blast && lowcase(*a) == lowcase(*b); ++a, ++b)
;
return !*a && b == blast;
}
bool strieq(const std::string &a, const std::string &b);
bool strieq(const char *a, const char *b);
bool strieq(const char *a, const uint8_t *b, size_t n);
bool strieq(const char *a, const char *b, size_t n);
template <typename A, typename B>
bool streq(const A *a, const B *b, size_t bn) {
if (!a || !b) {
template <typename InputIt> bool streq(const char *a, InputIt b, size_t bn) {
if (!a) {
return false;
}
auto blast = b + bn;
......@@ -270,46 +314,20 @@ bool streq(const A *a, const B *b, size_t bn) {
return !*a && b == blast;
}
template <typename A, typename B>
bool streq(const A *a, size_t alen, const B *b, size_t blen) {
template <typename InputIt1, typename InputIt2>
bool streq(InputIt1 a, size_t alen, InputIt2 b, size_t blen) {
if (alen != blen) {
return false;
}
return memcmp(a, b, alen) == 0;
return std::equal(a, a + alen, b);
}
bool strifind(const char *a, const char *b);
char upcase(char c);
char lowcase(char c);
inline char lowcase(char c) {
static unsigned char tbl[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z', 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255,
};
return tbl[static_cast<unsigned char>(c)];
}
// Lowercase |s| in place.
void inp_strlower(std::string &s);
inline void inp_strlower(std::string &s) {
std::transform(std::begin(s), std::end(s), std::begin(s), lowcase);
}
// Returns string representation of |n| with 2 fractional digits.
std::string dtos(double n);
......
......@@ -66,6 +66,18 @@ void test_util_strieq(void) {
CU_ASSERT(util::strieq(std::string(), std::string()));
CU_ASSERT(!util::strieq(std::string("alpha"), std::string("AlPhA ")));
CU_ASSERT(!util::strieq(std::string(), std::string("AlPhA ")));
CU_ASSERT(util::strieq("alpha", "alpha", 5));
CU_ASSERT(util::strieq("alpha", "AlPhA", 5));
CU_ASSERT(util::strieq("", static_cast<const char *>(nullptr), 0));
CU_ASSERT(!util::strieq("alpha", "AlPhA ", 6));
CU_ASSERT(!util::strieq("", "AlPhA ", 6));
CU_ASSERT(util::strieq("alpha", "alpha"));
CU_ASSERT(util::strieq("alpha", "AlPhA"));
CU_ASSERT(util::strieq("", ""));
CU_ASSERT(!util::strieq("alpha", "AlPhA "));
CU_ASSERT(!util::strieq("", "AlPhA "));
}
void test_util_inp_strlower(void) {
......@@ -92,6 +104,16 @@ void test_util_to_base64(void) {
CU_ASSERT("AAA++B/B" == x);
}
void test_util_to_token68(void) {
std::string x = "AAA++B/=";
util::to_token68(x);
CU_ASSERT("AAA--B_" == x);
x = "AAA++B/B";
util::to_token68(x);
CU_ASSERT("AAA--B_B" == x);
}
void test_util_percent_encode_token(void) {
CU_ASSERT("h2" == util::percent_encode_token("h2"));
CU_ASSERT("h3~" == util::percent_encode_token("h3~"));
......@@ -99,6 +121,21 @@ void test_util_percent_encode_token(void) {
CU_ASSERT("http%202" == util::percent_encode_token("http 2"));
}
void test_util_percent_decode(void) {
{
std::string s = "%66%6F%6f%62%61%72";
CU_ASSERT("foobar" == util::percentDecode(std::begin(s), std::end(s)));
}
{
std::string s = "%66%6";
CU_ASSERT("f%6" == util::percentDecode(std::begin(s), std::end(s)));
}
{
std::string s = "%66%";
CU_ASSERT("f%" == util::percentDecode(std::begin(s), std::end(s)));
}
}
void test_util_quote_string(void) {
CU_ASSERT("alpha" == util::quote_string("alpha"));
CU_ASSERT("" == util::quote_string(""));
......@@ -277,4 +314,28 @@ void test_util_format_duration(void) {
util::format_duration(std::chrono::microseconds(1050000)));
}
void test_util_starts_with(void) {
CU_ASSERT(util::startsWith("foo", "foo"));
CU_ASSERT(util::startsWith("fooo", "foo"));
CU_ASSERT(util::startsWith("ofoo", ""));
CU_ASSERT(!util::startsWith("ofoo", "foo"));
CU_ASSERT(util::istartsWith("FOO", "fOO"));
CU_ASSERT(util::startsWith("ofoo", ""));
CU_ASSERT(util::istartsWith("fOOo", "Foo"));
CU_ASSERT(!util::istartsWith("ofoo", "foo"));
}
void test_util_ends_with(void) {
CU_ASSERT(util::endsWith("foo", "foo"));
CU_ASSERT(util::endsWith("foo", ""));
CU_ASSERT(util::endsWith("ofoo", "foo"));
CU_ASSERT(!util::endsWith("ofoo", "fo"));
CU_ASSERT(util::iendsWith("fOo", "Foo"));
CU_ASSERT(util::iendsWith("foo", ""));
CU_ASSERT(util::iendsWith("oFoo", "fOO"));
CU_ASSERT(!util::iendsWith("ofoo", "fo"));
}
} // namespace shrpx
......@@ -31,7 +31,9 @@ void test_util_streq(void);
void test_util_strieq(void);
void test_util_inp_strlower(void);
void test_util_to_base64(void);
void test_util_to_token68(void);
void test_util_percent_encode_token(void);
void test_util_percent_decode(void);
void test_util_quote_string(void);
void test_util_utox(void);
void test_util_http_date(void);
......@@ -44,6 +46,8 @@ void test_util_parse_uint(void);
void test_util_parse_duration_with_unit(void);
void test_util_duration_str(void);
void test_util_format_duration(void);
void test_util_starts_with(void);
void test_util_ends_with(void);
} // namespace shrpx
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment