Base64 improvements (#1635)
This commit is contained in:
parent
eea916315e
commit
61073b4f74
|
@ -60,6 +60,9 @@ namespace utils
|
|||
/// Determine if the string is an integer
|
||||
DROGON_EXPORT bool isInteger(const std::string &str);
|
||||
|
||||
/// Determine if the string is base64 encoded
|
||||
DROGON_EXPORT bool isBase64(const std::string &str);
|
||||
|
||||
/// Generate random a string
|
||||
/**
|
||||
* @param length The string length
|
||||
|
@ -98,15 +101,46 @@ DROGON_EXPORT std::set<std::string> splitStringToSet(
|
|||
/// Get UUID string.
|
||||
DROGON_EXPORT std::string getUuid();
|
||||
|
||||
/// Get the encoded length of base64.
|
||||
DROGON_EXPORT size_t base64EncodedLength(unsigned int in_len,
|
||||
bool padded = true);
|
||||
|
||||
/// Encode the string to base64 format.
|
||||
DROGON_EXPORT std::string base64Encode(const unsigned char *bytes_to_encode,
|
||||
unsigned int in_len,
|
||||
bool url_safe = false);
|
||||
bool url_safe = false,
|
||||
bool padded = true);
|
||||
|
||||
/// Encode the string to base64 format.
|
||||
inline std::string base64Encode(string_view data,
|
||||
bool url_safe = false,
|
||||
bool padded = true)
|
||||
{
|
||||
return base64Encode((unsigned char *)data.data(),
|
||||
data.size(),
|
||||
url_safe,
|
||||
padded);
|
||||
}
|
||||
|
||||
/// Encode the string to base64 format with no padding.
|
||||
DROGON_EXPORT std::string base64EncodeUnpadded(
|
||||
const unsigned char *bytes_to_encode,
|
||||
unsigned int in_len,
|
||||
bool url_safe = false);
|
||||
|
||||
/// Encode the string to base64 format with no padding.
|
||||
inline std::string base64EncodeUnpadded(string_view data, bool url_safe = false)
|
||||
{
|
||||
return base64Encode(data, url_safe, false);
|
||||
}
|
||||
|
||||
/// Get the decoded length of base64.
|
||||
DROGON_EXPORT size_t base64DecodedLength(unsigned int in_len);
|
||||
|
||||
/// Decode the base64 format string.
|
||||
DROGON_EXPORT std::string base64Decode(const std::string &encoded_string);
|
||||
DROGON_EXPORT std::string base64Decode(string_view encoded_string);
|
||||
DROGON_EXPORT std::vector<char> base64DecodeToVector(
|
||||
const std::string &encoded_string);
|
||||
string_view encoded_string);
|
||||
|
||||
/// Check if the string need decoding
|
||||
DROGON_EXPORT bool needUrlDecoding(const char *begin, const char *end);
|
||||
|
|
|
@ -149,6 +149,14 @@ bool isInteger(const std::string &str)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool isBase64(const std::string &str)
|
||||
{
|
||||
for (auto c : str)
|
||||
if (!isBase64(c))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string genRandomString(int length)
|
||||
{
|
||||
static const char char_space[] =
|
||||
|
@ -387,11 +395,18 @@ std::string getUuid()
|
|||
#endif
|
||||
}
|
||||
|
||||
size_t base64EncodedLength(unsigned int in_len, bool padded)
|
||||
{
|
||||
return padded ? ((in_len + 3 - 1) / 3) * 4 : (in_len * 8 + 6 - 1) / 6;
|
||||
}
|
||||
|
||||
std::string base64Encode(const unsigned char *bytes_to_encode,
|
||||
unsigned int in_len,
|
||||
bool url_safe)
|
||||
bool url_safe,
|
||||
bool padded)
|
||||
{
|
||||
std::string ret;
|
||||
ret.reserve(base64EncodedLength(in_len, padded));
|
||||
int i = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
@ -428,27 +443,45 @@ std::string base64Encode(const unsigned char *bytes_to_encode,
|
|||
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (int j = 0; (j < i + 1); ++j)
|
||||
for (int j = 0; (j <= i); ++j)
|
||||
ret += charSet[char_array_4[j]];
|
||||
|
||||
while ((i++ < 3))
|
||||
ret += '=';
|
||||
if (padded)
|
||||
while ((++i < 4))
|
||||
ret += '=';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<char> base64DecodeToVector(const std::string &encoded_string)
|
||||
std::string base64EncodeUnpadded(const unsigned char *bytes_to_encode,
|
||||
unsigned int in_len,
|
||||
bool url_safe)
|
||||
{
|
||||
return base64Encode(bytes_to_encode, in_len, url_safe, false);
|
||||
}
|
||||
|
||||
size_t base64DecodedLength(unsigned int in_len)
|
||||
{
|
||||
return (in_len * 3) / 4;
|
||||
}
|
||||
|
||||
std::vector<char> base64DecodeToVector(string_view encoded_string)
|
||||
{
|
||||
auto in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int in_{0};
|
||||
char char_array_4[4], char_array_3[3];
|
||||
std::vector<char> ret;
|
||||
ret.reserve(in_len);
|
||||
ret.reserve(base64DecodedLength(in_len));
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=') &&
|
||||
isBase64(encoded_string[in_]))
|
||||
while (in_len-- && (encoded_string[in_] != '='))
|
||||
{
|
||||
if (!isBase64(encoded_string[in_]))
|
||||
{
|
||||
++in_;
|
||||
continue;
|
||||
}
|
||||
|
||||
char_array_4[i++] = encoded_string[in_];
|
||||
++in_;
|
||||
if (i == 4)
|
||||
|
@ -486,24 +519,31 @@ std::vector<char> base64DecodeToVector(const std::string &encoded_string)
|
|||
((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 (int j = 0; (j < i - 1); ++j)
|
||||
--i;
|
||||
for (int j = 0; (j < i); ++j)
|
||||
ret.push_back(char_array_3[j]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string base64Decode(const std::string &encoded_string)
|
||||
std::string base64Decode(string_view encoded_string)
|
||||
{
|
||||
auto in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int in_{0};
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
ret.reserve(base64DecodedLength(in_len));
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=') &&
|
||||
isBase64(encoded_string[in_]))
|
||||
while (in_len-- && (encoded_string[in_] != '='))
|
||||
{
|
||||
if (!isBase64(encoded_string[in_]))
|
||||
{
|
||||
++in_;
|
||||
continue;
|
||||
}
|
||||
|
||||
char_array_4[i++] = encoded_string[in_];
|
||||
++in_;
|
||||
if (i == 4)
|
||||
|
@ -540,7 +580,8 @@ std::string base64Decode(const std::string &encoded_string)
|
|||
((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 (int j = 0; (j < i - 1); ++j)
|
||||
--i;
|
||||
for (int j = 0; (j < i); ++j)
|
||||
ret += char_array_3[j];
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,34 @@
|
|||
DROGON_TEST(Base64)
|
||||
{
|
||||
std::string in{"drogon framework"};
|
||||
auto encoded = drogon::utils::base64Encode((const unsigned char *)in.data(),
|
||||
(unsigned int)in.length());
|
||||
auto encoded = drogon::utils::base64Encode(in);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(encoded == "ZHJvZ29uIGZyYW1ld29yaw==");
|
||||
CHECK(decoded == in);
|
||||
|
||||
SUBSECTION(InvalidChars)
|
||||
{
|
||||
auto decoded =
|
||||
drogon::utils::base64Decode("ZHJvZ2*9uIGZy**YW1ld2***9yaw*=*=");
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
||||
SUBSECTION(InvalidCharsNoPadding)
|
||||
{
|
||||
auto decoded =
|
||||
drogon::utils::base64Decode("ZHJvZ2*9uIGZy**YW1ld2***9yaw**");
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
||||
SUBSECTION(Unpadded)
|
||||
{
|
||||
std::string in{"drogon framework"};
|
||||
auto encoded = drogon::utils::base64EncodeUnpadded(in);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(encoded == "ZHJvZ29uIGZyYW1ld29yaw");
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
||||
SUBSECTION(LongString)
|
||||
{
|
||||
std::string in;
|
||||
|
@ -19,12 +41,9 @@ DROGON_TEST(Base64)
|
|||
{
|
||||
in.append(1, char(i));
|
||||
}
|
||||
auto out = drogon::utils::base64Encode((const unsigned char *)in.data(),
|
||||
(unsigned int)in.length());
|
||||
auto out = drogon::utils::base64Encode(in);
|
||||
auto out2 = drogon::utils::base64Decode(out);
|
||||
auto encoded =
|
||||
drogon::utils::base64Encode((const unsigned char *)in.data(),
|
||||
(unsigned int)in.length());
|
||||
auto encoded = drogon::utils::base64Encode(in);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
@ -32,15 +51,21 @@ DROGON_TEST(Base64)
|
|||
SUBSECTION(URLSafe)
|
||||
{
|
||||
std::string in{"drogon framework"};
|
||||
auto encoded =
|
||||
drogon::utils::base64Encode((const unsigned char *)in.data(),
|
||||
(unsigned int)in.length(),
|
||||
true);
|
||||
auto encoded = drogon::utils::base64Encode(in, true);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(encoded == "ZHJvZ29uIGZyYW1ld29yaw==");
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
||||
SUBSECTION(UnpaddedURLSafe)
|
||||
{
|
||||
std::string in{"drogon framework"};
|
||||
auto encoded = drogon::utils::base64EncodeUnpadded(in, true);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(encoded == "ZHJvZ29uIGZyYW1ld29yaw");
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
||||
SUBSECTION(LongURLSafe)
|
||||
{
|
||||
std::string in;
|
||||
|
@ -49,10 +74,7 @@ DROGON_TEST(Base64)
|
|||
{
|
||||
in.append(1, char(i));
|
||||
}
|
||||
auto encoded =
|
||||
drogon::utils::base64Encode((const unsigned char *)in.data(),
|
||||
(unsigned int)in.length(),
|
||||
true);
|
||||
auto encoded = drogon::utils::base64Encode(in, true);
|
||||
auto decoded = drogon::utils::base64Decode(encoded);
|
||||
CHECK(decoded == in);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue