diff --git a/src/entry.rs b/src/entry.rs index 52895f2..189b054 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -34,6 +34,7 @@ pub struct Entry { impl Entry { pub fn new(reader: &mut R, version: super::Version) -> Result { + // since i need the compression flags, i have to store these as variables which is mildly annoying let offset = reader.read_u64::()?; let compressed = reader.read_u64::()?; let uncompressed = reader.read_u64::()?; @@ -66,9 +67,10 @@ impl Entry { } pub fn read( - self, + &self, reader: &mut R, version: super::Version, + key: Option<&aes::Aes256Dec>, ) -> Result, super::Error> { let buf = io::BufWriter::new(Vec::new()); todo!("read the stuff"); diff --git a/src/footer.rs b/src/footer.rs index 747fd84..3798cd5 100644 --- a/src/footer.rs +++ b/src/footer.rs @@ -10,8 +10,8 @@ pub struct Footer { pub encrypted: bool, pub magic: u32, pub version: Version, - pub offset: u64, - pub size: u64, + pub index_offset: u64, + pub index_size: u64, pub hash: [u8; 20], pub frozen: bool, pub compression: Vec, @@ -27,8 +27,8 @@ impl Footer { 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::()?, + index_offset: reader.read_u64::()?, + index_size: reader.read_u64::()?, hash: reader.read_guid()?, frozen: version == Version::FrozenIndex && reader.read_bool()?, compression: { diff --git a/src/pak.rs b/src/pak.rs index 253c128..ab766ae 100644 --- a/src/pak.rs +++ b/src/pak.rs @@ -1,53 +1,76 @@ use std::io; -use super::ReadExt; -use aes::cipher::{BlockDecrypt, KeyInit}; -use byteorder::{ReadBytesExt, LE}; - use super::Version; #[derive(Debug)] -pub struct Pak { - pub version: Version, - pub footer: super::Footer, - pub mount_point: String, - pub entries: hashbrown::HashMap, +pub struct Pak { + version: Version, + mount_point: String, + key: Option, + entries: hashbrown::HashMap, + reader: R, } -impl Pak { - pub fn new( +impl Pak { + pub fn new( mut reader: R, version: super::Version, - key: Option<&[u8]>, + key_hash: Option<&[u8]>, ) -> Result { + use super::ReadExt; + use byteorder::{ReadBytesExt, LE}; + // read footer to get index, encryption & compression info reader.seek(io::SeekFrom::End(-version.size()))?; let footer = super::Footer::new(&mut reader, version)?; - reader.seek(io::SeekFrom::Start(footer.offset))?; - let mut index = reader.read_len(footer.size as usize)?; - if let Some(key) = key { - match aes::Aes256Dec::new_from_slice(key) { - Ok(key) => { - for chunk in index.chunks_mut(16) { - key.decrypt_block(aes::Block::from_mut_slice(chunk)) + // read index to get all the entry info + reader.seek(io::SeekFrom::Start(footer.index_offset))?; + let mut index = reader.read_len(footer.index_size as usize)?; + let mut key = None; + // decrypt index if needed + if footer.encrypted { + if let Some(hash) = key_hash { + use aes::cipher::{BlockDecrypt, KeyInit}; + match aes::Aes256Dec::new_from_slice(hash) { + Ok(decrypter) => { + for chunk in index.chunks_mut(16) { + decrypter.decrypt_block(aes::Block::from_mut_slice(chunk)) + } + key = Some(decrypter); } + Err(_) => return Err(super::Error::Aes), } - Err(_) => return Err(super::Error::Aes), } } - let mount_point = reader.read_string()?; - let len = reader.read_u32::()? as usize; + let mut index = io::Cursor::new(index); + let mount_point = index.read_string()?; + let len = index.read_u32::()? as usize; let mut entries = hashbrown::HashMap::with_capacity(len); for _ in 0..len { entries.insert( - reader.read_string()?, - super::Entry::new(&mut reader, version)?, + index.read_string()?, + super::Entry::new(&mut index, version)?, ); } Ok(Self { version, - footer, mount_point, + key, entries, + reader, }) } + + pub fn version(&self) -> super::Version { + self.version + } + + pub fn mount_point(&self) -> &str { + &self.mount_point + } + + pub fn get(&mut self, path: &str) -> Option, super::Error>> { + self.entries + .get(path) + .map(|entry| entry.read(&mut self.reader, self.version, self.key.as_ref())) + } }