Adding Base32 decode method

It can currently decode when the encoded string is a multiple of 8
bytes.
This commit is contained in:
2024-09-01 10:44:50 +02:00
parent 044b2e3e8f
commit c8efdbdffe

84
src/base32.zig Normal file
View File

@@ -0,0 +1,84 @@
const std = @import("std");
const expect = std.testing.expect;
const expectEqualStrings = std.testing.expectEqualStrings;
const Allocator = std.mem.Allocator;
const Base32Error = error{InvalidLength};
const Base32 = struct {
///
pub fn decodeU8(allocator: Allocator, data: []const u8) ![]const u8 {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
if (data.len % 8 != 0) {
return error.InvalidLength;
}
const result = try allocator.alloc(u8, (data.len / 8) * 5);
var i: u64 = 0;
var r: usize = 0;
while (i < data.len) {
var bytes: u40 = 0;
const v1: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i]).?);
const v2: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 1]).?);
const v3: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 2]).?);
const v4: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 3]).?);
const v5: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 4]).?);
const v6: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 5]).?);
const v7: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 6]).?);
const v8: u8 = @truncate(std.mem.indexOfScalar(u8, alphabet, data[i + 7]).?);
bytes = v1;
bytes = bytes << 5 | v2;
bytes = bytes << 5 | v3;
bytes = bytes << 5 | v4;
bytes = bytes << 5 | v5;
bytes = bytes << 5 | v6;
bytes = bytes << 5 | v7;
bytes = bytes << 5 | v8;
i += 8;
result[r] = @as(u8, @truncate((bytes >> 32) & 0b11111111));
r += 1;
result[r] = @as(u8, @truncate((bytes >> 24) & 0b11111111));
r += 1;
result[r] = @as(u8, @truncate((bytes >> 16) & 0b11111111));
r += 1;
result[r] = @as(u8, @truncate((bytes >> 8) & 0b11111111));
r += 1;
result[r] = @as(u8, @truncate((bytes) & 0b11111111));
r += 1;
}
return result;
}
};
test "base32 decode base32('abcde') " {
try testDecode("abcde", "MFRGGZDF");
}
test "base32 decode base32('aaaaa') " {
try testDecode("aaaaa", "MFQWCYLB");
}
fn testDecode(expected_decoded: []const u8, encoded: []const u8) !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const decoded = try Base32.decodeU8(allocator, encoded);
try expectEqualStrings(expected_decoded, decoded);
}
test "base32 decode - invalid length" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
try std.testing.expect(Base32.decodeU8(allocator, "1") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "12") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "123") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "1234") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "12345") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "123456") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "1234567") == error.InvalidLength);
try std.testing.expect(Base32.decodeU8(allocator, "123456789") == error.InvalidLength);
}