feat: Add rudimentary base64 encoding
2 files changed, 79 insertions(+), 4 deletions(-)

M src/baseenc.c
M src/baseenc.zig
M src/baseenc.c +22 -0
@@ 1,6 1,28 @@ 
+#include <stdint.h>
 #include <janet.h>
 
+extern ssize_t base_64_encode(const uint8_t*, size_t, uint8_t*, size_t);
+
+static Janet Baseenc_base64Encode(int argc, Janet argv[]) {
+  janet_arity(argc, 1, 2);
+  JanetByteView data = janet_getbytes(argv, 0);
+  JanetBuffer *buf;
+  if (argc > 1) {
+    buf = janet_getbuffer(argv, 1);
+  } else {
+    buf = janet_buffer((data.len * 4 + 3) / 3);
+  }
+
+  ssize_t len = base_64_encode(&data.bytes[0], (size_t)data.len, &buf->data[0], (size_t)buf->capacity);
+  if (len == -1) {
+    janet_panic("buffer overflow");
+  }
+  buf->count = (int32_t)len;
+  return janet_wrap_buffer(buf);
+}
+
 static const JanetReg Baseenc_cfuns[] = {
+  { "base64-encode", Baseenc_base64Encode, NULL },
   { NULL, NULL, NULL },
 };
 

          
M src/baseenc.zig +57 -4
@@ 1,9 1,62 @@ 
 const std = @import("std");
 
-export fn add(a: i32, b: i32) i32 {
-    return a + b;
+const EncDecError = error{
+    BufferOverflow,
+};
+
+const Base64 = struct {
+    const pad = @as(u8, '=');
+    const alphabet: *const [64]u8 =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++
+        "abcdefghijklmnopqrstuvwxyz" ++
+        "0123456789+/";
+    fn encode(in: []const u8, out: []u8) EncDecError!usize {
+        var i = @as(usize, 0);
+        var j = @as(usize, 0);
+        while (i < in.len) {
+            if (j + 4 > out.len) return EncDecError.BufferOverflow;
+            const a = @intCast(u32, in[i]);
+            const b = if (i + 1 < in.len) @intCast(u32, in[i + 1]) else 0;
+            const c = if (i + 2 < in.len) @intCast(u32, in[i + 2]) else 0;
+            out[j] = alphabet[a >> 2];
+            out[j + 1] = alphabet[(a << 4 & 0b110000) | (b >> 4 & 0b001111)];
+            out[j + 2] = alphabet[(b << 2 & 0b111100) | (c >> 6 & 0b000011)];
+            out[j + 3] = alphabet[c & 0b111111];
+            if (i + 1 >= in.len) {
+                out[j + 2] = pad;
+                out[j + 3] = pad;
+            } else if (i + 2 >= in.len) {
+                out[j + 3] = pad;
+            }
+
+            i += 3;
+            j += 4;
+        }
+
+        return j;
+    }
+
+    fn decode(in: []const u8, out: []u8) EncDecError!usize {
+        _ = in;
+        _ = out;
+        return EncDecError.BufferOverflow;
+    }
+};
+
+export fn base_64_encode(in_buf: [*]const u8, in_len: usize, out_buf: [*]u8, out_len: usize) isize {
+    const in = in_buf[0..in_len];
+    const out = out_buf[0..out_len];
+
+    return @intCast(isize, Base64.encode(in, out) catch |err| switch (err) {
+        EncDecError.BufferOverflow => return -1,
+    });
 }
 
-test "basic add functionality" {
-    try std.testing.expect(add(3, 7) == 10);
+export fn base_64_decode(in_buf: [*]const u8, in_len: usize, out_buf: [*]u8, out_len: usize) isize {
+    const in = in_buf[0..in_len];
+    const out = out_buf[0..out_len];
+
+    return @intCast(isize, Base64.decode(in, out) catch |err| switch (err) {
+        EncDecError.BufferOverflow => return -1,
+    });
 }