diff options
Diffstat (limited to 'ext/librethinkdbxx/src/utils.cc')
-rw-r--r-- | ext/librethinkdbxx/src/utils.cc | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/ext/librethinkdbxx/src/utils.cc b/ext/librethinkdbxx/src/utils.cc new file mode 100644 index 00000000..5a2c244d --- /dev/null +++ b/ext/librethinkdbxx/src/utils.cc @@ -0,0 +1,153 @@ +#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"); + } +} + +} |