@@ -9,11 +9,9 @@ const Error = error{
9
9
OutOfMemory ,
10
10
};
11
11
12
- // 2-7: 50-55
13
- // A-Z: 65-90
14
12
pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" .* ;
15
13
pub const standard_alphabet_values = [32 ]u8 {
16
- 0b00_00000 , // A
14
+ 0b00_00000 ,
17
15
0b00_00001 ,
18
16
0b00_00010 ,
19
17
0b00_00011 ,
@@ -39,12 +37,12 @@ pub const standard_alphabet_values = [32]u8{
39
37
0b00_10111 ,
40
38
0b00_11000 ,
41
39
0b00_11001 ,
42
- 0b00_11010 , // 2
43
- 0b00_11011 , // 3
44
- 0b00_11100 , // 4
45
- 0b00_11101 , // 5
46
- 0b00_11110 , // 6
47
- 0b00_11111 , // 7
40
+ 0b00_11010 ,
41
+ 0b00_11011 ,
42
+ 0b00_11100 ,
43
+ 0b00_11101 ,
44
+ 0b00_11110 ,
45
+ 0b00_11111 ,
48
46
};
49
47
50
48
pub const Base32Encoder = struct {
@@ -62,9 +60,7 @@ pub const Base32Encoder = struct {
62
60
const rem : u8 = @intCast (u8 , text .len % wsize );
63
61
const n : u8 = @intCast (u8 , text .len / wsize );
64
62
var buf : [9 ]u8 = .{0 } ** 9 ;
65
-
66
- const allocator = self .allocator ;
67
- var list = std .ArrayList (u8 ).init (allocator );
63
+ var list = std .ArrayList (u8 ).init (self .allocator );
68
64
69
65
for (0.. n ) | i | {
70
66
for (wsize * i .. wsize * (i + 1 )) | j | {
@@ -122,6 +118,67 @@ pub const Base32Encoder = struct {
122
118
123
119
return Error .InvalidCharacter ;
124
120
}
121
+
122
+ fn lookup_v (b : u8 ) Error ! u8 {
123
+ for (standard_alphabet_chars , 0.. ) | x , i | {
124
+ if (b == x ) return standard_alphabet_values [i ];
125
+ }
126
+
127
+ return Error .InvalidCharacter ;
128
+ }
129
+
130
+ pub fn decode (self : * Self , text : []const u8 ) Error ! []u8 {
131
+ if (text .len % 8 != 0 ) return Error .InvalidPadding ;
132
+ const wsize = 8 ;
133
+ const n : u8 = @intCast (u8 , text .len / wsize );
134
+ var buf : [9 ]u8 = .{0 } ** 9 ;
135
+ var list = std .ArrayList (u8 ).init (self .allocator );
136
+
137
+ for (0.. n ) | i | {
138
+ for (wsize * i .. wsize * (i + 1 )) | j | {
139
+ if (text [j ] == "=" [0 ]) break ;
140
+ buf [buf [8 ]] = text [j ];
141
+ buf [8 ] += 1 ;
142
+ }
143
+
144
+ const spit = try spit_decoded (buf );
145
+ try list .appendSlice (spit [0.. spit [8 ]]);
146
+ buf = .{0 } ** 9 ;
147
+ }
148
+
149
+ return list .items ;
150
+ }
151
+
152
+ fn spit_decoded (src : [9 ]u8 ) Error ! [9 ]u8 {
153
+ var dest : [9 ]u8 = .{0 } ** 9 ;
154
+ var lut = [_ ]u8 {0 } ** 8 ;
155
+ inline for (0.. 8) | i | {
156
+ lut [i ] = Base32Encoder .lookup_v (src [i ]) catch 0 ;
157
+ }
158
+
159
+ if (src [8 ] > 1 ) {
160
+ dest [0 ] = lut [0 ] << 3 | lut [1 ] >> 2 ;
161
+ dest [8 ] = 1 ;
162
+ }
163
+ if (src [8 ] > 3 ) {
164
+ dest [1 ] = lut [1 ] << 6 | lut [2 ] << 1 | lut [3 ] >> 4 ;
165
+ dest [8 ] = 2 ;
166
+ }
167
+ if (src [8 ] > 4 ) {
168
+ dest [2 ] = lut [3 ] << 4 | lut [4 ] >> 1 ;
169
+ dest [8 ] = 3 ;
170
+ }
171
+ if (src [8 ] > 6 ) {
172
+ dest [3 ] = lut [4 ] << 7 | lut [5 ] << 2 | lut [6 ] >> 3 ;
173
+ dest [8 ] = 4 ;
174
+ }
175
+ if (src [8 ] == 8 ) {
176
+ dest [4 ] = lut [6 ] << 5 | lut [7 ];
177
+ dest [8 ] = 5 ;
178
+ }
179
+
180
+ return dest ;
181
+ }
125
182
};
126
183
127
184
const TestPair = struct {
@@ -150,3 +207,25 @@ test "encode string" {
150
207
try testing .expect (std .mem .eql (u8 , res , t .expect ));
151
208
}
152
209
}
210
+
211
+ test "decode string" {
212
+ var arena = std .heap .ArenaAllocator .init (std .heap .page_allocator );
213
+ defer arena .deinit ();
214
+ const allocator = arena .allocator ();
215
+ var b32 = Base32Encoder .init (allocator );
216
+ const testCases = [_ ]TestPair {
217
+ .{ .arg = "JA======" , .expect = "H" },
218
+ .{ .arg = "JBSQ====" , .expect = "He" },
219
+ .{ .arg = "JBSWY===" , .expect = "Hel" },
220
+ .{ .arg = "JBSWY3A=" , .expect = "Hell" },
221
+ .{ .arg = "JBSWY3DP" , .expect = "Hello" },
222
+ .{ .arg = "JBSWY3DPEE======" , .expect = "Hello!" },
223
+ .{ .arg = "GEZDGNBVGY3TQOI=" , .expect = "123456789" },
224
+ .{ .arg = "GEZDGNBVGY3TQOJQGEZDGNBV" , .expect = "123456789012345" },
225
+ };
226
+
227
+ for (testCases ) | t | {
228
+ const res = try b32 .decode (t .arg );
229
+ try testing .expect (std .mem .eql (u8 , res , t .expect ));
230
+ }
231
+ }
0 commit comments