编程与调试 -- 实现 62 个字符的 Base64 编码

A-Z、a-z、0-9 一共只有 62 个字符,来编码二进制流,困扰了很久,后来发现采用扩展的方式编码 Base64 效果很好。 Base64 一次编码 6 个 bit,0(0x0)-63(0x3f),编码结果只出现这 62 个字符。

码表:

idx 编码 idx 编码 idx 编码 idx 编码
0 "0" 16 "g" 32 "w" 48 "M"
1 "1" 17 "h" 33 "x" 49 "N"
2 "2" 18 "i" 34 "y" 50 "O"
3 "3" 19 "j" 35 "z" 51 "P"
4 "4" 20 "k" 36 "A" 52 "Q"
5 "5" 21 "l" 37 "B" 53 "R"
6 "6" 22 "m" 38 "C" 54 "S"
7 "7" 23 "n" 39 "D" 55 "T"
8 "8" 24 "o" 40 "E" 56 "U"
9 "9" 25 "p" 41 "F" 57 "V"
10 "a" 26 "q" 42 "G" 58 "W"
11 "b" 27 "r" 43 "H" 59 "X0"
12 "c" 28 "s" 44 "I" 60 "X1"
13 "d" 29 "t" 45 "J" 61 "X2"
14 "e" 30 "u" 46 "K" 62 "X3"
15 "f" 31 "v" 47 "L" 63 "X4"

核心逻辑

62 个字符 编码 64 个数字。

定义映射表 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,只使用 0-WXYZ 作为扩展标记,进行递归编码,绝大部分(59/64=0.921875)都会编码成一个字符,只有小部分(5/64=0.078125)的概率会被编码成两个字符。 一个 6 bit,平均编码就是:$59/64 + (5/64)*2 = 1.078125$ 个字符。

  1. 0-W 一共 59 个字符用于编码,XYZ 作为扩展标记。
    • 可以编码 $0-58$,编码分别为:0, 1, 2W
  2. X 表示进位,基准为 59。
    • 可以编码 $59-117$,编码分别为:X0, X1, X2XW
  3. Y 表示两位,基准为 118。
    • 可以编码 $118-3598$,编码分别为:Y00, Y01, Y02YWW
  4. Z 表示三位,最高位递归处理,基准为 3599。
    • 可以编码 $3599-∞$,编码分别为:Z000, Z001, Z002ZWWW, Z00X0, Z00X1
16 进制 10 进制 编码
0 0 "0"
3a 58 "W"
3b 59 "X0"
75 117 "XW"
76 118 "Y00"
e0e 3598 "YWW"
e0f 3599 "Z000"
33051 208977 "ZWWW"
33052 208978 "Z00X0"
65294 414356 "ZWWXW"
65295 414357 "Z00Y00"
ffffe 1048574 "ZqbY53"
fffff 1048575 "ZrbY53"
bf3805 12531717 "ZWWYWW"
bf3806 12531718 "Z00Z000"
fffffe 16777214 "ZxAZDk0"
ffffff 16777215 "ZyAZDk0"

WCHAR L"中文 09azAZ" 加密:

BASE64(utf8) 5Lit5paHIDA5YXpBWg==
B62 逐字符编码 P925Ic7rv00w00M00V01C02401601v
B62 6bit 编码 Pi0bkW7pi00c00V0640uw1105E0
B62(utf8) 6bit 编码 Pd0VbyJVFq7830VonF1mw

编码效果很好,比 BASE64 长一丢丢(长 $0.078125%$),但是没有任何图形符号,非常干净。

