编译时 Base64 解码 C++
Compile-Time Base64 Decoding in C++
是否可以在编译时将base64编码数据解码为二进制数据?
我想到的东西看起来像这样:
constexpr auto decoded = decodeBase64<"SGVsbG8=">();
或
constexpr auto decoded = decodeBase64("SGVsbG8=");
我对最终decoded
类型没有特殊要求。
我发现很难用谷歌搜索 constexpr base64 解码器,所以我在这里改编了一个: https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594
由于这是 MIT 许可的,(叹气(,请务必在源文件中的某个地方打上这个:
/**
* The MIT License (MIT)
* Copyright (c) 2016 tomykaira
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
要从constexpr
函数返回字符串,您需要返回一个 char 数组。因为不能返回数组或std::string
,所以std::array
是最好的选择。但是有一个问题 - 由于标准监督,直到 C++17std::array
的[]
运算符都是非常常量。不过,您可以通过继承和添加构造函数来解决此问题:
template <size_t N>
struct fixed_string : std::array<char, N> {
constexpr fixed_string(const char (&input)[N]) : fixed_string(input, std::make_index_sequence<N>{}) {}
template <size_t... Is>
constexpr fixed_string(const char (&input)[N], std::index_sequence<Is...>) : std::array<char, N>{ input[Is]... } {}
};
更改解码器以使用它而不是std::string
,它似乎可以用作constexpr。需要 C++14,因为 C++11 constexpr 函数只能有一个返回语句:
template <size_t N>
constexpr const std::array<char, ((((N-1) >> 2) * 3) + 1)> decode(const char(&input)[N]) {
constexpr unsigned char kDecodingTable[] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static_assert(((N-1) & 3) == 0, "Input data size is not a multiple of 4");
char out[(((N-1) >> 2) * 3) + 1] {0};
size_t out_len = (N-1) / 4 * 3;
if (input[(N-1) - 1] == '=') out_len--;
if (input[(N-1) - 2] == '=') out_len--;
for (size_t i = 0, j = 0; i < N-1;) {
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
}
return fixed_string<(((N-1) >> 2) * 3) + 1>(out);
}
用法:
constexpr auto x = decode("aGVsbG8gd29ybGQ=");
/*...*/
printf(x.data()); // hello world
演示:https://godbolt.org/z/HFdk6Z
更新以解决来自 Marek R 和 Frank 的有用反馈
Parktomatomi的回答对找到这个解决方案有很大帮助。 使用 C++17 和 std::array 这似乎有效。
base64 解码器基于答案 https://stackoverflow.com/a/34571089/3158571
constexpr size_t decodeBase64Length(const char *s)
{
size_t len = std::char_traits<char>::length(s);
if (s[len - 2] == '=')
return (len / 4) * 3 - 2;
else if(s[len -1] == '=')
return (len / 4) * 3 - 1;
else
return (len / 4) * 3 ;
}
constexpr std::array<int, 256> prepareBase64DecodeTable() {
std::array<int, 256> T{ 0 }; // breaks constexpr: T.fill(-1) or missing initialization
for (int i = 0; i < 256; i++)
T[i] = -1;
for (int i = 0; i < 64; i++)
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
return T;
}
// based on https://stackoverflow.com/a/34571089/3158571
template<int N>
constexpr std::array<std::byte, N> decodeBase64(const char *b64Str)
{
constexpr auto T = prepareBase64DecodeTable();
std::array<std::byte, N> out = { std::byte(0) };
int valb = -8;
for (size_t i = 0, val = 0, posOut = 0; i < std::char_traits<char>::length(b64Str) && T[b64Str[i]] != -1; i++) {
val = (val << 6) + T[b64Str[i]];
valb += 6;
if (valb >= 0) {
out[posOut++] = std::byte((val >> valb) & 0xFF);
valb -= 8;
}
}
return out;
}
用法并不完美,因为我无法推断结果数组的长度,而无需将其显式传递为模板参数:
#define B64c "SGVsbG8xMg=="
constexpr auto b64 = decodeBase64<decodeBase64Length(B64c)>(B64c); // array<byte,7>
https://godbolt.org/z/-DX2-m 演示
- 无法解码base64+deflate数据
- 正在解码MSVC 32位版本的程序集(作业).没有手术做什么
- 使用已使用 java 编码的 openssl 解码数据
- 如何使用 OpenCV 解码在两个 UWP 应用之间发送的图像字节?
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 从原始字节解码协议缓冲区(以 C++为单位)
- FFmpeg——使用硬件加速进行视频解码
- 如何从WIC解码器确定自上而下/自下而上?
- 使用公钥加密消息:BER 解码错误
- 在CRC-16 CCITT中将数据从二进制解码为文本,我应该输入一个码字,使用CRC生成器进行编码
- 在 GLFW 窗口中显示 FFMPEG 解码帧
- 如何将 MJPEG 解码为原始 RGB(或 YUV)数据
- 编译时 Base64 解码 C++
- 解码H264流时如何跳过帧?
- 无法在 HEVC 解码器上设置输出类型 IMFTransform
- pyserial arduino 字节阵列解码问题
- 将帧从 h264 流解码到 OpenCV Mat
- 连接无线电流和 MP3 解码器
- 将数据包从C++服务器发送到NodeJs服务器时出现MessagePack解码错误
- h264_cuvid编解码器未找到