aboutsummaryrefslogtreecommitdiffstats
path: root/src/base32.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/base32.zig')
-rw-r--r--src/base32.zig105
1 files changed, 71 insertions, 34 deletions
diff --git a/src/base32.zig b/src/base32.zig
index b1400a5..26622d8 100644
--- a/src/base32.zig
+++ b/src/base32.zig
@@ -1,40 +1,83 @@
1const std = @import("std"); 1const std = @import("std");
2 2
3// TODO(rutgerbrf): simplify the code of the encoder & decoder?
4
5pub const Encoder = struct { 3pub const Encoder = struct {
6 const Self = @This(); 4 const Self = @This();
7 5
8 out_off: u4 = 0, 6 buffer: []const u8,
9 buf: u5 = 0, 7 index: ?usize,
8 bit_off: u3,
10 9
11 pub fn write(self: *Self, b: u8, out: []u8) usize { 10 fn bitmask(self: *const Self) u8 {
12 var i: usize = 0; 11 return @as(u8, 0b11111000) >> self.bit_off;
13 var bits_left: u4 = 8; 12 }
14 while (bits_left > 0) { 13
15 var space_avail = @truncate(u3, 5 - self.out_off); 14 fn n_front_bits(self: *const Self) u3 {
16 var write_bits: u3 = if (bits_left < space_avail) @truncate(u3, bits_left) else space_avail; 15 // bit_off n_front_bits
17 bits_left -= write_bits; 16 // 0 5
18 var mask: u8 = (@as(u8, 0x01) << write_bits) - 1; 17 // 1 5
19 var want: u8 = (b >> @truncate(u3, bits_left)) & mask; 18 // 2 5
20 self.buf |= @truncate(u5, want << (space_avail - write_bits)); 19 // 3 5
21 self.out_off += write_bits; 20 // 4 4
22 if (self.out_off == 5) { 21 // 5 3
23 if (i >= out.len) break; 22 // 6 2
24 out[i] = self.char(); 23 // 7 1
25 i += 1; 24 return if (self.bit_off <= 3) 5 else 7 - self.bit_off + 1;
26 self.out_off = 0; 25 }
27 self.buf = 0; 26
27 fn front(self: *const Self, index: usize) u5 {
28 // bit_off bits shl shr front
29 // 0 0b11111000 3 0b11111
30 // 1 0b01111100 2 0b11111
31 // 2 0b00111110 1 0b11111
32 // 3 0b00011111 0 0 0b11111
33 // 4 0b00001111 1 0b11110
34 // 5 0b00000111 2 0b11100
35 // 6 0b00000011 3 0b11000
36 // 7 0b00000001 4 0b10000
37 const bits = self.buffer[index] & self.bitmask();
38 if (self.bit_off >= 4) return @truncate(u5, bits << (self.bit_off - 3));
39 return @truncate(u5, bits >> (3 - self.bit_off));
40 }
41
42 fn back(self: *const Self, index: usize, bits: u3) u5 {
43 if (bits == 0) return 0;
44 return @truncate(u5, self.buffer[index] >> (7 - bits + 1));
45 }
46
47 fn next_u5(self: *Self) ?u5 {
48 const front_index = self.index orelse return null;
49 const num_front_bits = self.n_front_bits();
50 const front_bits = self.front(front_index);
51
52 var back_bits: u5 = 0;
53 if (self.bit_off >= 3) {
54 self.bit_off -= 3;
55 const new_index = front_index + 1;
56 if (self.buffer.len > new_index) {
57 self.index = new_index;
58 back_bits = self.back(new_index, 5 - num_front_bits);
59 } else {
60 self.index = null;
28 } 61 }
62 } else {
63 self.bit_off += 5;
29 } 64 }
30 return i; 65
66 return front_bits | back_bits;
67 }
68
69 fn char(unencoded: u5) u8 {
70 return unencoded + (if (unencoded < 26) @as(u8, 'A') else '2' - 26);
31 } 71 }
32 72
33 fn char(self: *const Self) u8 { 73 pub fn next(self: *Self) ?u8 {
34 return self.buf + (if (self.buf < 26) @as(u8, 'A') else '2' - 26); 74 const unencoded = self.next_u5() orelse return null;
75 return char(unencoded);
35 } 76 }
36}; 77};
37 78
79// TODO(rutgerbrf): simplify the code of the decoder
80
38pub const DecodeError = error{CorruptInputError}; 81pub const DecodeError = error{CorruptInputError};
39 82
40pub const Decoder = struct { 83pub const Decoder = struct {
@@ -89,17 +132,11 @@ pub fn decodedLen(enc_len: usize) usize {
89} 132}
90 133
91pub fn encode(bs: []const u8, out: []u8) usize { 134pub fn encode(bs: []const u8, out: []u8) usize {
92 var e = Encoder{}; 135 var e = Encoder{ .buffer = bs, .index = 0, .bit_off = 0 };
93 var i: usize = 0; 136 for (out) |*b, i| {
94 for (bs) |b| { 137 b.* = e.next() orelse return i;
95 if (i >= out.len) break;
96 i += e.write(b, out[i..]);
97 } 138 }
98 if (e.out_off != 0 and i < out.len) { 139 return out.len;
99 out[i] = e.char();
100 i += 1;
101 }
102 return i; // amount of bytes processed
103} 140}
104 141
105pub fn decode(ps: []const u8, out: []u8) DecodeError!usize { 142pub fn decode(ps: []const u8, out: []u8) DecodeError!usize {