Add git_buf_put_base64 to buffer API
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
diff --git a/src/buffer.c b/src/buffer.c
index 61cfaf9..ee2dd28 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -186,6 +186,46 @@ int git_buf_puts_escaped(
return 0;
}
+static const char b64str[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int git_buf_put_base64(git_buf *buf, const char *data, size_t len)
+{
+ size_t extra = len % 3;
+ uint8_t *write, a, b, c;
+ const uint8_t *read = (const uint8_t *)data;
+
+ ENSURE_SIZE(buf, buf->size + ((len * 4 + 3) / 3) + 1);
+ write = (uint8_t *)&buf->ptr[buf->size];
+
+ /* convert each run of 3 bytes into 4 output bytes */
+ for (len -= extra; len > 0; len -= 3) {
+ a = *read++;
+ b = *read++;
+ c = *read++;
+
+ *write++ = b64str[a >> 2];
+ *write++ = b64str[(a & 0x03) << 4 | b >> 4];
+ *write++ = b64str[(b & 0x0f) << 2 | c >> 6];
+ *write++ = b64str[c & 0x3f];
+ }
+
+ if (extra > 0) {
+ a = *read++;
+ b = (extra > 1) ? *read++ : 0;
+
+ *write++ = b64str[a >> 2];
+ *write++ = b64str[(a & 0x03) << 4 | b >> 4];
+ *write++ = (extra > 1) ? b64str[(b & 0x0f) << 2] : '=';
+ *write++ = '=';
+ }
+
+ buf->size = ((char *)write) - buf->ptr;
+ buf->ptr[buf->size] = '\0';
+
+ return 0;
+}
+
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
{
int len;
diff --git a/src/buffer.h b/src/buffer.h
index 17922e4..94b7e0e 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -154,4 +154,7 @@ bool git_buf_is_binary(const git_buf *buf);
/* Unescape all characters in a buffer */
void git_buf_unescape(git_buf *buf);
+/* Write data as base64 encoded in buffer */
+int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
+
#endif
diff --git a/tests-clar/core/buffer.c b/tests-clar/core/buffer.c
index 972567e..236bf39 100644
--- a/tests-clar/core/buffer.c
+++ b/tests-clar/core/buffer.c
@@ -678,3 +678,28 @@ void test_core_buffer__unescape(void)
assert_unescape("\\", "\\\\");
assert_unescape("", "");
}
+
+void test_core_buffer__base64(void)
+{
+ git_buf buf = GIT_BUF_INIT;
+
+ /* t h i s
+ * 0x 74 68 69 73
+ * 0b 01110100 01101000 01101001 01110011
+ * 0b 011101 000110 100001 101001 011100 110000
+ * 0x 1d 06 21 29 1c 30
+ * d G h p c w
+ */
+ cl_git_pass(git_buf_put_base64(&buf, "this", 4));
+ cl_assert_equal_s("dGhpcw==", buf.ptr);
+
+ git_buf_clear(&buf);
+ cl_git_pass(git_buf_put_base64(&buf, "this!", 5));
+ cl_assert_equal_s("dGhpcyE=", buf.ptr);
+
+ git_buf_clear(&buf);
+ cl_git_pass(git_buf_put_base64(&buf, "this!\n", 6));
+ cl_assert_equal_s("dGhpcyEK", buf.ptr);
+
+ git_buf_free(&buf);
+}