reconfigure for entry reading and api

This commit is contained in:
spuds 2023-01-13 12:38:30 +00:00
parent c440ca6707
commit 7d1fd167e1
No known key found for this signature in database
GPG key ID: 0B6CA6068E827C8F
3 changed files with 55 additions and 30 deletions

View file

@ -34,6 +34,7 @@ pub struct Entry {
impl Entry { impl Entry {
pub fn new<R: io::Read>(reader: &mut R, version: super::Version) -> Result<Self, super::Error> { pub fn new<R: io::Read>(reader: &mut R, version: super::Version) -> Result<Self, super::Error> {
// since i need the compression flags, i have to store these as variables which is mildly annoying
let offset = reader.read_u64::<LE>()?; let offset = reader.read_u64::<LE>()?;
let compressed = reader.read_u64::<LE>()?; let compressed = reader.read_u64::<LE>()?;
let uncompressed = reader.read_u64::<LE>()?; let uncompressed = reader.read_u64::<LE>()?;
@ -66,9 +67,10 @@ impl Entry {
} }
pub fn read<R: io::Read + io::Seek>( pub fn read<R: io::Read + io::Seek>(
self, &self,
reader: &mut R, reader: &mut R,
version: super::Version, version: super::Version,
key: Option<&aes::Aes256Dec>,
) -> Result<Vec<u8>, super::Error> { ) -> Result<Vec<u8>, super::Error> {
let buf = io::BufWriter::new(Vec::new()); let buf = io::BufWriter::new(Vec::new());
todo!("read the stuff"); todo!("read the stuff");

View file

@ -10,8 +10,8 @@ pub struct Footer {
pub encrypted: bool, pub encrypted: bool,
pub magic: u32, pub magic: u32,
pub version: Version, pub version: Version,
pub offset: u64, pub index_offset: u64,
pub size: u64, pub index_size: u64,
pub hash: [u8; 20], pub hash: [u8; 20],
pub frozen: bool, pub frozen: bool,
pub compression: Vec<Compression>, pub compression: Vec<Compression>,
@ -27,8 +27,8 @@ impl Footer {
encrypted: version >= Version::IndexEncryption && reader.read_bool()?, encrypted: version >= Version::IndexEncryption && reader.read_bool()?,
magic: reader.read_u32::<LE>()?, magic: reader.read_u32::<LE>()?,
version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or(version), version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or(version),
offset: reader.read_u64::<LE>()?, index_offset: reader.read_u64::<LE>()?,
size: reader.read_u64::<LE>()?, index_size: reader.read_u64::<LE>()?,
hash: reader.read_guid()?, hash: reader.read_guid()?,
frozen: version == Version::FrozenIndex && reader.read_bool()?, frozen: version == Version::FrozenIndex && reader.read_bool()?,
compression: { compression: {

View file

@ -1,53 +1,76 @@
use std::io; use std::io;
use super::ReadExt;
use aes::cipher::{BlockDecrypt, KeyInit};
use byteorder::{ReadBytesExt, LE};
use super::Version; use super::Version;
#[derive(Debug)] #[derive(Debug)]
pub struct Pak { pub struct Pak<R: io::Read + io::Seek> {
pub version: Version, version: Version,
pub footer: super::Footer, mount_point: String,
pub mount_point: String, key: Option<aes::Aes256Dec>,
pub entries: hashbrown::HashMap<String, super::Entry>, entries: hashbrown::HashMap<String, super::Entry>,
reader: R,
} }
impl Pak { impl<R: io::Read + io::Seek> Pak<R> {
pub fn new<R: io::Read + io::Seek>( pub fn new(
mut reader: R, mut reader: R,
version: super::Version, version: super::Version,
key: Option<&[u8]>, key_hash: Option<&[u8]>,
) -> Result<Self, super::Error> { ) -> Result<Self, super::Error> {
use super::ReadExt;
use byteorder::{ReadBytesExt, LE};
// read footer to get index, encryption & compression info
reader.seek(io::SeekFrom::End(-version.size()))?; reader.seek(io::SeekFrom::End(-version.size()))?;
let footer = super::Footer::new(&mut reader, version)?; let footer = super::Footer::new(&mut reader, version)?;
reader.seek(io::SeekFrom::Start(footer.offset))?; // read index to get all the entry info
let mut index = reader.read_len(footer.size as usize)?; reader.seek(io::SeekFrom::Start(footer.index_offset))?;
if let Some(key) = key { let mut index = reader.read_len(footer.index_size as usize)?;
match aes::Aes256Dec::new_from_slice(key) { let mut key = None;
Ok(key) => { // decrypt index if needed
for chunk in index.chunks_mut(16) { if footer.encrypted {
key.decrypt_block(aes::Block::from_mut_slice(chunk)) 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 mut index = io::Cursor::new(index);
let len = reader.read_u32::<LE>()? as usize; let mount_point = index.read_string()?;
let len = index.read_u32::<LE>()? as usize;
let mut entries = hashbrown::HashMap::with_capacity(len); let mut entries = hashbrown::HashMap::with_capacity(len);
for _ in 0..len { for _ in 0..len {
entries.insert( entries.insert(
reader.read_string()?, index.read_string()?,
super::Entry::new(&mut reader, version)?, super::Entry::new(&mut index, version)?,
); );
} }
Ok(Self { Ok(Self {
version, version,
footer,
mount_point, mount_point,
key,
entries, 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<Result<Vec<u8>, super::Error>> {
self.entries
.get(path)
.map(|entry| entry.read(&mut self.reader, self.version, self.key.as_ref()))
}
} }