summaryrefslogtreecommitdiff
path: root/ext/librethinkdbxx/src/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/librethinkdbxx/src/utils.cc')
-rw-r--r--ext/librethinkdbxx/src/utils.cc153
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");
+ }
+}
+
+}