summaryrefslogtreecommitdiff
path: root/modules/codec/c++/base64.hpp
blob: b65060ef4f2fab47723aaf9f92f81601f6900385 (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
105
106
107
108
#pragma once

namespace saw {
namespace encode {
struct Base64 {};
}

template<>
class data<schema::String, encode::Base64, storage::Default> {
public:
	using Schema = schema::String;
private:
	std::string data_;
public:
	data() = default;

	data(std::string data__):
		data_{std::move(data__)}
	{}

	uint64_t size() const {
		return data_.size();
	}

	char& at(uint64_t i){
		return data_.at(i);
	}

	const char& at(uint64_t i) const {
		return data_.at(i);
	}

	std::string stl_string() const {
		return data_;
	}

	bool operator==(const data<Schema, encode::Base64>& rhs) const {
		return data_ == rhs.data_;
	}
};

namespace impl {
constexpr char base64_char_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
}

template<>
class codec<schema::String, encode::Base64> {
public:
	using Schema = schema::String;
private:
public:
	template<typename FromEncode>
	static error_or<void> encode(const data<Schema, FromEncode>& from, data<Schema,encode::Base64>& to){
		std::string b64_str;

		try {
			uint64_t unpadded_len = (from.size() * 4u + 2u) / 3u;
			uint64_t padded_len = ( unpadded_len + 3u ) & ~3u;
			b64_str.resize(padded_len);
		}catch(const std::exception&){
			return make_error<err::out_of_memory>();
		}

		uint64_t j{0u}, k{0u};
		std::array<uint8_t,3> s{};

		for(uint64_t i = 0u; i < from.size(); ++i){
			s[j] = from.at(i);
			++j;
			if(j==3){
				b64_str.at(k) = impl::base64_char_map[(s[0u] & 0xFC) >> 2];
				b64_str.at(k+1u) = impl::base64_char_map[((s[0u] & 0x03) << 4) | ((s[1] & 0xF0) >> 4)];
				b64_str.at(k+2u) = impl::base64_char_map[((s[1u] & 0x0F) << 2) | ((s[2] & 0xC0) >> 6)];
				b64_str.at(k+3u) = impl::base64_char_map[(s[2u] & 0x3F)];
				j = 0u;
				k+=4u;
			}
		}

		if(j > 0){
			if( j == 1u ){
				s[1u] = 0u;
			}

			b64_str.at(k+0u) = impl::base64_char_map[(s[0u] & 0xFF) >> 2];
			b64_str.at(k+1u) = impl::base64_char_map[((s[0u] & 0x03)<<4) + ((s[1u]&0xF0)>>4)];
			if(j == 2u){
				b64_str[k+2u] = impl::base64_char_map[ ((s[1u]&0x0F)<<2) ];
			}else {
				b64_str[k+2u] = '=';
			}
			b64_str[k+3u] = '=';
		}

		to = {std::move(b64_str)};
		return void_t{};
	}

	template<typename ToDecode>
	static error_or<void> decode(data<Schema,encode::Base64>& from, data<Schema, ToDecode>& to){
		(void) to;
		(void) from;

		return make_error<err::not_implemented>();
	}

};
}