mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
Refactor base64:
The implementation no longer uses std::string and instead works on raw memory buffers, which must be pre-sized accordingly.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
1.0.0-b38
|
1.0.0-b38
|
||||||
|
|
||||||
* Refactor static_string
|
* Refactor static_string
|
||||||
|
* Refactor base64
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -5,15 +5,6 @@
|
|||||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BEAST_DETAIL_BASE64_HPP
|
|
||||||
#define BEAST_DETAIL_BASE64_HPP
|
|
||||||
|
|
||||||
#include <cctype>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
|
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||||
Copyright notice:
|
Copyright notice:
|
||||||
@@ -44,77 +35,195 @@ namespace detail {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<class = void>
|
#ifndef BEAST_DETAIL_BASE64_HPP
|
||||||
std::string const&
|
#define BEAST_DETAIL_BASE64_HPP
|
||||||
base64_alphabet()
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
namespace base64 {
|
||||||
|
|
||||||
|
inline
|
||||||
|
char const*
|
||||||
|
get_alphabet()
|
||||||
{
|
{
|
||||||
static std::string const alphabet =
|
static char constexpr tab[] = {
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
};
|
||||||
"0123456789+/";
|
return &tab[0];
|
||||||
return alphabet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool
|
signed char const*
|
||||||
is_base64(unsigned char c)
|
get_inverse()
|
||||||
{
|
{
|
||||||
return (std::isalnum(c) || (c == '+') || (c == '/'));
|
static signed char constexpr tab[] = {
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63
|
||||||
|
-1, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
|
||||||
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
|
||||||
|
};
|
||||||
|
return &tab[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
|
||||||
std::string
|
/// Returns max chars needed to encode a base64 string
|
||||||
base64_encode (std::uint8_t const* data,
|
inline
|
||||||
std::size_t in_len)
|
std::size_t constexpr
|
||||||
|
encoded_size(std::size_t n)
|
||||||
{
|
{
|
||||||
|
return 4 * ((n + 2) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns max bytes needed to decode a base64 string
|
||||||
|
inline
|
||||||
|
std::size_t constexpr
|
||||||
|
decoded_size(std::size_t n)
|
||||||
|
{
|
||||||
|
return n / 4 * 3; // requires n&3==0, smaller
|
||||||
|
//return 3 * n / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Encode a series of octets as a padded, base64 string.
|
||||||
|
|
||||||
|
The resulting string will not be null terminated.
|
||||||
|
|
||||||
|
@par Requires
|
||||||
|
|
||||||
|
The memory pointed to by `out` points to valid memory
|
||||||
|
of at least `encoded_size(len)` bytes.
|
||||||
|
|
||||||
|
@return The number of characters written to `out`. This
|
||||||
|
will exclude any null termination.
|
||||||
|
*/
|
||||||
|
template<class = void>
|
||||||
|
std::size_t
|
||||||
|
encode(void* dest, void const* src, std::size_t len)
|
||||||
|
{
|
||||||
|
char* out = static_cast<char*>(dest);
|
||||||
|
char const* in = static_cast<char const*>(src);
|
||||||
|
auto const tab = base64::get_alphabet();
|
||||||
|
|
||||||
|
for(auto n = len / 3; n--;)
|
||||||
|
{
|
||||||
|
*out++ = tab[ (in[0] & 0xfc) >> 2];
|
||||||
|
*out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
|
||||||
|
*out++ = tab[((in[2] & 0xc0) >> 6) + ((in[1] & 0x0f) << 2)];
|
||||||
|
*out++ = tab[ in[2] & 0x3f];
|
||||||
|
in += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(len % 3)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
*out++ = tab[ (in[0] & 0xfc) >> 2];
|
||||||
|
*out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];
|
||||||
|
*out++ = tab[ (in[1] & 0x0f) << 2];
|
||||||
|
*out++ = '=';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
*out++ = tab[ (in[0] & 0xfc) >> 2];
|
||||||
|
*out++ = tab[((in[0] & 0x03) << 4)];
|
||||||
|
*out++ = '=';
|
||||||
|
*out++ = '=';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out - static_cast<char*>(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decode a padded base64 string into a series of octets.
|
||||||
|
|
||||||
|
@par Requires
|
||||||
|
|
||||||
|
The memory pointed to by `out` points to valid memory
|
||||||
|
of at least `decoded_size(len)` bytes.
|
||||||
|
|
||||||
|
@return The number of octets written to `out`, and
|
||||||
|
the number of characters read from the input string,
|
||||||
|
expressed as a pair.
|
||||||
|
*/
|
||||||
|
template<class = void>
|
||||||
|
std::pair<std::size_t, std::size_t>
|
||||||
|
decode(void* dest, char const* src, std::size_t len)
|
||||||
|
{
|
||||||
|
char* out = static_cast<char*>(dest);
|
||||||
|
auto in = reinterpret_cast<unsigned char const*>(src);
|
||||||
unsigned char c3[3], c4[4];
|
unsigned char c3[3], c4[4];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
std::string ret;
|
auto const inverse = base64::get_inverse();
|
||||||
ret.reserve (3 + in_len * 8 / 6);
|
|
||||||
|
|
||||||
char const* alphabet (base64_alphabet().data());
|
while(len-- && *in != '=')
|
||||||
|
|
||||||
while(in_len--)
|
|
||||||
{
|
{
|
||||||
c3[i++] = *(data++);
|
auto const v = inverse[*in];
|
||||||
if(i == 3)
|
if(v == -1)
|
||||||
|
break;
|
||||||
|
++in;
|
||||||
|
c4[i] = v;
|
||||||
|
if(++i == 4)
|
||||||
{
|
{
|
||||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
||||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
||||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
||||||
c4[3] = c3[2] & 0x3f;
|
|
||||||
for(i = 0; (i < 4); i++)
|
for(i = 0; i < 3; i++)
|
||||||
ret += alphabet[c4[i]];
|
*out++ = c3[i];
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i)
|
if(i)
|
||||||
{
|
{
|
||||||
for(j = i; j < 3; j++)
|
c3[0] = ( c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
||||||
c3[j] = '\0';
|
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
||||||
|
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
||||||
|
|
||||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
for(j = 0; j < i - 1; j++)
|
||||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
*out++ = c3[j];
|
||||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
|
||||||
c4[3] = c3[2] & 0x3f;
|
|
||||||
|
|
||||||
for(j = 0; (j < i + 1); j++)
|
|
||||||
ret += alphabet[c4[j]];
|
|
||||||
|
|
||||||
while((i++ < 3))
|
|
||||||
ret += '=';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return {out - static_cast<char*>(dest),
|
||||||
|
in - reinterpret_cast<unsigned char const*>(src)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // base64
|
||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
std::string
|
std::string
|
||||||
base64_encode (std::string const& s)
|
base64_encode (std::uint8_t const* data,
|
||||||
|
std::size_t len)
|
||||||
|
{
|
||||||
|
std::string dest;
|
||||||
|
dest.resize(base64::encoded_size(len));
|
||||||
|
dest.resize(base64::encode(&dest[0], data, len));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::string
|
||||||
|
base64_encode(std::string const& s)
|
||||||
{
|
{
|
||||||
return base64_encode (reinterpret_cast <
|
return base64_encode (reinterpret_cast <
|
||||||
std::uint8_t const*> (s.data()), s.size());
|
std::uint8_t const*> (s.data()), s.size());
|
||||||
@@ -124,52 +233,12 @@ template<class = void>
|
|||||||
std::string
|
std::string
|
||||||
base64_decode(std::string const& data)
|
base64_decode(std::string const& data)
|
||||||
{
|
{
|
||||||
auto in_len = data.size();
|
std::string dest;
|
||||||
unsigned char c3[3], c4[4];
|
dest.resize(base64::decoded_size(data.size()));
|
||||||
int i = 0;
|
auto const result = base64::decode(
|
||||||
int j = 0;
|
&dest[0], data.data(), data.size());
|
||||||
int in_ = 0;
|
dest.resize(result.first);
|
||||||
|
return dest;
|
||||||
std::string ret;
|
|
||||||
ret.reserve (in_len * 6 / 8); // ???
|
|
||||||
|
|
||||||
while(in_len-- && (data[in_] != '=') &&
|
|
||||||
is_base64(data[in_]))
|
|
||||||
{
|
|
||||||
c4[i++] = data[in_]; in_++;
|
|
||||||
if(i == 4) {
|
|
||||||
for(i = 0; i < 4; i++)
|
|
||||||
c4[i] = static_cast<unsigned char>(
|
|
||||||
base64_alphabet().find(c4[i]));
|
|
||||||
|
|
||||||
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
|
||||||
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
|
||||||
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
|
||||||
|
|
||||||
for(i = 0; (i < 3); i++)
|
|
||||||
ret += c3[i];
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(i)
|
|
||||||
{
|
|
||||||
for(j = i; j < 4; j++)
|
|
||||||
c4[j] = 0;
|
|
||||||
|
|
||||||
for(j = 0; j < 4; j++)
|
|
||||||
c4[j] = static_cast<unsigned char>(
|
|
||||||
base64_alphabet().find(c4[j]));
|
|
||||||
|
|
||||||
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
|
||||||
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
|
||||||
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
|
||||||
|
|
||||||
for(j = 0; (j < i - 1); j++)
|
|
||||||
ret += c3[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
Reference in New Issue
Block a user