三种编码方式

  • 6 bit 模式(Base64 模式),编码效率和 Base64 差不多。
    std::wstring b62base64::BBEncode(const char* buffer, const int length) {
        std::wstring retv;
        BBEncode(retv, BB62_TYPE);
        BBEncode(retv, length);
        BBEncode(retv, b62base64::BBType::BBTypeBin); // 0:bin,1:char,2:wchar。
        // 一次编码 3 个字节。
        for (int i = 0; i < length; i += 3) {
            char a = buffer[i];
            char b = i + 1 < length ? buffer[i + 1] : 0;
            char c = i + 2 < length ? buffer[i + 2] : 0;
            BBEncode(retv, (a & B11111100) >> 2);
            BBEncode(retv, ((a & B00000011) << 4) | ((b & B11110000) >> 4));
            if (i + 1 >= length) {
                break;
            }
            BBEncode(retv, ((b & B00001111) << 2) | ((c & B11000000) >> 6));
            if (i + 2 >= length) {
                break;
            }
            BBEncode(retv, c & B00111111);
        }
        return retv;
    }
    
  • char 模式,每个 char 单独编码,避免前后影响,这个和 16 进制编码效率差不多。
    std::wstring b62base64::BBEncode(const std::string& str) {
        const int length = str.size();
        const char* buffer = str.c_str();
    
        std::wstring retv;
        BBEncode(retv, BB62_TYPE);
        BBEncode(retv, length);
        BBEncode(retv, b62base64::BBType::BBTypeChar); // 0:bin,1:char,2:wchar。
        for (int i = 0; i < length; i++) {
            char ch = buffer[i]; // <= 0xff
            BBEncode(retv, ch / BB59);
            BBEncode(retv, ch % BB59);
        }
        return retv;
    }
    
  • wchar 模式,每个 wchar 编码成 3 个位,避免前后影响。编码效率比 16 进制 高 25%。
    std::wstring b62base64::BBEncode(const std::wstring& str) {
        const int length = str.size();
        const wchar_t* buffer = str.c_str();
    
        std::wstring retv;
        BBEncode(retv, BB62_TYPE);
        BBEncode(retv, length);
        BBEncode(retv, b62base64::BBType::BBTypeWChar); // 0:bin,1:char,2:wchar。
        for (int i = 0; i < length; i++) {
            wchar_t ch = buffer[i]; // <= 0xffff
            BBEncode(retv, ch / BB59 / BB59);
            BBEncode(retv, ch / BB59 % BB59);
            BBEncode(retv, ch % BB59);
        }
        return retv;
    }
    

预定义

// 0 0 P12000
const wchar_t BB59TABLE[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define BB59      59
#define CHECK_RETURN(state, retv) do { \
    if (state.IsError()) { return retv; } \
    } while (0)
#define CHECK_ARRAY_RETURN(state, retv) do { \
    if (index >= bufsize) { \
        state.OnError(b62base64::BBDecodeError::BBDecodeErrArrayOverflow); \
        return retv; } \
    } while (0)

编码核心逻辑

int b62base64::BBEncode(std::wstring& retv, unsigned long value) {
    int len = 0;
    if (value < BB59) {
        retv.push_back(BB59TABLE[value]);
        len += 1;
    }
    else if (value - BB59 < BB59) {
        value -= BB59;
        retv.push_back(L'X');
        retv.push_back(BB59TABLE[value]);
        len += 2;
    }
    else if ((value - BB59 * 2) / BB59 < BB59) {
        value -= BB59 * 2;
        retv.push_back(L'Y');
        retv.push_back(BB59TABLE[value % BB59]);
        retv.push_back(BB59TABLE[value / BB59]);
        len += 3;
    }
    else {
        const int basek = BB59 * 2 + BB59 * BB59;
        assert(value >= basek); // 不能出现负数。
        value -= basek;

        retv.push_back(L'Z');
        retv.push_back(BB59TABLE[value % BB59]);
        retv.push_back(BB59TABLE[value / BB59 % BB59]);
        len += 3 + BBEncode(retv, value / BB59 / BB59); // 递归最高位置。
    }
    return len;
}

解码核心逻辑

unsigned long b62base64::BBDecode(const wchar_t* ptr, const unsigned int bufsize,
        unsigned int& index, b62base64::BBDecodeState& state) {

    CHECK_ARRAY_RETURN(state, 0);
    const wchar_t op = ptr[index++];
    if (op == L'X') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t X = ptr[index++];
        return BB59 + BBDecode(X, state);
    }
    else if (op == L'Y') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Y1 = ptr[index++];
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Y2 = ptr[index++];
        return BB59 * 2 + BBDecode(Y1, state) + BBDecode(Y2, state) * BB59;
    }
    else if (op == L'Z') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Z1 = ptr[index++];
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Z2 = ptr[index++];
        unsigned long Z3 = BBDecode(ptr, bufsize, index, state);
        CHECK_RETURN(state, 0);
        const int basek = BB59 * 2 + BB59 * BB59;
        return basek + BBDecode(Z1, state) + BBDecode(Z2, state) * BB59 + Z3 * BB59 * BB59;
    }
    else {
        return BBDecode(op, state);
    }
}

