C++ で無料で入手できる Base64 デコード コード スニペットはありますか?
13 に答える
これは、もともとRené Nyffeneggerによって書かれた実装を私が修正したものです。そして、なぜ私はそれを変更したのですか?std::string
オブジェクト内に格納されたバイナリ データを操作する必要があるとは思えなかったので;)
base64.h :
#ifndef _BASE64_H_
#define _BASE64_H_
#include <vector>
#include <string>
typedef unsigned char BYTE;
std::string base64_encode(BYTE const* buf, unsigned int bufLen);
std::vector<BYTE> base64_decode(std::string const&);
#endif
base64.cpp :
#include "base64.h"
#include <iostream>
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(BYTE c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(BYTE const* buf, unsigned int bufLen) {
std::string ret;
int i = 0;
int j = 0;
BYTE char_array_3[3];
BYTE char_array_4[4];
while (bufLen--) {
char_array_3[i++] = *(buf++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::vector<BYTE> base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
BYTE char_array_4[4], char_array_3[3];
std::vector<BYTE> ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
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 (i = 0; (i < 3); i++)
ret.push_back(char_array_3[i]);
i = 0;
}
}
if (i) {
for (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]);
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++) ret.push_back(char_array_3[j]);
}
return ret;
}
使用法は次のとおりです。
std::vector<BYTE> myData;
...
std::string encodedData = base64_encode(&myData[0], myData.size());
std::vector<BYTE> decodedData = base64_decode(encodedData);
C++ を使用した base 64 のエンコードとデコードを参照してください。
そのページの実装は次のとおりです。
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
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 (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (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]);
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++) ret += char_array_3[j];
}
return ret;
}
ここにはいくつかのスニペットがあります。ただし、これはコンパクトで効率的で、C++11 に適しています。
static std::string base64_encode(const std::string &in) {
std::string out;
int val = 0, valb = -6;
for (uchar c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]);
valb -= 6;
}
}
if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]);
while (out.size()%4) out.push_back('=');
return out;
}
static std::string base64_decode(const std::string &in) {
std::string out;
std::vector<int> T(256,-1);
for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
int val=0, valb=-8;
for (uchar c : in) {
if (T[c] == -1) break;
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val>>valb)&0xFF));
valb -= 8;
}
}
return out;
}
私はこれがよりうまくいくと思います:
#include <string>
static const char* B64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const int B64index[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
0, 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, 0, 0, 0, 0, 63,
0, 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
};
const std::string b64encode(const void* data, const size_t &len)
{
std::string result((len + 2) / 3 * 4, '=');
unsigned char *p = (unsigned char*) data;
char *str = &result[0];
size_t j = 0, pad = len % 3;
const size_t last = len - pad;
for (size_t i = 0; i < last; i += 3)
{
int n = int(p[i]) << 16 | int(p[i + 1]) << 8 | p[i + 2];
str[j++] = B64chars[n >> 18];
str[j++] = B64chars[n >> 12 & 0x3F];
str[j++] = B64chars[n >> 6 & 0x3F];
str[j++] = B64chars[n & 0x3F];
}
if (pad) /// Set padding
{
int n = --pad ? int(p[last]) << 8 | p[last + 1] : p[last];
str[j++] = B64chars[pad ? n >> 10 & 0x3F : n >> 2];
str[j++] = B64chars[pad ? n >> 4 & 0x03F : n << 4 & 0x3F];
str[j++] = pad ? B64chars[n << 2 & 0x3F] : '=';
}
return result;
}
const std::string b64decode(const void* data, const size_t &len)
{
if (len == 0) return "";
unsigned char *p = (unsigned char*) data;
size_t j = 0,
pad1 = len % 4 || p[len - 1] == '=',
pad2 = pad1 && (len % 4 > 2 || p[len - 2] != '=');
const size_t last = (len - pad1) / 4 << 2;
std::string result(last / 4 * 3 + pad1 + pad2, '\0');
unsigned char *str = (unsigned char*) &result[0];
for (size_t i = 0; i < last; i += 4)
{
int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]];
str[j++] = n >> 16;
str[j++] = n >> 8 & 0xFF;
str[j++] = n & 0xFF;
}
if (pad1)
{
int n = B64index[p[last]] << 18 | B64index[p[last + 1]] << 12;
str[j++] = n >> 16;
if (pad2)
{
n |= B64index[p[last + 2]] << 6;
str[j++] = n >> 8 & 0xFF;
}
}
return result;
}
std::string b64encode(const std::string& str)
{
return b64encode(str.c_str(), str.size());
}
std::string b64decode(const std::string& str64)
{
return b64decode(str64.c_str(), str64.size());
}
パフォーマンスの問題を指摘してくれた Jens Alfke に感謝し、この古い投稿にいくつかの変更を加えました。これは、以前よりもはるかに高速に動作します。その他の利点は、破損したデータをスムーズに処理できることです。
最終版: この種の問題では、速度はやり過ぎのように見えますが、楽しみのために、これを最速のアルゴリズムにするためにいくつかの変更を加えました。貴重な提案と優れたベンチマークを提供してくれた GaspardP に特に感謝します。
DaedalusAlphaの答えに対する私のバリエーション:
いくつかのテストを犠牲にしてパラメーターをコピーすることを回避します。
BYTE の代わりに uint8_t を使用します。
文字列を処理するための便利な関数をいくつか追加しますが、通常、入力データはバイナリであり、内部に 0 バイトが含まれている可能性があるため、通常は文字列として操作しないでください (これは多くの場合、null で終了するデータを意味します)。
また、コンパイラの警告を修正するためにいくつかのキャストを追加します (少なくとも GCC では、まだ MSVC で実行していません)。
ファイルbase64.hppの一部:
void base64_encode(string & out, const vector<uint8_t>& buf);
void base64_encode(string & out, const uint8_t* buf, size_t bufLen);
void base64_encode(string & out, string const& buf);
void base64_decode(vector<uint8_t> & out, string const& encoded_string);
// Use this if you know the output should be a valid string
void base64_decode(string & out, string const& encoded_string);
ファイルbase64.cpp :
static const uint8_t from_base64[128] = {
// 8 rows of 16 = 128
// Note: only requires 123 entries, as we only lookup for <= z , which z=122
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 0, 255, 255, 255,
255, 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, 255, 255, 255, 255, 63,
255, 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, 255, 255, 255, 255, 255
};
static const char to_base64[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
void base64_encode(string & out, string const& buf)
{
if (buf.empty())
base64_encode(out, NULL, 0);
else
base64_encode(out, reinterpret_cast<uint8_t const*>(&buf[0]), buf.size());
}
void base64_encode(string & out, std::vector<uint8_t> const& buf)
{
if (buf.empty())
base64_encode(out, NULL, 0);
else
base64_encode(out, &buf[0], buf.size());
}
void base64_encode(string & ret, uint8_t const* buf, size_t bufLen)
{
// Calculate how many bytes that needs to be added to get a multiple of 3
size_t missing = 0;
size_t ret_size = bufLen;
while ((ret_size % 3) != 0)
{
++ret_size;
++missing;
}
// Expand the return string size to a multiple of 4
ret_size = 4*ret_size/3;
ret.clear();
ret.reserve(ret_size);
for (size_t i = 0; i < ret_size/4; ++i)
{
// Read a group of three bytes (avoid buffer overrun by replacing with 0)
const size_t index = i*3;
const uint8_t b3_0 = (index+0 < bufLen) ? buf[index+0] : 0;
const uint8_t b3_1 = (index+1 < bufLen) ? buf[index+1] : 0;
const uint8_t b3_2 = (index+2 < bufLen) ? buf[index+2] : 0;
// Transform into four base 64 characters
const uint8_t b4_0 = ((b3_0 & 0xfc) >> 2);
const uint8_t b4_1 = ((b3_0 & 0x03) << 4) + ((b3_1 & 0xf0) >> 4);
const uint8_t b4_2 = ((b3_1 & 0x0f) << 2) + ((b3_2 & 0xc0) >> 6);
const uint8_t b4_3 = ((b3_2 & 0x3f) << 0);
// Add the base 64 characters to the return value
ret.push_back(to_base64[b4_0]);
ret.push_back(to_base64[b4_1]);
ret.push_back(to_base64[b4_2]);
ret.push_back(to_base64[b4_3]);
}
// Replace data that is invalid (always as many as there are missing bytes)
for (size_t i = 0; i != missing; ++i)
ret[ret_size - i - 1] = '=';
}
template <class Out>
void base64_decode_any( Out & ret, std::string const& in)
{
typedef typename Out::value_type T;
// Make sure the *intended* string length is a multiple of 4
size_t encoded_size = in.size();
while ((encoded_size % 4) != 0)
++encoded_size;
const size_t N = in.size();
ret.clear();
ret.reserve(3*encoded_size/4);
for (size_t i = 0; i < encoded_size; i += 4)
{
// Note: 'z' == 122
// Get values for each group of four base 64 characters
const uint8_t b4_0 = ( in[i+0] <= 'z') ? from_base64[static_cast<uint8_t>(in[i+0])] : 0xff;
const uint8_t b4_1 = (i+1 < N and in[i+1] <= 'z') ? from_base64[static_cast<uint8_t>(in[i+1])] : 0xff;
const uint8_t b4_2 = (i+2 < N and in[i+2] <= 'z') ? from_base64[static_cast<uint8_t>(in[i+2])] : 0xff;
const uint8_t b4_3 = (i+3 < N and in[i+3] <= 'z') ? from_base64[static_cast<uint8_t>(in[i+3])] : 0xff;
// Transform into a group of three bytes
const uint8_t b3_0 = ((b4_0 & 0x3f) << 2) + ((b4_1 & 0x30) >> 4);
const uint8_t b3_1 = ((b4_1 & 0x0f) << 4) + ((b4_2 & 0x3c) >> 2);
const uint8_t b3_2 = ((b4_2 & 0x03) << 6) + ((b4_3 & 0x3f) >> 0);
// Add the byte to the return value if it isn't part of an '=' character (indicated by 0xff)
if (b4_1 != 0xff) ret.push_back( static_cast<T>(b3_0) );
if (b4_2 != 0xff) ret.push_back( static_cast<T>(b3_1) );
if (b4_3 != 0xff) ret.push_back( static_cast<T>(b3_2) );
}
}
void base64_decode(vector<uint8_t> & out, string const& encoded_string)
{
base64_decode_any(out, encoded_string);
}
void base64_decode(string & out, string const& encoded_string)
{
base64_decode_any(out, encoded_string);
}
私は最初に自分のバージョンを作成し、次にこのトピックを見つけました。
私のバージョンが、ここに提示されている他のバージョンよりもシンプルに見えるのはなぜですか? 私は何か間違ったことをしていますか?速度についてはテストしませんでした。
inline char const* b64units = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
inline char* b64encode(void const* a, int64_t b) {
ASSERT(a != nullptr);
if (b > 0) {
uint8_t const* aa = static_cast<uint8_t const*>(a);
uint8_t v = 0;
int64_t bp = 0;
int64_t sb = 0;
int8_t off = 0;
int64_t nt = ((b + 2) / 3) * 4;
int64_t nd = (b * 8) / 6;
int64_t tl = ((b * 8) % 6) ? 1 : 0;
int64_t nf = nt - nd - tl;
int64_t ri = 0;
char* r = new char[nt + 1]();
for (int64_t i = 0; i < nd; i++) {
v = (aa[sb] << off) | (aa[sb + 1] >> (8 - off));
v >>= 2;
r[ri] = b64units[v];
ri += 1;
bp += 6;
sb = (bp / 8);
off = (bp % 8);
}
if (tl > 0) {
v = (aa[sb] << off);
v >>= 2;
r[ri] = b64units[v];
ri += 1;
}
for (int64_t i = 0; i < nf; i++) {
r[ri] = '=';
ri += 1;
}
return r;
} else return nullptr;
}
PS: 私の方法はうまくいきます。Node.jsでテストしました:
let data = 'stackabuse.com';
let buff = new Buffer(data);
let base64data = buff.toString('base64');