Adding Base32 decode method
It can currently decode when the encoded string is a multiple of 8 bytes.
This commit is contained in:
84
src/base32.zig
Normal file
84
src/base32.zig
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user