b62base64.h

#pragma once
#include <windows.h>
#include <assert.h>
#include <memory>
#include <string>
#include <vector>

namespace b62base64 {

    enum BBType {
        BBTypeNone = 0xf,
        BBTypeBin = 0,
        BBTypeChar = 1, // sizeof(char)
        BBTypeWChar = 2, // sizeof(wchar)
    };

    enum BBDecodeError {
        BBDecodeSuccess = 0,
        BBDecodeUnknowType = 1, // 头 type 不对。
        BBDecodeUnknowAlgType = 2, // 编码不能识别。
        BBDecodeErrChar = 3, // 字符错误。
        BBDecodeErrArrayOverflow = 4, // 数组溢出访问。
        BBDecodeErrCallback = 5, // BBDecodeCallback 返回 FALSE。
        BBDecodeErrSize = 6, // 最终 size 不对。
    };

    __interface BBDecodeState {
        virtual void OnError(BBDecodeError err) = 0;
        virtual BOOL IsError() = 0;
    };

    __interface BBDecodeCallback : public BBDecodeState {
        virtual BOOL OnConfig(int size, int type) = 0;
        virtual BOOL OnValue(unsigned long value) = 0;
        virtual BOOL OnTheEnd() = 0;
    };

    // 编解码核心逻辑
    int BBDecode(const wchar_t ch, BBDecodeState& state);
    int BBEncode(std::wstring& retv, unsigned long value);
    unsigned long BBDecode(const wchar_t* ptr, const unsigned int bufsize,
        unsigned int& index, BBDecodeState& state);

    // 编码
    std::wstring BBEncode(const std::wstring& str);
    std::wstring BBEncode(const std::string& str);
    std::wstring BBEncode(const char* buffer, const int length);
    std::wstring BBEncode(const std::vector<char>& buffer);

    // 解码
    BOOL BBDecode(const std::wstring& str, BBDecodeCallback& result);
    std::wstring BBDecodeStr(const std::wstring& str);
    std::string BBDecodeStrA(const std::wstring& str);
    std::vector<char> BBDecodeBuffer(const std::wstring& str);

    // 创建随机字符串
    std::wstring MakeRandString(int size);
    std::string MakeRandStringA(int size);
    std::vector<char> MakeRandBuffer(int size);

    // 16 进制编码
    std::wstring HexEncode(const std::wstring& str);
    std::wstring HexEncode(const std::string& str);
    std::wstring HexEncode(const std::vector<char>& str);

    // 测试接口。
    int b62base64_test();
};

b62base64.cpp

#pragma once
#include <windows.h>
#include <assert.h>
#include <memory>
#include <string>
#include "b62base64.h"
//#include "base64.h"

const wchar_t BB59TABLE[] = L"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

#define ISCHAR_09(ch) (ch >= L'0' && ch <= L'9')
#define ISCHAR_az(ch) (ch >= L'a' && ch <= L'z')
#define ISCHAR_AZ(ch) (ch >= L'A' && ch <= L'Z')
#define PARSE_09(ch) (ch - L'0')
#define PARSE_az(ch) (ch - L'a' + 10)
#define PARSE_AZ(ch) (ch - L'A' + 10 + 26)

#define MASK_EXT1 -1 // 扩展一位
#define MASK_EXT2 -2 // 扩展两位
#define MASK_EXTR -3 // 递归扩展
#define MASK_ERR  -9

#define BB59      59
#define BB62_TYPE 0x33

const unsigned char B11111100 = 0B11111100; // 0xfc;
const unsigned char B00000011 = 0B00000011; // 0x03;
const unsigned char B11110000 = 0B11110000; // 0xf0;
const unsigned char B00001111 = 0B00001111; // 0x0f;
const unsigned char B11000000 = 0B11000000; // 0xc0;
const unsigned char B00111111 = 0B00111111; // 0x3f;
const unsigned char B110000 = 0B110000; // 0x30;
const unsigned char B001111 = 0B001111; // 0x0f;
const unsigned char B111100 = 0B111100; // 0x3c;
const unsigned char B000011 = 0B000011; // 0x03;

