mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-03 11:44:09 +00:00
154 lines
4.1 KiB
C++
154 lines
4.1 KiB
C++
#include "utils.h"
|
|
#include "error.h"
|
|
|
|
namespace RethinkDB {
|
|
|
|
size_t utf8_encode(unsigned int code, char* buf) {
|
|
if (!(code & ~0x7F)) {
|
|
buf[0] = code;
|
|
return 1;
|
|
} else if (!(code & ~0x7FF)) {
|
|
buf[0] = 0xC0 | (code >> 6);
|
|
buf[1] = 0x80 | (code & 0x3F);
|
|
return 2;
|
|
} else if (!(code & ~0xFFFF)) {
|
|
buf[0] = 0xE0 | (code >> 12);
|
|
buf[1] = 0x80 | ((code >> 6) & 0x3F);
|
|
buf[2] = 0x80 | (code & 0x3F);
|
|
return 3;
|
|
} else if (!(code & ~0x1FFFFF)) {
|
|
buf[0] = 0xF0 | (code >> 18);
|
|
buf[1] = 0x80 | ((code >> 12) & 0x3F);
|
|
buf[2] = 0x80 | ((code >> 6) & 0x3F);
|
|
buf[3] = 0x80 | (code & 0x3F);
|
|
return 4;
|
|
} else if (!(code & ~0x3FFFFFF)) {
|
|
buf[0] = 0xF8 | (code >> 24);
|
|
buf[1] = 0x80 | ((code >> 18) & 0x3F);
|
|
buf[2] = 0x80 | ((code >> 12) & 0x3F);
|
|
buf[3] = 0x80 | ((code >> 6) & 0x3F);
|
|
buf[4] = 0x80 | (code & 0x3F);
|
|
return 5;
|
|
} else if (!(code & ~0x7FFFFFFF)) {
|
|
buf[0] = 0xFC | (code >> 30);
|
|
buf[1] = 0x80 | ((code >> 24) & 0x3F);
|
|
buf[2] = 0x80 | ((code >> 18) & 0x3F);
|
|
buf[3] = 0x80 | ((code >> 12) & 0x3F);
|
|
buf[4] = 0x80 | ((code >> 6) & 0x3F);
|
|
buf[5] = 0x80 | (code & 0x3F);
|
|
return 6;
|
|
} else {
|
|
throw Error("Invalid unicode codepoint %ud", code);
|
|
}
|
|
}
|
|
|
|
bool base64_decode(char c, int* out) {
|
|
if (c >= 'A' && c <= 'Z') {
|
|
*out = c - 'A';
|
|
} else if (c >= 'a' && c <= 'z') {
|
|
*out = c - ('a' - 26);
|
|
} else if (c >= '0' && c <= '9') {
|
|
*out = c - ('0' - 52);
|
|
} else if (c == '+') {
|
|
*out = 62;
|
|
} else if (c == '/') {
|
|
*out = 63;
|
|
} else {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool base64_decode(const std::string& in, std::string& out) {
|
|
out.clear();
|
|
out.reserve(in.size() * 3 / 4);
|
|
auto read = in.begin();
|
|
while (true) {
|
|
int c[4];
|
|
int end = 4;
|
|
for (int i = 0; i < 4; i++) {
|
|
while (true) {
|
|
if (read == in.end()) {
|
|
c[i] = 0;
|
|
end = i;
|
|
i = 3;
|
|
break;
|
|
} else if (base64_decode(*read, &c[i])) {
|
|
++read;
|
|
break;
|
|
} else {
|
|
++read;
|
|
}
|
|
}
|
|
}
|
|
if (end == 1) return false;
|
|
int val = c[0] << 18 | c[1] << 12 | c[2] << 6 | c[3];
|
|
if (end > 1) out.append(1, val >> 16);
|
|
if (end > 2) out.append(1, val >> 8 & 0xFF);
|
|
if (end > 3) out.append(1, val & 0xFF);
|
|
if (end != 4) break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
char base64_encode(unsigned int c) {
|
|
if (c < 26) {
|
|
return 'A' + c;
|
|
} else if (c < 52) {
|
|
return 'a' + c - 26;
|
|
} else if (c < 62) {
|
|
return '0' + c - 52;
|
|
} else if (c == 62) {
|
|
return '+';
|
|
} else if (c == 63) {
|
|
return '/';
|
|
} else {
|
|
throw Error("unreachable: base64 encoding %d", c);
|
|
}
|
|
}
|
|
|
|
void base64_encode(unsigned int* c, int n, std::string& out) {
|
|
if (n == 0) {
|
|
return;
|
|
}
|
|
out.append(1, base64_encode(c[0] >> 2));
|
|
out.append(1, base64_encode((c[0] & 0x3) << 4 | c[1] >> 4));
|
|
if (n == 1) {
|
|
out.append("==");
|
|
return;
|
|
}
|
|
out.append(1, base64_encode((c[1] & 0xF) << 2 | c[2] >> 6));
|
|
if (n == 2) {
|
|
out.append("=");
|
|
return;
|
|
}
|
|
out.append(1, base64_encode(c[2] & 0x3F));
|
|
}
|
|
|
|
std::string base64_encode(const std::string& in) {
|
|
std::string out;
|
|
out.reserve(in.size() * 4 / 3 + in.size() / 48 + 3);
|
|
auto read = in.begin();
|
|
while (true) {
|
|
for (int group = 0; group < 16; ++group) {
|
|
unsigned int c[3];
|
|
int i = 0;
|
|
for (; i < 3; ++i) {
|
|
if (read == in.end()) {
|
|
c[i] = 0;
|
|
break;
|
|
} else {
|
|
c[i] = static_cast<unsigned char>(*read++);
|
|
}
|
|
}
|
|
base64_encode(c, i, out);
|
|
if (i != 3) {
|
|
return out;
|
|
}
|
|
}
|
|
out.append("\n");
|
|
}
|
|
}
|
|
|
|
}
|