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 offset: u64, pub size: u64, pub hash: [u8; 20], pub frozen: bool, pub compression: Option>, } 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), offset: reader.read_u64::()?, size: reader.read_u64::()?, hash: reader.read_guid()?, frozen: version == Version::FrozenIndex && reader.read_bool()?, compression: match version >= Version::FNameBasedCompression { true => { let mut compression = Vec::with_capacity(match version == Version::FNameBasedCompression { true => 4, false => 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(), ) } Some(compression) } false => None, }, }; if super::MAGIC != footer.magic { return Err(super::Error::WrongMagic(footer.magic)); } if version != footer.version { return Err(super::Error::WrongVersion(version, footer.version)); } Ok(footer) } }