c ++中的base64解码片段

joe*_*eld 58 c++ base64

任何人都有c ++中免费提供的base64解码代码片段?

Lih*_*ihO 94

这是我对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
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

这是用法:

std::vector<BYTE> myData;
...
std::string encodedData = base64_encode(&myData[0], myData.size());
std::vector<BYTE> decodedData = base64_decode(encodedData);
Run Code Online (Sandbox Code Playgroud)

我希望有人会发现这个答案有用^^

  • +1表示不在`base64_decode`上返回std :: string (16认同)
  • 在 std::string 中存储二进制数据有什么问题? (5认同)
  • 谢谢。对您的代码的使用有任何限制吗?(我的个人案例将是学术 CFD 代码)。 (2认同)
  • @masche:这是关于在字节级别上编码和解码任何类型的数据.图像 - >原始数据(字节) - >编码成base64字符串,然后回来是base64字符串 - >解码成原始数据(字节) - >构建一些输入流或对象或其他任何东西以使用它作为图像再次... (2认同)

Joh*_*kin 77

谷歌是你的朋友

以下是该页面的实现:

/* 
   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;
}
Run Code Online (Sandbox Code Playgroud)

  • 对于好奇,这是"base64 decode c ++"的第一次热门 (13认同)
  • 现在这个问题有2500个观看次数,所以我想我不是唯一一个.:) (8认同)
  • 谷歌并不总是你的朋友。这种实现几乎是您可能选择的最糟糕的实现。看到这个:/sf/ask/23968661/#41094722 (7认同)
  • 我们应该避免所有这些不必要的字符串连接 - 因为我们知道`in_len`,我们知道`ret`的长度,为什么不在初始化时给它一个修复长度? (2认同)

小智 33

这里有几个片段.然而,这个是紧凑,高效,和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;
}
Run Code Online (Sandbox Code Playgroud)

  • 在其范围内反转"int val"是UB."unsigned val = 0; int valb = ..."是正确的. (3认同)
  • typedef 无符号字符 uchar; (3认同)

小智 14

使用base-n mini lib,您可以执行以下操作:

some_data_t in[] { ... };
constexpr int len = sizeof(in)/sizeof(in[0]);

std::string encoded;
bn::encode_b64(in, in + len, std::back_inserter(encoded));

some_data_t out[len];
bn::decode_b64(encoded.begin(), encoded.end(), out);
Run Code Online (Sandbox Code Playgroud)

API是通用的,基于迭代器的.

披露:我是作者.

  • `std::size` 会比 `sizeof` hax 更好 (3认同)

pol*_*ఠ_ఠ 13

我认为这个更好用:

#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, '=');
    char *p = (char*) data, *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());
}
Run Code Online (Sandbox Code Playgroud)

感谢@Jens Alfke指出性能问题,我对这篇帖子进行了一些修改.这个比以前更快.它的另一个优点是可以顺利处理损坏的数据.

上一版:虽然在这些类型的问题中,似乎速度是一种矫枉过正,但仅仅为了它的乐趣,我做了一些其他修改,使其成为AFAIK中最快的算法.特别感谢@GaspardP的宝贵建议和不错的基准.

  • 在解码器中,您可以通过使用 `char*` 而不是 `std::string`(只需执行 `char* out = &amp;str[0]`)进一步提升性能(在我的测试中为 10-15%)然后使用 `out[j++]` 而不是 `str[j++]`) 通过这样做,您可以跳过由 `std::string::operator[]` 完成的不必要的检查。此外,通过再分配一个字节(`std::string str;` `str.resize(3*((len+3)/4))避免最后一个`push_back`可能会变得非常昂贵** );` 然后使用 `out[j++]`everywere 和 `str.resize(j);` 最后。 (4认同)
  • 我在http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c/41094722#41094722中进行了评论-尽管此代码并不是最快的编码,但它是最快的解码(与其他16种实现方式相比)。 (2认同)
  • 您在上次编辑中添加了内存泄漏,更不用说缓冲区副本了。不要在没有 `delete` 的情况下使用 `new`。实际上,根本不要使用`new`。@Gaspard,我不知道任何“`std::string::operator[]` 所做的不必要的检查”(实际上我有理由确信没有,至少在发布中),但你可以使用一个 `vector&lt;char&gt;` 如果真的很绝望 - 无论如何你的替换代码不是 Gaspard 建议的,它仍然使用字符串来处理元素访问之外的所有内容并且安全/快速,尽管我认为这是不必要的;) (2认同)
  • @LightnessRacesinOrbit:在版本中,“operator[]”被记录为未经检查 - 你是对的。然而,“std::string”有一个优化,即小字符串在结构内而不是堆上分配。每次对字符串执行“[]”时,它都会检查它是否很小,以了解从哪里获取缓冲区。我的测试表明它并不总是被优化掉。在 Windows 上,它看起来像这样: `value_type *_Myptr() { // 确定当前指向可变字符串缓冲区的指针 return (this-&gt;_BUF_SIZE &lt;= _Myres ? _Unfancy(_Bx._Ptr) : _Bx._Buf); }` (2认同)
  • @polfosolఠ_ఠ,谢谢你。请考虑使用`unsigned char * p`而不是编码器中的`char * p`。如果我的输入包含字节'&gt; = 0x80`,我的base64字符串会损坏。在添加`unsigned`之后,看起来一切正常。 (2认同)

Dae*_*pha 9

根据GaspardP的这一优秀比较,我不会选择这个解决方案.这不是最糟糕的,但它也不是最好的.它唯一能做的就是它可能更容易理解.

我发现另外两个答案很难理解.它们还会在我的编译器中产生一些警告,并且在解码部分中使用find函数会导致效率非常差.所以我决定推出自己的.

标题:

#ifndef _BASE64_H_
#define _BASE64_H_

#include <vector>
#include <string>
typedef unsigned char BYTE;

class Base64
{
public:
    static std::string encode(const std::vector<BYTE>& buf);
    static std::string encode(const BYTE* buf, unsigned int bufLen);
    static std::vector<BYTE> decode(std::string encoded_string);
};

#endif
Run Code Online (Sandbox Code Playgroud)

身体:

static const BYTE from_base64[] = { 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, 255, 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[] = 
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";


std::string Base64::encode(const std::vector<BYTE>& buf)
{
    if (buf.empty())
        return ""; // Avoid dereferencing buf if it's empty
    return encode(&buf[0], (unsigned int)buf.size());
}

std::string Base64::encode(const BYTE* buf, unsigned int 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;

    std::string ret;
    ret.reserve(ret_size);

    for (unsigned int i=0; i<ret_size/4; ++i)
    {
        // Read a group of three bytes (avoid buffer overrun by replacing with 0)
        size_t index = i*3;
        BYTE b3[3];
        b3[0] = (index+0 < bufLen) ? buf[index+0] : 0;
        b3[1] = (index+1 < bufLen) ? buf[index+1] : 0;
        b3[2] = (index+2 < bufLen) ? buf[index+2] : 0;

        // Transform into four base 64 characters
        BYTE b4[4];
        b4[0] =                         ((b3[0] & 0xfc) >> 2);
        b4[1] = ((b3[0] & 0x03) << 4) + ((b3[1] & 0xf0) >> 4);
        b4[2] = ((b3[1] & 0x0f) << 2) + ((b3[2] & 0xc0) >> 6);
        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] = '=';

    return ret;
}

std::vector<BYTE> Base64::decode(std::string encoded_string)
{
    // Make sure string length is a multiple of 4
    while ((encoded_string.size() % 4) != 0)
        encoded_string.push_back('=');

    size_t encoded_size = encoded_string.size();
    std::vector<BYTE> ret;
    ret.reserve(3*encoded_size/4);

    for (size_t i=0; i<encoded_size; i += 4)
    {
        // Get values for each group of four base 64 characters
        BYTE b4[4];
        b4[0] = (encoded_string[i+0] <= 'z') ? from_base64[encoded_string[i+0]] : 0xff;
        b4[1] = (encoded_string[i+1] <= 'z') ? from_base64[encoded_string[i+1]] : 0xff;
        b4[2] = (encoded_string[i+2] <= 'z') ? from_base64[encoded_string[i+2]] : 0xff;
        b4[3] = (encoded_string[i+3] <= 'z') ? from_base64[encoded_string[i+3]] : 0xff;

        // Transform into a group of three bytes
        BYTE b3[3];
        b3[0] = ((b4[0] & 0x3f) << 2) + ((b4[1] & 0x30) >> 4);
        b3[1] = ((b4[1] & 0x0f) << 4) + ((b4[2] & 0x3c) >> 2);
        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(b3[0]);
        if (b4[2] != 0xff) ret.push_back(b3[1]);
        if (b4[3] != 0xff) ret.push_back(b3[2]);
    }

    return ret;
}
Run Code Online (Sandbox Code Playgroud)

用法:

BYTE buf[] = "ABCD";
std::string encoded = Base64::encode(buf, 4);
// encoded = "QUJDRA=="
std::vector<BYTE> decoded = Base64::decode(encoded);
Run Code Online (Sandbox Code Playgroud)

这里的一个好处是解码功能还可以解码base 64编码的url变体.

  • 没有 find() 的奖励积分和输出的 reserve() 。少一点,因为您将输入作为副本(因此您可以根据需要在末尾添加 =)。如果它是一个无复制的东西会很好。 (2认同)
  • 更长:我最喜欢这个答案......对于#行也很好.没有find()的奖励点和输出的reserve().我要改进的东西(这将扩大代码):你将输入作为副本(所以如果需要,你可以在最后添加一个=).如果它是一个无副本的东西会很好.也可以写成普通函数 - 不需要课程.并且应该在解除引用buf [0]之前检查空buf向量.并添加接口以将数据写入引用(因此调用者可以重用内存). (2认同)

nun*_*jpg 8

使用更紧凑的查找表和使用 C++17 特性的一些变化:

std::string base64_decode(const std::string_view in) {
  // table from '+' to 'z'
  const uint8_t lookup[] = {
      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};
  static_assert(sizeof(lookup) == 'z' - '+' + 1);

  std::string out;
  int val = 0, valb = -8;
  for (uint8_t c : in) {
    if (c < '+' || c > 'z')
      break;
    c -= '+';
    if (lookup[c] >= 64)
      break;
    val = (val << 6) + lookup[c];
    valb += 6;
    if (valb >= 0) {
      out.push_back(char((val >> valb) & 0xFF));
      valb -= 8;
    }
  }
  return out;
}
Run Code Online (Sandbox Code Playgroud)

如果您没有 std::string_view,请尝试使用 std::experimental::string_view。


ele*_*ice 5

我对DaedalusAlpha 的回答的变体:

它避免了以几次测试为代价来复制参数。

使用 uint8_t 而不是 BYTE。

添加了一些处理字符串的方便函数,尽管通常输入数据是二进制的并且内部可能有零字节,因此通常不应作为字符串进行操作(这通常意味着以空字符结尾的数据)。

还添加了一些强制转换来修复编译器警告(至少在 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);
Run Code Online (Sandbox Code Playgroud)

文件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);
}
Run Code Online (Sandbox Code Playgroud)