use crate::{fields, format::*};
use nom::{
bytes::streaming::tag,
combinator::opt,
number::streaming::{le_u16, le_u32, le_u64},
sequence::preceded,
};
#[derive(Debug)]
pub struct LocalFileHeaderRecord {
pub reader_version: Version,
pub flags: u16,
pub method: u16,
pub modified: MsdosTimestamp,
pub crc32: u32,
pub compressed_size: u32,
pub uncompressed_size: u32,
pub name: ZipString,
pub extra: ZipBytes,
}
impl LocalFileHeaderRecord {
pub const SIGNATURE: &'static str = "PK\x03\x04";
pub fn parse(i: &[u8]) -> parse::Result<'_, Self> {
preceded(
tag(Self::SIGNATURE),
fields!({
reader_version: Version::parse,
flags: le_u16,
method: le_u16,
modified: MsdosTimestamp::parse,
crc32: le_u32,
compressed_size: le_u32,
uncompressed_size: le_u32,
name_len: le_u16,
extra_len: le_u16,
} chain fields!({
name: ZipString::parser(name_len),
extra: ZipBytes::parser(extra_len),
} map Self {
reader_version,
flags,
method,
modified,
crc32,
compressed_size,
uncompressed_size,
name,
extra,
})),
)(i)
}
pub fn has_data_descriptor(&self) -> bool {
self.flags & 0b1000 != 0
}
}
#[derive(Debug)]
pub struct DataDescriptorRecord {
pub crc32: u32,
pub compressed_size: u64,
pub uncompressed_size: u64,
}
impl DataDescriptorRecord {
const SIGNATURE: &'static str = "PK\x07\x08";
pub fn parse(i: &[u8], is_zip64: bool) -> parse::Result<'_, Self> {
if is_zip64 {
preceded(
opt(tag(Self::SIGNATURE)),
fields!(Self {
crc32: le_u32,
compressed_size: le_u64,
uncompressed_size: le_u64,
}),
)(i)
} else {
preceded(
opt(tag(Self::SIGNATURE)),
fields!({
crc32: le_u32,
compressed_size: le_u32,
uncompressed_size: le_u32,
} map Self {
crc32,
compressed_size: compressed_size as u64,
uncompressed_size: uncompressed_size as u64,
}),
)(i)
}
}
}