diff --git a/src/main.zig b/src/main.zig index 3e0d8b2..696058a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -261,12 +261,11 @@ const BlockData = struct { if (self.blockType != 2) { return error.unsuported_block_type; } - - try self.dynamic_huffman; + try self.dynamic_huffman(); } - fn dynamic_huffman() !void { + fn dynamic_huffman(self: *Self) !void { var bitw = self.bitw; var number_of_literal_codes: u32 = @as(u32, try bitw.walk(5)) + 257; diff --git a/src/utils.zig b/src/utils.zig new file mode 100644 index 0000000..3817997 --- /dev/null +++ b/src/utils.zig @@ -0,0 +1,20 @@ +const std = @import("std"); +const stdout = std.io.getStdOut().writer(); +const stderr = std.io.getStdErr().writer(); + +pub fn print(comptime str: []const u8, params: anytype) void { + stdout.print(str ++ "\n", params) catch {}; +} + +pub fn printf(comptime str: []const u8, params: anytype) void { + stdout.print(str, params) catch {}; +} + +pub fn pErr(comptime str: []const u8, params: anytype) void { + stderr.print(str ++ "\n", params) catch {}; +} + +pub fn exit(comptime str: []const u8, params: anytype, exitCode: u8) void { + pErr(str, params); + std.os.exit(exitCode); +} diff --git a/src/walker.zig b/src/walker.zig new file mode 100644 index 0000000..2eb04b0 --- /dev/null +++ b/src/walker.zig @@ -0,0 +1,153 @@ +const std = @import("std"); +const utils = @import("utils.zig"); + +pub fn BitWalkerUint(comptime T: anytype, comptime reverse: bool) type { + const typeInfo = @typeInfo(T); + + if (typeInfo != .Int) { + @compileError("This needs to be a int"); + } + + if (typeInfo.Int.signedness == .signed) { + @compileError("The integer needs to be unsigned"); + } + + return struct { + value: T, + mask: T, + + // TODO this is probably wrong + in_byte_position: i16, + size: u8, + + const Self = @This(); + + pub fn init(value: T, size: u8) !Self { + if (typeInfo.Int.bits < size) + return error.invlaid_size; + + var start_value: u8 = 0; + if (reverse) { + start_value = size - 1; + } + + var mask: T = 1; + var i: u8 = 0; + while (i < start_value) : (i += 1) { + mask = @shlExact(mask, 1); + } + + return Self{ + .value = value, + .in_byte_position = start_value, + .size = size, + .mask = mask, + }; + } + + pub fn walkBit(self: *Self) ?u1 { + if (self.mask == 0) + return null; + + var result = (self.value & self.mask) == self.mask; + + if (reverse) { + self.in_byte_position -= 1; + if (self.mask == 1) { + self.mask = 0; + } else { + self.mask = @shrExact(self.mask, 1); + } + } else { + self.in_byte_position += 1; + self.mask = @shlExact(self.mask, 1); + if (self.in_byte_position > self.size) { + self.mask = 0; + } else { + self.mask = @shrExact(self.mask, 1); + } + } + + return @boolToInt(result); + } + }; +} + +pub const BitWalker = struct { + const Self = @This(); + + data: *[]u8, + position: usize = 0, + in_byte_position: u3 = 0, + direction: bool = false, + + pub fn init(data: *[]u8, direction: bool) Self { + return Self{ + .data = data, + .direction = direction, + }; + } + + pub fn bitWalk(self: *Self) !u1 { + return @intCast(u1, try self.walk(1)); + } + + // TODO direction + pub fn walk(self: *Self, bits: u3) !u8 { + if (bits > 8 or bits == 0) return error.invalid_bit_number; + + var byte = self.data.ptr[self.position]; + + // jumps over bytes + if (self.in_byte_position + @as(u4, bits) > 8) { + // Generate a mast that covers the last part of the old byte + var old_mask: u8 = 0; + var i: usize = 0; + while (i < 8 - @as(u4, self.in_byte_position)) : (i += 1) { + old_mask = @shlExact(old_mask, 1) + 1; + } + old_mask = @shlExact(old_mask, self.in_byte_position); + + var next_byte = self.data.ptr[self.position + 1]; + var new_byte_pos: u3 = @intCast(u3, @as(u4, bits) - (8 - @as(u4, self.in_byte_position))); + + var new_mask: u8 = 0; + var j: usize = 0; + while (j < new_byte_pos) : (j += 1) { + new_mask = @shlExact(new_mask, 1) + 1; + } + + var result = @shrExact(byte & old_mask, self.in_byte_position) + @shlExact(next_byte & new_mask, @intCast(u3, 8 - @as(u4, self.in_byte_position))); + + //print("mask: {b}, new_mask: {b}", .{ old_mask, new_mask }); + //print("here {b} {b}", .{ byte, old_mask }); + //print("here_new {b} {b}", .{ next_byte, new_mask }); + //print("result {}", .{result}); + + self.position += 1; + self.in_byte_position = new_byte_pos; + + return result; + } + + // Generate a mast that covers the last part of the old byte + var old_mask: u8 = 0; + var i: usize = 0; + while (i < bits) : (i += 1) { + old_mask = @shlExact(old_mask, 1) + 1; + } + old_mask = @shlExact(old_mask, self.in_byte_position); + + const result = @shrExact(byte & old_mask, self.in_byte_position); + + const sum = @intCast(u4, self.in_byte_position) + @intCast(u4, bits); + if (sum == 8) { + self.position += 1; + self.in_byte_position = 0; + } else { + self.in_byte_position += bits; + } + + return result; + } +};