#include <iostream>
#include <bitset>
#include <cstring>

// 问题:将一个二进制流转换成可阅读的字符串,字符串为:大写字母加数字,去除0和O,I和1相近字符。

const int g_bitNum = 5;
const char* g_Coder = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";

int Encode(const char* pData, int nLen, char* res)
{
    int totalLen = nLen * 8;
    int resLen = totalLen / g_bitNum;
    if (totalLen % g_bitNum != 0) ++resLen;
    if (res == nullptr) {
        return resLen;
    }
    for (int i = 0; i < resLen; ++i) {
        unsigned char nIndex = 0;
        int index = i * g_bitNum;
        for (int j = 0; j < g_bitNum && index + j < totalLen; ++j) {

            // bitValue 这一行只管取出下一位的值,放在哪里不管。
            // index 是连续的(相当于大组里面内增,换个大组继续内增)
            // index / 8 或者 index % 8 就是锁定第几组char的第几个,移动到最低位取出。
            unsigned char bitValue = ((pData[index / 8] >> (7 - index % 8)) & 1);

            // value 这一行只管把值放到对应的位置,与上面不要联系。
            // 这里对 value 高位到低位的放
            nIndex |= (bitValue << (g_bitNum - 1 - j));

            // 关键点:value 和 bitValue 各管各的。
            ++index;
        }
        res[i] = g_Coder[nIndex];
    }
    res[resLen] = '\0';
    return resLen;
}

int Decode(const char* pData, unsigned char* res)
{
    int len = static_cast<int>(std::strlen(pData));
    int codeBitCount = len * g_bitNum;
    int resCnt = codeBitCount / 8;
    if (res == nullptr) {
        return resCnt;
    }
    std::memset(res, 0, resCnt * sizeof(char));
    for (int i = 0; i < len; ++i) {
        const char key = pData[i];
        int nIndex = static_cast<int>(std::strchr(g_Coder, key) - g_Coder);
        for (int j = 0; j < g_bitNum && i * g_bitNum + j < codeBitCount; ++j) {
            // bitValue 这一行,只管取出每一位
            int bitValue = ((nIndex >> (g_bitNum - 1 - j)) & 1);
            // nOffset 是原始数据位索引
            int nOffset = i * g_bitNum + j;
            res[nOffset / 8] |= (bitValue << (7 - nOffset % 8));
        }
    }
    return resCnt;
}

int main()
{
    int data[] = {12345, 45678};
    std::cout << "Original Data Len: " << sizeof(data) << std::endl;
    char* szEncode = nullptr;
    int size = Encode((const char*)data, sizeof(data), szEncode);
    std::printf("Encode Data Len: %d\n", size);
    szEncode = new char[size + 1];
    Encode((const char*)data, sizeof(data), szEncode);
    std::printf("Encode Data: %s\n", szEncode);

    unsigned char * szDecode = nullptr;
    int osize = Decode((const char *)szEncode, szDecode);
    std::printf("Decode Data Len: %d\n", osize);
    szDecode = new unsigned char [osize + 1];
    Decode((const char*)szEncode, szDecode);

    int* pInt = (int *)szDecode;
    std::printf("Int[0]:%d, Int[1]:%d\n", pInt[0], pInt[1]);
    delete[] szDecode;
    delete[] szEncode;
    return 0;
}