2023-01-03 14:20:35 +00:00
|
|
|
use std::str::FromStr;
|
2023-01-03 10:33:42 +00:00
|
|
|
|
|
|
|
use byteorder::{ReadBytesExt, LE};
|
|
|
|
|
|
|
|
use super::{Compression, ReadExt, Version};
|
|
|
|
|
2023-01-06 19:54:48 +00:00
|
|
|
#[derive(Debug)]
|
2023-01-03 10:33:42 +00:00
|
|
|
pub struct Footer {
|
2023-01-06 19:54:48 +00:00
|
|
|
pub encryption_uuid: Option<u128>,
|
2023-01-10 22:29:20 +00:00
|
|
|
pub encrypted: bool,
|
2023-01-03 10:33:42 +00:00
|
|
|
pub magic: u32,
|
|
|
|
pub version: Version,
|
|
|
|
pub offset: u64,
|
|
|
|
pub size: u64,
|
|
|
|
pub hash: [u8; 20],
|
2023-01-10 22:29:20 +00:00
|
|
|
pub frozen: bool,
|
2023-01-03 10:33:42 +00:00
|
|
|
pub compression: Option<Vec<Compression>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Footer {
|
2023-01-07 21:10:11 +00:00
|
|
|
pub fn new<R: std::io::Read>(reader: &mut R, version: Version) -> Result<Self, super::Error> {
|
|
|
|
let footer = Self {
|
|
|
|
encryption_uuid: match version >= Version::EncryptionKeyGuid {
|
|
|
|
true => Some(reader.read_u128::<LE>()?),
|
|
|
|
false => None,
|
|
|
|
},
|
2023-01-10 22:29:20 +00:00
|
|
|
encrypted: version >= Version::IndexEncryption && reader.read_bool()?,
|
2023-01-03 10:33:42 +00:00
|
|
|
magic: reader.read_u32::<LE>()?,
|
2023-01-07 21:10:11 +00:00
|
|
|
version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or(version),
|
2023-01-03 10:33:42 +00:00
|
|
|
offset: reader.read_u64::<LE>()?,
|
|
|
|
size: reader.read_u64::<LE>()?,
|
|
|
|
hash: reader.read_guid()?,
|
2023-01-10 22:29:20 +00:00
|
|
|
frozen: version == Version::FrozenIndex && reader.read_bool()?,
|
2023-01-07 21:10:11 +00:00
|
|
|
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::<String>(),
|
|
|
|
)
|
|
|
|
.unwrap_or_default(),
|
2023-01-03 14:20:35 +00:00
|
|
|
)
|
2023-01-07 21:10:11 +00:00
|
|
|
}
|
|
|
|
Some(compression)
|
2023-01-03 10:33:42 +00:00
|
|
|
}
|
2023-01-07 21:10:11 +00:00
|
|
|
false => None,
|
|
|
|
},
|
2023-01-03 10:33:42 +00:00
|
|
|
};
|
|
|
|
if super::MAGIC != footer.magic {
|
2023-01-06 19:54:48 +00:00
|
|
|
return Err(super::Error::WrongMagic(footer.magic));
|
2023-01-03 10:33:42 +00:00
|
|
|
}
|
2023-01-07 21:10:11 +00:00
|
|
|
if version != footer.version {
|
|
|
|
return Err(super::Error::WrongVersion(version, footer.version));
|
2023-01-03 10:33:42 +00:00
|
|
|
}
|
|
|
|
Ok(footer)
|
|
|
|
}
|
|
|
|
}
|