class MyDecodeState : public b62base64::BBDecodeState {
public:
    void OnError(b62base64::BBDecodeError err) override {
        m_err = err;
    }

    BOOL IsError() override {
        return m_err != b62base64::BBDecodeError::BBDecodeSuccess;
    }

private:
    b62base64::BBDecodeError m_err = b62base64::BBDecodeError::BBDecodeSuccess;
};

class MyDecodeCallback : public b62base64::BBDecodeCallback, public MyDecodeState {
public:
    MyDecodeCallback(std::string& str) : m_str(&str) {
    }
    MyDecodeCallback(std::wstring& wstr) : m_wstr(&wstr) {
    }
    MyDecodeCallback(std::vector<char>& buffer) : m_buffer(&buffer) {
    }

public:
    BOOL OnConfig(int size, int type) override {
        this->m_size = size;
        this->m_type = (b62base64::BBType)type;
        if (type == b62base64::BBType::BBTypeChar) {
            return !!m_str;
        }
        if (type == b62base64::BBType::BBTypeWChar) {
            return !!m_wstr;
        }
        if (type == b62base64::BBType::BBTypeBin) {
            return !!m_buffer;
        }
        return FALSE;
    }
    BOOL OnValue(unsigned long value) override {
        if (m_type == b62base64::BBType::BBTypeChar && m_str) {
            m_str->push_back(value);
            return TRUE;
        }
        if (m_type == b62base64::BBType::BBTypeWChar && m_wstr) {
            m_wstr->push_back(value);
            return TRUE;
        }
        if (m_type == b62base64::BBType::BBTypeBin && m_buffer) {
            m_buffer->push_back(value);
            return TRUE;
        }
        return FALSE;
    }

    BOOL OnTheEnd() override {
        if (m_type == b62base64::BBType::BBTypeChar && m_str) {
            if (m_str->size() != m_size) {
                OnError(b62base64::BBDecodeError::BBDecodeErrSize);
                return FALSE;
            }
            return TRUE;
        }
        if (m_type == b62base64::BBType::BBTypeWChar && m_wstr) {
            if (m_wstr->size() != m_size) {
                OnError(b62base64::BBDecodeError::BBDecodeErrSize);
                return FALSE;
            }
            return TRUE;
        }
        if (m_type == b62base64::BBType::BBTypeBin && m_buffer) {
            if (m_buffer->size() != m_size) {
                OnError(b62base64::BBDecodeError::BBDecodeErrSize);
                return FALSE;
            }
            return TRUE;
        }
        return FALSE;
    }

public:
    void OnError(b62base64::BBDecodeError err) override {
        MyDecodeState::OnError(err);
    }

    BOOL IsError() override {
        return MyDecodeState::IsError();
    }

private:
    std::string* m_str = nullptr;
    std::wstring* m_wstr = nullptr;
    std::vector<char>* m_buffer = nullptr;
    int m_size = -1;
    b62base64::BBType m_type = b62base64::BBType::BBTypeNone;
};

#define CHECK_RETURN(state, retv) do { \
    if (state.IsError()) { return retv; } \
    } while (0)
#define CHECK_ARRAY_RETURN(state, retv) do { \
    if (index >= bufsize) { \
        state.OnError(b62base64::BBDecodeError::BBDecodeErrArrayOverflow); \
        return retv; } \
    } while (0)

int b62base64::BBDecode(const wchar_t ch, b62base64::BBDecodeState& state) {
    if (ISCHAR_09(ch)) {
        return PARSE_09(ch);
    }
    if (ISCHAR_az(ch)) {
        return PARSE_az(ch);
    }
    if (ISCHAR_AZ(ch)) {
        if (ch == L'X') {
            state.OnError(b62base64::BBDecodeError::BBDecodeErrChar);
            return MASK_EXT1;
        }
        if (ch == L'Y') {
            state.OnError(b62base64::BBDecodeError::BBDecodeErrChar);
            return MASK_EXT2;
        }
        if (ch == L'Z') {
            state.OnError(b62base64::BBDecodeError::BBDecodeErrChar);
            return MASK_EXTR;
        }
        return PARSE_AZ(ch);
    }
    state.OnError(b62base64::BBDecodeError::BBDecodeErrChar);
    return MASK_ERR;
}

