aboutsummaryrefslogtreecommitdiff
path: root/base64.cpp
blob: 80640f2cbb5d955f8ac1b248f6abc7ae729c00fb (plain)
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "base64.h"

using namespace std;

namespace Base64{

	char alphabet[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	uint8_t revbet[128]={
#define XX (127)
		XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, //0-15
		XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX, //16-31
		XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,62,XX,XX,XX,63, //32-47
		52,53,54,55,56,57,58,59,60,61,XX,XX,XX,XX,XX,XX, //48-63
		XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, //64-79
		15,16,17,18,19,20,21,22,23,24,25,XX,XX,XX,XX,XX, //80-95
		XX,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, //96-111
		41,42,43,44,45,46,47,48,49,50,51,XX,XX,XX,XX,XX, //112-127
#undef XX
	};

	string encode(const string &data){
		int sz=data.size();
		if(sz==0)return {};
		int blocks=sz/3;
		string res(4*blocks+4*(sz%3!=0),'\0');
		int x;
		for(int i=0;i<blocks;i++){
			x=((unsigned char)data[3*i]<<16)|((unsigned char)data[3*i+1]<<8)|(unsigned char)data[3*i+2];
			res[4*i+3]=alphabet[x&0x3f]; x>>=6;
			res[4*i+2]=alphabet[x&0x3f]; x>>=6;
			res[4*i+1]=alphabet[x&0x3f]; x>>=6;
			res[4*i+0]=alphabet[x];
		}
		switch(sz%3){
			case 1:
				res[4*blocks+0]=alphabet[(unsigned char)data[3*blocks]>>2];
				res[4*blocks+1]=alphabet[((unsigned char)data[3*blocks]&0x3)<<4];
				res[4*blocks+2]='=';
				res[4*blocks+3]='=';
				break;

			case 2:
				res[4*blocks+0]=alphabet[(unsigned char)data[3*blocks]>>2];
				res[4*blocks+1]=alphabet[(((unsigned char)data[3*blocks]&0x3)<<4)|((unsigned char)data[3*blocks+1]>>4)];
				res[4*blocks+2]=alphabet[(((unsigned char)data[3*blocks+1]&0xf)<<2)];
				res[4*blocks+3]='=';
				break;
		}
		return res;
	}

	string decode(const string &dataS){
		int szS=dataS.size();
		if(szS==0)return {};
		uint8_t data[szS];
		int sz=0;
		for(char c : dataS){
			if(revbet[c&0x7f]!=127)data[sz++]=revbet[c&0x7f];
		}

		int blocks=sz/4;
		int endlen;
		if(sz%4==0){
			if(data[sz-1]=='='){
				blocks--;
				if(data[sz-2]=='=')endlen=1;
				else endlen=2;
			} else endlen=0;
		} else endlen=sz%4-1;
		string res(3*blocks+endlen,'\0');
		int x;
		for(int i=0;i<blocks;i++){
			x=(data[4*i]<<18)|(data[4*i+1]<<12)|(data[4*i+2]<<6)|data[4*i+3];
			res[3*i+2]=x&0xff; x>>=8;
			res[3*i+1]=x&0xff; x>>=8;
			res[3*i+0]=x;
		}
		switch(endlen){
			case 1:
				res[3*blocks+0]=(data[4*blocks]<<2)|(data[4*blocks+1]>>4);
				break;

			case 2:
				res[3*blocks+0]=(data[4*blocks]<<2)|(data[4*blocks+1]>>4);
				res[3*blocks+1]=(data[4*blocks+1]<<4)|(data[4*blocks+2]>>2);
				break;
		}
		return res;
	}

}