| ... | ... | @@ -2,8 +2,16 @@ const std = @import("std"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | 3 | const testing = std.testing; |
| 4 | 4 | |
| 5 | | pub fn bitReader(reader: anytype) BitReader(@TypeOf(reader)) { |
| 6 | | return BitReader(@TypeOf(reader)).init(reader); |
| 5 | pub fn bitReader(comptime T: type, reader: anytype) BitReader(T, @TypeOf(reader)) { |
| 6 | return BitReader(T, @TypeOf(reader)).init(reader); |
| 7 | } |
| 8 | |
| 9 | pub fn BitReader64(comptime ReaderType: type) type { |
| 10 | return BitReader(u64, ReaderType); |
| 11 | } |
| 12 | |
| 13 | pub fn BitReader32(comptime ReaderType: type) type { |
| 14 | return BitReader(u32, ReaderType); |
| 7 | 15 | } |
| 8 | 16 | |
| 9 | 17 | /// Bit reader used during inflate (decompression). Has internal buffer of 64 |
| ... | ... | @@ -15,12 +23,16 @@ pub fn bitReader(reader: anytype) BitReader(@TypeOf(reader)) { |
| 15 | 23 | /// fill buffer from forward_reader by calling fill in advance and readF with |
| 16 | 24 | /// buffered flag set. |
| 17 | 25 | /// |
| 18 | | pub fn BitReader(comptime ReaderType: type) type { |
| 26 | pub fn BitReader(T: type, comptime ReaderType: type) type { |
| 27 | assert(T == u32 or T == u64); |
| 28 | const t_bytes: usize = @sizeOf(T); |
| 29 | const Tshift = if (T == u64) u6 else u5; |
| 30 | |
| 19 | 31 | return struct { |
| 20 | 32 | // Underlying reader used for filling internal bits buffer |
| 21 | 33 | forward_reader: ReaderType = undefined, |
| 22 | 34 | // Internal buffer of 64 bits |
| 23 | | bits: u64 = 0, |
| 35 | bits: T = 0, |
| 24 | 36 | // Number of bits in the buffer |
| 25 | 37 | nbits: u32 = 0, |
| 26 | 38 | |
| ... | ... | @@ -51,14 +63,14 @@ pub fn BitReader(comptime ReaderType: type) type { |
| 51 | 63 | |
| 52 | 64 | // Number of empty bytes in bits, round nbits to whole bytes. |
| 53 | 65 | const empty_bytes = |
| 54 | | @as(u8, if (self.nbits & 0x7 == 0) 8 else 7) - // 8 for 8, 16, 24..., 7 otherwise |
| 66 | @as(u8, if (self.nbits & 0x7 == 0) t_bytes else t_bytes - 1) - // 8 for 8, 16, 24..., 7 otherwise |
| 55 | 67 | (self.nbits >> 3); // 0 for 0-7, 1 for 8-16, ... same as / 8 |
| 56 | 68 | |
| 57 | | var buf: [8]u8 = [_]u8{0} ** 8; |
| 69 | var buf: [t_bytes]u8 = [_]u8{0} ** t_bytes; |
| 58 | 70 | const bytes_read = self.forward_reader.readAll(buf[0..empty_bytes]) catch 0; |
| 59 | 71 | if (bytes_read > 0) { |
| 60 | | const u: u64 = std.mem.readInt(u64, buf[0..8], .little); |
| 61 | | self.bits |= u << @as(u6, @intCast(self.nbits)); |
| 72 | const u: T = std.mem.readInt(T, buf[0..t_bytes], .little); |
| 73 | self.bits |= u << @as(Tshift, @intCast(self.nbits)); |
| 62 | 74 | self.nbits += 8 * @as(u8, @intCast(bytes_read)); |
| 63 | 75 | return; |
| 64 | 76 | } |
| ... | ... | @@ -99,7 +111,17 @@ pub fn BitReader(comptime ReaderType: type) type { |
| 99 | 111 | |
| 100 | 112 | /// Read with flags provided. |
| 101 | 113 | pub fn readF(self: *Self, comptime U: type, comptime how: u3) !U { |
| 102 | | const n: u6 = @bitSizeOf(U); |
| 114 | if (U == T) { |
| 115 | assert(how == 0); |
| 116 | assert(self.alignBits() == 0); |
| 117 | try self.fill(@bitSizeOf(T)); |
| 118 | assert(self.nbits == @bitSizeOf(T)); |
| 119 | const v = self.bits; |
| 120 | self.nbits = 0; |
| 121 | self.bits = 0; |
| 122 | return v; |
| 123 | } |
| 124 | const n: Tshift = @bitSizeOf(U); |
| 103 | 125 | switch (how) { |
| 104 | 126 | 0 => { // `normal` read |
| 105 | 127 | try self.fill(n); // ensure that there are n bits in the buffer |
| ... | ... | @@ -157,7 +179,7 @@ pub fn BitReader(comptime ReaderType: type) type { |
| 157 | 179 | } |
| 158 | 180 | |
| 159 | 181 | /// Advance buffer for n bits. |
| 160 | | pub fn shift(self: *Self, n: u6) !void { |
| 182 | pub fn shift(self: *Self, n: Tshift) !void { |
| 161 | 183 | if (n > self.nbits) return error.EndOfStream; |
| 162 | 184 | self.bits >>= n; |
| 163 | 185 | self.nbits -= n; |
| ... | ... | @@ -218,10 +240,10 @@ pub fn BitReader(comptime ReaderType: type) type { |
| 218 | 240 | }; |
| 219 | 241 | } |
| 220 | 242 | |
| 221 | | test "BitReader" { |
| 243 | test "readF" { |
| 222 | 244 | var fbs = std.io.fixedBufferStream(&[_]u8{ 0xf3, 0x48, 0xcd, 0xc9, 0x00, 0x00 }); |
| 223 | | var br = bitReader(fbs.reader()); |
| 224 | | const F = BitReader(@TypeOf(fbs.reader())).flag; |
| 245 | var br = bitReader(u64, fbs.reader()); |
| 246 | const F = BitReader64(@TypeOf(fbs.reader())).flag; |
| 225 | 247 | |
| 226 | 248 | try testing.expectEqual(@as(u8, 48), br.nbits); |
| 227 | 249 | try testing.expectEqual(@as(u64, 0xc9cd48f3), br.bits); |
| ... | ... | @@ -254,36 +276,38 @@ test "BitReader" { |
| 254 | 276 | } |
| 255 | 277 | |
| 256 | 278 | test "read block type 1 data" { |
| 257 | | const data = [_]u8{ |
| 258 | | 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1 |
| 259 | | 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00, |
| 260 | | 0x0c, 0x01, 0x02, 0x03, // |
| 261 | | 0xaa, 0xbb, 0xcc, 0xdd, |
| 262 | | }; |
| 263 | | var fbs = std.io.fixedBufferStream(&data); |
| 264 | | var br = bitReader(fbs.reader()); |
| 265 | | const F = BitReader(@TypeOf(fbs.reader())).flag; |
| 279 | inline for ([_]type{ u64, u32 }) |T| { |
| 280 | const data = [_]u8{ |
| 281 | 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1 |
| 282 | 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00, |
| 283 | 0x0c, 0x01, 0x02, 0x03, // |
| 284 | 0xaa, 0xbb, 0xcc, 0xdd, |
| 285 | }; |
| 286 | var fbs = std.io.fixedBufferStream(&data); |
| 287 | var br = bitReader(T, fbs.reader()); |
| 288 | const F = BitReader(T, @TypeOf(fbs.reader())).flag; |
| 266 | 289 | |
| 267 | | try testing.expectEqual(@as(u1, 1), try br.readF(u1, 0)); // bfinal |
| 268 | | try testing.expectEqual(@as(u2, 1), try br.readF(u2, 0)); // block_type |
| 290 | try testing.expectEqual(@as(u1, 1), try br.readF(u1, 0)); // bfinal |
| 291 | try testing.expectEqual(@as(u2, 1), try br.readF(u2, 0)); // block_type |
| 269 | 292 | |
| 270 | | for ("Hello world\n") |c| { |
| 271 | | try testing.expectEqual(@as(u8, c), try br.readF(u8, F.reverse) - 0x30); |
| 293 | for ("Hello world\n") |c| { |
| 294 | try testing.expectEqual(@as(u8, c), try br.readF(u8, F.reverse) - 0x30); |
| 295 | } |
| 296 | try testing.expectEqual(@as(u7, 0), try br.readF(u7, 0)); // end of block |
| 297 | br.alignToByte(); |
| 298 | try testing.expectEqual(@as(u32, 0x0302010c), try br.readF(u32, 0)); |
| 299 | try testing.expectEqual(@as(u16, 0xbbaa), try br.readF(u16, 0)); |
| 300 | try testing.expectEqual(@as(u16, 0xddcc), try br.readF(u16, 0)); |
| 272 | 301 | } |
| 273 | | try testing.expectEqual(@as(u7, 0), try br.readF(u7, 0)); // end of block |
| 274 | | br.alignToByte(); |
| 275 | | try testing.expectEqual(@as(u32, 0x0302010c), try br.readF(u32, 0)); |
| 276 | | try testing.expectEqual(@as(u16, 0xbbaa), try br.readF(u16, 0)); |
| 277 | | try testing.expectEqual(@as(u16, 0xddcc), try br.readF(u16, 0)); |
| 278 | 302 | } |
| 279 | 303 | |
| 280 | | test "init" { |
| 304 | test "shift/fill" { |
| 281 | 305 | const data = [_]u8{ |
| 282 | 306 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 283 | 307 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 284 | 308 | }; |
| 285 | 309 | var fbs = std.io.fixedBufferStream(&data); |
| 286 | | var br = bitReader(fbs.reader()); |
| 310 | var br = bitReader(u64, fbs.reader()); |
| 287 | 311 | |
| 288 | 312 | try testing.expectEqual(@as(u64, 0x08_07_06_05_04_03_02_01), br.bits); |
| 289 | 313 | try br.shift(8); |
| ... | ... | @@ -303,31 +327,39 @@ test "init" { |
| 303 | 327 | } |
| 304 | 328 | |
| 305 | 329 | test "readAll" { |
| 306 | | const data = [_]u8{ |
| 307 | | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 308 | | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 309 | | }; |
| 310 | | var fbs = std.io.fixedBufferStream(&data); |
| 311 | | var br = bitReader(fbs.reader()); |
| 330 | inline for ([_]type{ u64, u32 }) |T| { |
| 331 | const data = [_]u8{ |
| 332 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 333 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 334 | }; |
| 335 | var fbs = std.io.fixedBufferStream(&data); |
| 336 | var br = bitReader(T, fbs.reader()); |
| 312 | 337 | |
| 313 | | try testing.expectEqual(@as(u64, 0x08_07_06_05_04_03_02_01), br.bits); |
| 338 | switch (T) { |
| 339 | u64 => try testing.expectEqual(@as(u64, 0x08_07_06_05_04_03_02_01), br.bits), |
| 340 | u32 => try testing.expectEqual(@as(u32, 0x04_03_02_01), br.bits), |
| 341 | else => unreachable, |
| 342 | } |
| 314 | 343 | |
| 315 | | var out: [16]u8 = undefined; |
| 316 | | try br.readAll(out[0..]); |
| 317 | | try testing.expect(br.nbits == 0); |
| 318 | | try testing.expect(br.bits == 0); |
| 344 | var out: [16]u8 = undefined; |
| 345 | try br.readAll(out[0..]); |
| 346 | try testing.expect(br.nbits == 0); |
| 347 | try testing.expect(br.bits == 0); |
| 319 | 348 | |
| 320 | | try testing.expectEqualSlices(u8, data[0..16], &out); |
| 349 | try testing.expectEqualSlices(u8, data[0..16], &out); |
| 350 | } |
| 321 | 351 | } |
| 322 | 352 | |
| 323 | 353 | test "readFixedCode" { |
| 324 | | const fixed_codes = @import("huffman_encoder.zig").fixed_codes; |
| 354 | inline for ([_]type{ u64, u32 }) |T| { |
| 355 | const fixed_codes = @import("huffman_encoder.zig").fixed_codes; |
| 325 | 356 | |
| 326 | | var fbs = std.io.fixedBufferStream(&fixed_codes); |
| 327 | | var rdr = bitReader(fbs.reader()); |
| 357 | var fbs = std.io.fixedBufferStream(&fixed_codes); |
| 358 | var rdr = bitReader(T, fbs.reader()); |
| 328 | 359 | |
| 329 | | for (0..286) |c| { |
| 330 | | try testing.expectEqual(c, try rdr.readFixedCode()); |
| 360 | for (0..286) |c| { |
| 361 | try testing.expectEqual(c, try rdr.readFixedCode()); |
| 362 | } |
| 363 | try testing.expect(rdr.nbits == 0); |
| 331 | 364 | } |
| 332 | | try testing.expect(rdr.nbits == 0); |
| 333 | 365 | } |