diff --git a/tdutils/td/utils/base64.cpp b/tdutils/td/utils/base64.cpp index 02ee20233..884fcf9a1 100644 --- a/tdutils/td/utils/base64.cpp +++ b/tdutils/td/utils/base64.cpp @@ -188,11 +188,8 @@ Result base64url_decode(Slice base64) { return output; } -bool is_base64(Slice input) { - if ((input.size() & 3) != 0) { - return false; - } - +template +static bool is_base64_impl(Slice input) { size_t padding_length = 0; while (!input.empty() && input.back() == '=') { input.remove_suffix(1); @@ -201,22 +198,35 @@ bool is_base64(Slice input) { if (padding_length >= 3) { return false; } + if ((!is_url || padding_length > 0) && ((input.size() + padding_length) & 3) != 0) { + return false; + } + if (is_url && (input.size() & 3) == 1) { + return false; + } - init_base64_table(); - for (size_t i = 0; i < input.size(); i++) { - if (char_to_value[input.ubegin()[i]] == 64) { + unsigned char *table; + if (is_url) { + init_base64url_table(); + table = url_char_to_value; + } else { + init_base64_table(); + table = char_to_value; + } + for (auto c:input) { + if (table[static_cast(c)] == 64) { return false; } } if ((input.size() & 3) == 2) { - auto value = char_to_value[input.back()]; + auto value = table[input.back()]; if ((value & 15) != 0) { return false; } } if ((input.size() & 3) == 3) { - auto value = char_to_value[input.back()]; + auto value = table[input.back()]; if ((value & 3) != 0) { return false; } @@ -225,13 +235,21 @@ bool is_base64(Slice input) { return true; } +bool is_base64(Slice input) { + return is_base64_impl(input); +} + +bool is_base64url(Slice input) { + return is_base64_impl(input); +} + string base64_filter(Slice input) { string res; res.reserve(input.size()); init_base64_table(); - for (size_t i = 0; i < input.size(); i++) { - if (char_to_value[input.ubegin()[i]] != 64 || input[i] == '=') { - res += input[i]; + for (auto c : input) { + if (char_to_value[static_cast(c)] != 64 || c == '=') { + res += c; } } return res; diff --git a/tdutils/td/utils/base64.h b/tdutils/td/utils/base64.h index d7a98495b..cef2b4cb3 100644 --- a/tdutils/td/utils/base64.h +++ b/tdutils/td/utils/base64.h @@ -19,6 +19,7 @@ string base64url_encode(Slice input); Result base64url_decode(Slice base64); bool is_base64(Slice input); +bool is_base64url(Slice input); string base64_filter(Slice input); diff --git a/tdutils/test/misc.cpp b/tdutils/test/misc.cpp index a2f542553..b86e1f030 100644 --- a/tdutils/test/misc.cpp +++ b/tdutils/test/misc.cpp @@ -115,6 +115,30 @@ TEST(Misc, errno_tls_bug) { } TEST(Misc, base64) { + ASSERT_TRUE(is_base64("dGVzdA==") == true); + ASSERT_TRUE(is_base64("dGVzdB==") == false); + ASSERT_TRUE(is_base64("dGVzdA=") == false); + ASSERT_TRUE(is_base64("dGVzdA") == false); + ASSERT_TRUE(is_base64("dGVz") == true); + ASSERT_TRUE(is_base64("") == true); + ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") == true); + ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") == false); + ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/") == false); + ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_") == false); + ASSERT_TRUE(is_base64("====") == false); + + ASSERT_TRUE(is_base64url("dGVzdA==") == true); + ASSERT_TRUE(is_base64url("dGVzdB==") == false); + ASSERT_TRUE(is_base64url("dGVzdA=") == false); + ASSERT_TRUE(is_base64url("dGVzdA") == true); + ASSERT_TRUE(is_base64url("dGVz") == true); + ASSERT_TRUE(is_base64url("") == true); + ASSERT_TRUE(is_base64url("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_") == true); + ASSERT_TRUE(is_base64url("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=") == false); + ASSERT_TRUE(is_base64url("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/") == false); + ASSERT_TRUE(is_base64url("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") == false); + ASSERT_TRUE(is_base64url("====") == false); + for (int l = 0; l < 300000; l += l / 20 + l / 1000 * 500 + 1) { for (int t = 0; t < 10; t++) { string s = rand_string(std::numeric_limits::min(), std::numeric_limits::max(), l); @@ -139,16 +163,6 @@ TEST(Misc, base64) { ASSERT_TRUE(base64_encode(" /'.;.';≤.];,].',[.;/,.;/]/..;!@#!*(%?::;!%\";") == "ICAgICAgLycuOy4nO+KJpC5dOyxdLicsWy47LywuOy9dLy4uOyFAIyEqKCU/" "Ojo7ISUiOw=="); - ASSERT_TRUE(is_base64("dGVzdA==") == true); - ASSERT_TRUE(is_base64("dGVzdB==") == false); - ASSERT_TRUE(is_base64("dGVzdA=") == false); - ASSERT_TRUE(is_base64("dGVzdA") == false); - ASSERT_TRUE(is_base64("dGVz") == true); - ASSERT_TRUE(is_base64("") == true); - ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") == true); - ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") == false); - ASSERT_TRUE(is_base64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-/") == false); - ASSERT_TRUE(is_base64("====") == false); } TEST(Misc, to_integer) {