summaryrefslogtreecommitdiffstats
blob: ec6f960157a4999ca019e314bde95d472cfa3d99 (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
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * Copyright (c) 2013 Remko Tronçon
 * Licensed under the GNU General Public License v3.
 * See Documentation/Licenses/GPLv3.txt for more information.
 */

#include <Swiften/StringCodecs/Base64.h>

#pragma clang diagnostic ignored "-Wconversion"

using namespace Swift;

namespace {
	const char* encodeMap =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	const unsigned char decodeMap[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, 255, 62,  255, 255, 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, 255,
		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
	};

	template<typename ResultType, typename InputType>
	ResultType encodeDetail(const InputType& input) {
		ResultType result;
		size_t i = 0;
		for (; i < (input.size()/3)*3; i += 3) {
			unsigned int c = input[i+2] | (input[i+1]<<8) | (input[i]<<16);
			result.push_back(encodeMap[(c&0xFC0000)>>18]);
			result.push_back(encodeMap[(c&0x3F000)>>12]);
			result.push_back(encodeMap[(c&0xFC0)>>6]);
			result.push_back(encodeMap[c&0x3F]);
		}
		if (input.size() % 3 == 2) {
			unsigned int c = (input[i+1]<<8) | (input[i]<<16);
			result.push_back(encodeMap[(c&0xFC0000)>>18]);
			result.push_back(encodeMap[(c&0x3F000)>>12]);
			result.push_back(encodeMap[(c&0xFC0)>>6]);
			result.push_back('=');
		}
		else if (input.size() % 3 == 1) {
			unsigned int c = input[i]<<16;
			result.push_back(encodeMap[(c&0xFC0000)>>18]);
			result.push_back(encodeMap[(c&0x3F000)>>12]);
			result.push_back('=');
			result.push_back('=');
		}
		return result;
	}
}


std::string Base64::encode(const ByteArray& s) {
	return encodeDetail<std::string>(s);
}

SafeByteArray Base64::encode(const SafeByteArray& s) {
	return encodeDetail<SafeByteArray>(s);
}

ByteArray Base64::decode(const std::string& input1) {
	ByteArray result;
	std::string input(input1);
	input.erase(std::remove(input.begin(), input.end(), '\n'), input.end());
	input.erase(std::remove(input.begin(), input.end(), '\r'), input.end());

	if (input.size() % 4) {
		return ByteArray();
	}
	for (size_t i = 0; i < input.size(); i += 4) {
		unsigned char c1 = input[i+0];
		unsigned char c2 = input[i+1];
		unsigned char c3 = input[i+2];
		unsigned char c4 = input[i+3];
		if (c3 == '=') {
			unsigned int c = (((decodeMap[c1]<<6)|decodeMap[c2])&0xFF0)>>4;
			result.push_back(c);
		}
		else if (c4 == '=') {
			unsigned int c = (((decodeMap[c1]<<12)|(decodeMap[c2]<<6)|decodeMap[c3])&0x3FFFC)>>2;
			result.push_back((c&0xFF00) >> 8);
			result.push_back(c&0xFF);
		}
		else {
			unsigned int c = (decodeMap[c1]<<18) | (decodeMap[c2]<<12) | (decodeMap[c3]<<6) | decodeMap[c4];
			result.push_back((c&0xFF0000) >> 16);
			result.push_back((c&0xFF00) >> 8);
			result.push_back(c&0xFF);
		}
	}
	return result;
}