central_directory_protocol = {
let base_protocol = combine([
{ protocol: exact(string.encode("PK\x01\x02")) },
{ name: "version_made_by", protocol: bytes.uint16le },
{ name: "version_required", protocol: bytes.uint16le },
{
name: "flags_1",
protocol: flags([
"encrypted",
"compression_1",
"compression_2",
"crc32_at_the_end",
null,
"is_compressed_patched_data",
"strong_encryption",
null
])
},
{
name: "flags_2",
protocol: flags([null, null, null, "use_utf8", null, null, null, null])
},
{
name: "compression",
protocol: switch_protocol(
bytes.uint16le,
new Map([
[0, "uncompressed"],
[8, "deflate"]
])
)
},
{ name: "modification_time", protocol: bytes.uint16le },
{ name: "modification_date", protocol: bytes.uint16le },
{ name: "crc_32", protocol: bytes.uint32le },
{ name: "compressed_size", protocol: bytes.uint32le },
{ name: "uncompressed_size", protocol: bytes.uint32le },
{ name: "name_length", protocol: bytes.uint16le },
{ name: "extra_field_length", protocol: bytes.uint16le },
{ name: "comment_length", protocol: bytes.uint16le },
{ name: "start_disk_number", protocol: bytes.uint16le },
{ name: "internal_attributes", protocol: bytes.uint16le },
{ name: "external_attributes", protocol: bytes.uint32le },
{ name: "offset", protocol: bytes.uint32le }
]);
return just_repeat({
decode: (buffer) => {
let [
{
name_length,
compression,
flags_1,
flags_2,
extra_field_length,
comment_length,
modification_time,
modification_date,
...data
},
base_offset
] = base_protocol.decode(buffer);
let [{ file_name, extra_field, comment }, rest_offset] = combine([
{
name: "file_name",
protocol: with_exact_length(name_length, string)
},
{
name: "extra_field",
protocol: with_exact_length(
extra_field_length,
just_repeat(
combine([
{
name: "header",
protocol: bytes.uint16le
},
{
name: "value",
protocol: with_length(bytes.uint16le, uint8array)
}
])
)
)
},
{
name: "comment",
protocol: with_exact_length(comment_length, string)
}
]).decode(buffer.subarray(base_offset));
return [
{
...data,
compression: compression,
last_modified: parseDosDateTime(modification_date, modification_time),
file_name_length: name_length,
file_name: file_name,
extra_field_length: extra_field_length,
extra_field: extra_field,
comment_length: comment_length,
comment: comment,
flags: new Set([...flags_1, ...flags_2])
},
base_offset + rest_offset
];
}
});
}