src: Clean up string utlity functions
This commit is contained in:
parent
3e2714810a
commit
7fa62c9904
|
@ -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) ||
|
||||
|
|
102
src/util.cc
102
src/util.cc
|
@ -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
|
||||
|
|
198
src/util.h
198
src/util.h
|
@ -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,97 +197,8 @@ std::string iso8601_date(int64_t ms);
|
|||
|
||||
time_t parse_http_date(const std::string &s);
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool startsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, first1);
|
||||
}
|
||||
|
||||
bool startsWith(const std::string &a, const std::string &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;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool istartsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, first1, CaseCmp());
|
||||
}
|
||||
|
||||
bool istartsWith(const std::string &a, const std::string &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,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, last1 - (last2 - first2));
|
||||
}
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool iendsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());
|
||||
}
|
||||
|
||||
bool endsWith(const std::string &a, const std::string &b);
|
||||
|
||||
int strcompare(const char *a, const uint8_t *b, size_t n);
|
||||
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
auto blast = b + bn;
|
||||
for (; *a && b != blast && *a == *b; ++a, ++b)
|
||||
;
|
||||
return !*a && b == blast;
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
bool streq(const A *a, size_t alen, const B *b, size_t blen) {
|
||||
if (alen != blen) {
|
||||
return false;
|
||||
}
|
||||
return memcmp(a, b, alen) == 0;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -308,8 +223,111 @@ inline char lowcase(char c) {
|
|||
return tbl[static_cast<unsigned char>(c)];
|
||||
}
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool startsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, first1);
|
||||
}
|
||||
|
||||
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 {
|
||||
return lowcase(lhs) == lowcase(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool istartsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, first1, CaseCmp());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
template <typename InputIterator1, typename InputIterator2>
|
||||
bool endsWith(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
if (last1 - first1 < last2 - first2) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
template <typename InputIt> bool streq(const char *a, InputIt b, size_t bn) {
|
||||
if (!a) {
|
||||
return false;
|
||||
}
|
||||
auto blast = b + bn;
|
||||
for (; *a && b != blast && *a == *b; ++a, ++b)
|
||||
;
|
||||
return !*a && b == blast;
|
||||
}
|
||||
|
||||
template <typename InputIt1, typename InputIt2>
|
||||
bool streq(InputIt1 a, size_t alen, InputIt2 b, size_t blen) {
|
||||
if (alen != blen) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(a, a + alen, b);
|
||||
}
|
||||
|
||||
bool strifind(const char *a, const char *b);
|
||||
|
||||
// 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
|
||||
|
||||
|
|
Loading…
Reference in New Issue