use std::str::FromStr; use byteorder::{ReadBytesExt, LE}; use super::{Compression, ReadExt, Version}; #[derive(Debug)] pub struct Footer { pub encryption_uuid: Option, pub encrypted: bool, pub magic: u32, pub version: Version, pub index_offset: u64, pub index_size: u64, pub hash: [u8; 20], pub frozen: bool, pub compression: Vec, } impl Footer { pub fn new(reader: &mut R, version: Version) -> Result { let footer = Self { encryption_uuid: match version >= Version::EncryptionKeyGuid { true => Some(reader.read_u128::()?), false => None, }, encrypted: version >= Version::IndexEncryption && reader.read_bool()?, magic: reader.read_u32::()?, version: Version::from_repr(reader.read_u32::()?).unwrap_or(version), index_offset: reader.read_u64::()?, index_size: reader.read_u64::()?, hash: reader.read_guid()?, frozen: version == Version::FrozenIndex && reader.read_bool()?, compression: { let mut compression = Vec::with_capacity(match version { ver if ver < Version::FNameBasedCompression => 0, Version::FNameBasedCompression => 4, _ => 5, }); for _ in 0..compression.capacity() { compression.push( Compression::from_str( &reader .read_len(32)? .iter() // filter out whitespace and convert to char .filter_map(|&ch| (ch != 0).then_some(ch as char)) .collect::(), ) .unwrap_or_default(), ) } compression }, }; if super::MAGIC != footer.magic { return Err(super::Error::Magic(footer.magic)); } if version != footer.version { return Err(super::Error::Version { used: version, version: footer.version, }); } Ok(footer) } }