int b62base64::BBEncode(std::wstring& retv, unsigned long value) {
    int len = 0;
    if (value < BB59) {
        retv.push_back(BB59TABLE[value]);
        len += 1;
    }
    else if (value - BB59 < BB59) {
        value -= BB59;
        retv.push_back(L'X');
        retv.push_back(BB59TABLE[value]);
        len += 2;
    }
    else if ((value - BB59 * 2) / BB59 < BB59) {
        value -= BB59 * 2;
        retv.push_back(L'Y');
        retv.push_back(BB59TABLE[value % BB59]);
        retv.push_back(BB59TABLE[value / BB59]);
        len += 3;
    }
    else {
        const int basek = BB59 * 2 + BB59 * BB59;
        assert(value >= basek); // 不能出现负数。
        value -= basek;

        retv.push_back(L'Z');
        retv.push_back(BB59TABLE[value % BB59]);
        retv.push_back(BB59TABLE[value / BB59 % BB59]);
        len += 3 + BBEncode(retv, value / BB59 / BB59); // 递归最高位置。
    }
    return len;
}

unsigned long b62base64::BBDecode(const wchar_t* ptr, const unsigned int bufsize,
    unsigned int& index, b62base64::BBDecodeState& state) {

    CHECK_ARRAY_RETURN(state, 0);
    const wchar_t op = ptr[index++];
    if (op == L'X') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t X = ptr[index++];
        return BB59 + BBDecode(X, state);
    }
    else if (op == L'Y') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Y1 = ptr[index++];
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Y2 = ptr[index++];
        return BB59 * 2 + BBDecode(Y1, state) + BBDecode(Y2, state) * BB59;
    }
    else if (op == L'Z') {
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Z1 = ptr[index++];
        CHECK_ARRAY_RETURN(state, 0);
        wchar_t Z2 = ptr[index++];
        unsigned long Z3 = BBDecode(ptr, bufsize, index, state);
        CHECK_RETURN(state, 0);
        const int basek = BB59 * 2 + BB59 * BB59;
        return basek + BBDecode(Z1, state) + BBDecode(Z2, state) * BB59 + Z3 * BB59 * BB59;
    }
    else {
        return BBDecode(op, state);
    }
}

std::wstring b62base64::BBEncode(const std::wstring& str) {
    const int length = str.size();
    const wchar_t* buffer = str.c_str();

    std::wstring retv;
    BBEncode(retv, BB62_TYPE);
    BBEncode(retv, length);
    BBEncode(retv, b62base64::BBType::BBTypeWChar); // 0:bin,1:char,2:wchar。
    for (int i = 0; i < length; i++) {
        wchar_t ch = buffer[i]; // <= 0xffff
        BBEncode(retv, ch / BB59 / BB59);
        BBEncode(retv, ch / BB59 % BB59);
        BBEncode(retv, ch % BB59);
    }
    return retv;
}

std::wstring b62base64::BBEncode(const std::string& str) {
    const int length = str.size();
    const char* buffer = str.c_str();

    std::wstring retv;
    BBEncode(retv, BB62_TYPE);
    BBEncode(retv, length);
    BBEncode(retv, b62base64::BBType::BBTypeChar); // 0:bin,1:char,2:wchar。
    for (int i = 0; i < length; i++) {
        char ch = buffer[i]; // <= 0xff
        BBEncode(retv, ch / BB59);
        BBEncode(retv, ch % BB59);
    }
    return retv;
}

std::wstring b62base64::BBEncode(const char* buffer, const int length) {
    std::wstring retv;
    BBEncode(retv, BB62_TYPE);
    BBEncode(retv, length);
    BBEncode(retv, b62base64::BBType::BBTypeBin); // 0:bin,1:char,2:wchar。
    // 一次编码 3 个字节。
    for (int i = 0; i < length; i += 3) {
        char a = buffer[i];
        char b = i + 1 < length ? buffer[i + 1] : 0;
        char c = i + 2 < length ? buffer[i + 2] : 0;
        BBEncode(retv, (a & B11111100) >> 2);
        BBEncode(retv, ((a & B00000011) << 4) | ((b & B11110000) >> 4));
        if (i + 1 >= length) {
            break;
        }
        BBEncode(retv, ((b & B00001111) << 2) | ((c & B11000000) >> 6));
        if (i + 2 >= length) {
            break;
        }
        BBEncode(retv, c & B00111111);
    }
    return retv;
}

