fn outputHeader(
h: *Huffman,
freqs: *const [257]u16,
buf: *CodesBuf,
bytes: u16,
eos: bool,
) Writer.Error!?struct {
codes: *const [257]u16,
bits: *const [257]u4,
} {
assert(freqs[256] == 1);
const dyn_codes_bitsize, _ = huffman.build(
freqs,
buf.dyn_codes[0..257],
buf.dyn_bits[0..257],
15,
true,
);
var clen_values: [258]u8 = undefined;
var clen_extra: [258]u8 = undefined;
var clen_freqs: [19]u16 = @splat(0);
const clen_len, const clen_extra_bitsize = buildClen(
&buf.dyn_bits,
&clen_values,
&clen_extra,
&clen_freqs,
);
var clen_codes: [19]u16 = undefined;
var clen_bits: [19]u4 = @splat(0);
const clen_codes_bitsize, _ = huffman.build(
&clen_freqs,
&clen_codes,
&clen_bits,
7,
false,
);
const hclen = clenHlen(clen_freqs);
const dynamic_bitsize = @as(u32, 14) +
(4 + @as(u6, hclen)) * 3 + clen_codes_bitsize + clen_extra_bitsize +
dyn_codes_bitsize;
const fixed_bitsize = n: {
const freq7 = 1; // eos
var freq9: u16 = 0;
for (freqs[144..256]) |f| freq9 += f;
const freq8: u16 = bytes - freq9;
break :n @as(u32, freq7) * 7 + @as(u32, freq8) * 8 + @as(u32, freq9) * 9;
};
const stored_bitsize = n: {
const stored_align_bits = -%(h.bit_writer.buffered_n +% 3);
break :n stored_align_bits + @as(u32, 32) + @as(u32, bytes) * 8;
};
if (stored_bitsize <= @min(dynamic_bitsize, fixed_bitsize)) {
try h.bit_writer.write(BlockHeader.int(.{ .kind = .stored, .final = eos }), 3);
try h.bit_writer.output.rebase(0, 5);
h.bit_writer.byteAlign();
h.bit_writer.output.writeInt(u16, bytes, .little) catch unreachable;
h.bit_writer.output.writeInt(u16, ~bytes, .little) catch unreachable;
return null;
}
if (fixed_bitsize <= dynamic_bitsize) {
try h.bit_writer.write(BlockHeader.int(.{ .final = eos, .kind = .fixed }), 3);
return .{
.codes = token.fixed_lit_codes[0..257],
.bits = token.fixed_lit_bits[0..257],
};
} else {
try h.bit_writer.write(BlockHeader.Dynamic.int(.{
.regular = .{ .final = eos, .kind = .dynamic },
.hlit = 0,
.hdist = 0,
.hclen = hclen,
}), 17);
try h.bit_writer.writeClen(
hclen,
clen_values[0..clen_len],
clen_extra[0..clen_len],
clen_codes,
clen_bits,
);
return .{ .codes = buf.dyn_codes[0..257], .bits = buf.dyn_bits[0..257] };
}
}
Returns null if the block is stored.