#include <iostream>
#include <string>
#include <vector>
#define BASE64BIT 6
/* pre-fetch, pre-masking-set */
/* ビットスライシング用クラス */
class bitcut {
private:
std::string buffer;
std::string::const_iterator p;;
uint_least8_t mask;
uint_least8_t fetch_byte;
int width;
public:
bool isEOL; /* 外部呼び出し側では、このフラグを見てスライスするかどうかを判断する */
bitcut(std::string input, int width) { /*コンストラクタにスライスする文字列と、文字列を構成するバイトの有効ビット幅を設定 */
this->buffer = input;
this->p = buffer.begin();
this->width = width;
if (p == buffer.end()) {
isEOL = true;
} else {
isEOL = false;
fetch_byte = *p;
mask = 1 << (this->width - 1);
}
}
/* bit 数分スライス、tailignore = bit 数分スライスしようとして、残りビットが bit に足りないとき無視するのなら true */
int_least8_t cut(int bit, bool tailignore) { /* bit <= 16 */
uint_least8_t buff = 0;
for (int i = 0; i < bit; i++) {
if (isEOL == false) {
int t = fetch_byte & mask;
buff = buff | ((t > 0) ? 1 : 0);
buff = buff << 1;
mask = mask >> 1;
if (mask == 0) {
this->p++;
if (this->p == buffer.end()) {
this->isEOL = true;
} else {
fetch_byte = *p;
mask = 1 << (this->width - 1);
}
}
} else { /* isEOL == true */
if (tailignore != true)
buff = buff << 1;
}
}
buff = buff >> 1;
return buff;
}
};
/* エンコード */
std::string encode(std::string key) {
std::string ret;
bitcut bc(key, 8);
if (bc.isEOL == true)
return ret;
int_least8_t c;
do {
for (int i = 0 ; i < 4; i++) {
if (bc.isEOL == true) {
c = '=';
} else {
c = bc.cut(BASE64BIT, false);
if (c <= 25) c += 'A';
else if (c <= 51) c = c - 26 + 'a';
else if (c <= 61) c = c - 52 + '0';
else if (c == 62) c = '+';
else if (c == 63) c = '/';
}
ret.push_back(c);
}
} while (bc.isEOL == false);
return ret;
}
/* デコード */
std::string decode(std::string key) {
std::string ret;
for (std::string::iterator p = key.begin(); p != key.end(); ) {
if (*p == '=') {
p = key.erase(p);
continue;
} else if (*p == '+') {
*p = 62;
p++;
} else if (*p == '/') {
*p = 63;
p++;
} else if (*p <= '9') {
*p = *p - '0' + 52;
p++;
} else if (*p <= 'Z') {
*p = *p - 'A';
p++;
} else if (*p <= 'z') {
*p = *p - 'a' + 26;
p++;
}
}
bitcut bc(key, BASE64BIT);
if (bc.isEOL == true)
return ret;
int_least8_t c2;
do {
c2 = bc.cut(8, true);
ret.push_back(c2);
} while (bc.isEOL == false);
return ret;
}
void f(std::string key) {
std::string out;
std::cout << "input: " << key << std::endl;
std::cout << "encode: " << (out = encode(key)) << std::endl;
std::cout << "decode: " << decode(out) << std::endl;
}
int main() {
// f("ghi");
f("ABCDEFG");
f("Hello, World!");
f("0123456789\"#$%&\'()`=@");
f("12ab34cd56ef78");
return 0;
}
/* end */