std::wstring b62base64::BBEncode(const std::vector<char>& buffer) {
    if (buffer.empty()) {
        return BBEncode("", 0);
    }
    std::wstring retv = BBEncode(&buffer[0], buffer.size());
    return retv;
}

BOOL b62base64::BBDecode(const std::wstring& str, b62base64::BBDecodeCallback& result) {

    unsigned int index = 0;
    const wchar_t* buffer = str.c_str();
    unsigned int bufsize = str.size();

    const int algType = BBDecode(buffer, bufsize, index, result);
    CHECK_RETURN(result, FALSE);
    if (algType != BB62_TYPE) {
        result.OnError(b62base64::BBDecodeError::BBDecodeUnknowType);
        return FALSE;
    }

    const int length = BBDecode(buffer, bufsize, index, result);
    CHECK_RETURN(result, FALSE);
    const int flag = BBDecode(buffer, bufsize, index, result);
    CHECK_RETURN(result, FALSE);
    if (!result.OnConfig(length, flag)) {
        result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
        return FALSE;
    }

    if (flag == b62base64::BBType::BBTypeWChar) {
        for (int i = 0; i < length; i++) {
            wchar_t a = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            wchar_t b = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            wchar_t c = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            unsigned long value = a * BB59 * BB59 + b * BB59 + c;
            if (!result.OnValue(value)) {
                result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
                return FALSE;
            }
        }
        return result.OnTheEnd();
    }
    if (flag == b62base64::BBType::BBTypeChar) {
        for (int i = 0; i < length; i++) {
            char a = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            char b = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            unsigned long value = a * BB59 + b;
            if (!result.OnValue(value)) {
                result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
                return FALSE;
            }
        }
        return result.OnTheEnd();
    }
    if (flag == b62base64::BBType::BBTypeBin) {
        unsigned int rstindex = 0;
        for (int i = 0; i < length; i += 3) {
            char a = BBDecode(buffer, bufsize, index, result);
            CHECK_RETURN(result, FALSE);
            char b = index < bufsize ? BBDecode(buffer, bufsize, index, result) : 0;
            CHECK_RETURN(result, FALSE);
            char c = index < bufsize ? BBDecode(buffer, bufsize, index, result) : 0;
            CHECK_RETURN(result, FALSE);
            char d = index < bufsize ? BBDecode(buffer, bufsize, index, result) : 0;
            CHECK_RETURN(result, FALSE);
            if (!result.OnValue((a << 2) | ((b & B110000) >> 4))) {
                result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
                return FALSE;
            }
            if (++rstindex >= length) {
                break;
            }
            if (!result.OnValue(((b & B001111) << 4) | ((c & B111100) >> 2))) {
                result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
                return FALSE;
            }
            if (++rstindex >= length) {
                break;
            }
            if (!result.OnValue(((c & B000011) << 6) | d)) {
                result.OnError(b62base64::BBDecodeError::BBDecodeErrCallback);
                return FALSE;
            }
            if (++rstindex >= length) {
                break;
            }
        }
        return result.OnTheEnd();
    }
    result.OnError(b62base64::BBDecodeError::BBDecodeUnknowAlgType);
    return FALSE;
}

std::wstring b62base64::BBDecodeStr(const std::wstring& str) {
    std::wstring result;
    MyDecodeCallback resultw(result);
    if (BBDecode(str, resultw)) {
        return result;
    }
    assert(resultw.IsError());
    return result;
}

std::string b62base64::BBDecodeStrA(const std::wstring& str) {
    std::string result;
    MyDecodeCallback resultw(result);
    if (BBDecode(str, resultw)) {
        return result;
    }
    assert(resultw.IsError());
    return result;
}

std::vector<char> b62base64::BBDecodeBuffer(const std::wstring& str) {
    std::vector<char> result;
    MyDecodeCallback resultw(result);
    if (BBDecode(str, resultw)) {
        return result;
    }
    assert(resultw.IsError());
    return result;
}

std::wstring b62base64::MakeRandString(int size) {
    std::wstring retv;
    retv.resize(size);
    for (int i = 0; i < size; i++) {
        retv[i] = rand() & 0xffff;
    }
    return retv;
}

