From 0e7ba4e401211f2a08dbf1bff007e6edb78a2cfc Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Sun, 16 Feb 2020 22:42:48 +0800 Subject: [PATCH] Faster base64 (#63) Cool kids on the Internet use two tables to do base64. That looks cool. We should get it. --- src/misc.cpp | 49 ++++++++++++++++++++++++++++++++++--------------- src/misc.h | 4 +++- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index f9ee102..b6588e1 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -243,23 +243,37 @@ std::string base64_encode(const std::string &string_to_encode) } -std::string base64_decode(const std::string &encoded_string) +std::string base64_decode(const std::string &encoded_string, bool accept_urlsafe) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; + string_size in_len = encoded_string.size(); + string_size i = 0; + string_size in_ = 0; unsigned char char_array_4[4], char_array_3[3]; + static unsigned char dtable[256], itable[256], table_ready = 0; std::string ret; - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) + // Should not need thread_local with the flag... + if (!table_ready) { + // No memset needed for static/TLS + for (string_size k = 0; k < base64_chars.length(); k++) { + dtable[base64_chars[k]] = k; // decode (find) + itable[base64_chars[k]] = 1; // is_base64 + } + // Add urlsafe table + dtable['-'] = dtable['+']; itable['-'] = 2; + dtable['_'] = dtable['/']; itable['_'] = 2; + table_ready = 1; + } + + while (in_len-- && (encoded_string[in_] != '=') && + (accept_urlsafe ? itable[encoded_string[in_]] : (itable[encoded_string[in_]] == 1))) { char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) + if (i == 4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); + for (string_size j = 0; j < 4; j++) + char_array_4[j] = dtable[char_array_4[j]]; char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); @@ -273,17 +287,17 @@ std::string base64_decode(const std::string &encoded_string) if (i) { - for (j = i; j <4; j++) + for (string_size j = i; j <4; j++) char_array_4[j] = 0; - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); + for (string_size j = 0; j <4; j++) + char_array_4[j] = dtable[char_array_4[j]]; char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) + for (string_size j = 0; (j < i - 1); j++) ret += char_array_3[j]; } @@ -621,14 +635,19 @@ std::string urlsafe_base64_reverse(const std::string &encoded_string) return replace_all_distinct(replace_all_distinct(encoded_string, "-", "+"), "_", "/"); } +std::string urlsafe_base64(const std::string &encoded_string) +{ + return replace_all_distinct(replace_all_distinct(replace_all_distinct(encoded_string, "+", "-"), "/", "_"), "=", ""); +} + std::string urlsafe_base64_decode(const std::string &encoded_string) { - return base64_decode(urlsafe_base64_reverse(encoded_string)); + return base64_decode(encoded_string, true); } std::string urlsafe_base64_encode(const std::string &string_to_encode) { - return replace_all_distinct(replace_all_distinct(replace_all_distinct(base64_encode(string_to_encode), "+", "-"), "/", "_"), "=", ""); + return urlsafe_base64(base64_encode(string_to_encode)); } std::string getMD5(const std::string &data) diff --git a/src/misc.h b/src/misc.h index 39f7685..a70a348 100644 --- a/src/misc.h +++ b/src/misc.h @@ -13,6 +13,7 @@ #define PATH_SLASH "//" #endif // _WIN32 +typedef std::string::size_type string_size; typedef std::vector string_array; typedef const std::string &refCnstStr; @@ -23,12 +24,13 @@ static const std::string base64_chars = std::string UrlEncode(const std::string& str); std::string UrlDecode(const std::string& str); -std::string base64_decode(const std::string &encoded_string); +std::string base64_decode(const std::string &encoded_string, bool accept_urlsafe = false); std::string base64_encode(const std::string &string_to_encode); std::vector split(const std::string &s, const std::string &seperator); std::string getUrlArg(const std::string &url, const std::string &request); std::string replace_all_distinct(std::string str, const std::string &old_value, const std::string &new_value); +std::string urlsafe_base64(const std::string &encoded_string); std::string urlsafe_base64_reverse(const std::string &encoded_string); std::string urlsafe_base64_decode(const std::string &encoded_string); std::string urlsafe_base64_encode(const std::string &string_to_encode);