std::string b62base64::MakeRandStringA(int size) {
    std::string retv;
    retv.resize(size);
    for (int i = 0; i < size; i++) {
        retv[i] = rand() & 0xff;
    }
    return retv;
}

std::vector<char> b62base64::MakeRandBuffer(int size) {
    std::vector<char> retv;
    retv.resize(size);
    for (int i = 0; i < size; i++) {
        retv[i] = rand() & 0xff;
    }
    return retv;
}

std::wstring b62base64::HexEncode(const std::wstring& str) {
    std::wstring ret;
    wchar_t buffer[10];
    for (int i = 0; i < str.size(); i++) {
        wsprintf(buffer, L"%04x", (unsigned wchar_t)str[i]);
        assert(wcslen(buffer) == 4);
        ret.append(buffer);
    }
    return ret;
}

std::wstring b62base64::HexEncode(const std::string& str) {
    std::wstring ret;
    wchar_t buffer[10];
    for (int i = 0; i < str.size(); i++) {
        wsprintf(buffer, L"%02x", (unsigned char)str[i]);
        assert(wcslen(buffer) == 2);
        ret.append(buffer);
    }
    return ret;
}

std::wstring b62base64::HexEncode(const std::vector<char>& str) {
    std::wstring ret;
    wchar_t buffer[10];
    for (int i = 0; i < str.size(); i++) {
        wsprintf(buffer, L"%02x", (unsigned char)str[i]);
        assert(wcslen(buffer) == 2);
        ret.append(buffer);
    }
    return ret;
}

int b62base64::b62base64_test()
{
#ifdef _DEBUG
    for (int i = 0; i < 10000; i++) {
        int size = rand() % 10;

        std::wstring strw = MakeRandString(size);
        std::string stra = MakeRandStringA(size);
        std::vector<char> mystr = MakeRandBuffer(size);
        assert(strw.size() == size);
        assert(stra.size() == size);
        assert(mystr.size() == size);

        std::wstring strwE = BBEncode(strw);
        std::wstring straE = BBEncode(stra);
        std::wstring mystrE = BBEncode(mystr);

        std::wstring strwD = BBDecodeStr(strwE);
        std::string straD = BBDecodeStrA(straE);
        std::vector<char> mystrD = BBDecodeBuffer(mystrE);

        std::wstring t1 = HexEncode(strw);
        std::wstring t2 = HexEncode(strwD);
        int sizek = strwD.size();
        assert(strw.compare(strwD) == 0 && size == sizek);

        t1 = HexEncode(stra);
        t2 = HexEncode(straD);
        sizek = straD.size();
        assert(stra.compare(straD) == 0 && size == sizek);

        t1 = HexEncode(mystr);
        t2 = HexEncode(mystrD);
        sizek = mystrD.size();
        assert(size == sizek);
        if (sizek) {
            assert(memcmp(&mystr[0], &mystrD[0], sizek) == 0);
        }
    }

    int strlen = 0;
    std::wstring preline;
    for (unsigned int i = 0; i <= 0xfffff; i++) {
        std::wstring temp;
        BBEncode(temp, i);

        MyDecodeState state;
        unsigned int index = 0;
        unsigned long result = BBDecode(temp.c_str(), temp.size(), index, state);

        assert(result == i);
        if (temp.size() != strlen || i == 0xfffff) {
            wprintf(preline.c_str());
            wprintf(L"| %x | %d | %s |\r\n", i, i, temp.c_str());
            strlen = temp.size();
        }
        wchar_t kbuffer[1024];
        wsprintf(kbuffer, L"| %x | %d | %s |\r\n", i, i, temp.c_str());
        preline = kbuffer;
    }

    strlen = 0;
    for (int i = 0; i < 0xfffff; i++) {
        std::wstring testk(L"0");
        testk[0] = i;

        std::wstring temp = BBEncode(testk);
        if (temp.size() != strlen) {
            wprintf(L"%x %d %s \r\n", i, i, temp.c_str());
            strlen = temp.size();
        }
        std::wstring result = BBDecodeStr(temp);
        assert(result.compare(testk) == 0);
    }

    std::wstring test = L"中文 09azAZ";
    std::wstring result = BBEncode(test);
    std::wstring temp = BBDecodeStr(result);
    assert(test.compare(temp) == 0);
#endif
    return 0;
}

参考资料快照

本文短链接:
If you have any questions or feedback, please reach out .