eager evaluation was the first problem

This commit is contained in:
spuds 2023-01-07 21:10:11 +00:00
parent 39ea548d57
commit 778b87570a
No known key found for this signature in database
GPG key ID: 0B6CA6068E827C8F
8 changed files with 60 additions and 70 deletions

View file

@ -1,18 +1,8 @@
fn main() -> Result<(), un_pak::Error> { fn main() -> Result<(), un_pak::Error> {
let path = std::env::args().nth(1).unwrap_or_default(); let pak = un_pak::Pak::new(
for version in un_pak::Version::iter() { un_pak::Version::CompressionEncryption,
print!("{version} - "); std::io::Cursor::new(include_bytes!("rando_p.pak")),
match un_pak::Pak::new( )?;
version, print!("{:#?}", pak);
std::io::BufReader::new(std::fs::OpenOptions::new().read(true).open(&path)?),
) {
Ok(pak) => {
print!("{:#?}", pak);
println!("parsed successfully!");
}
Err(e) => println!("{e}"),
}
}
std::thread::sleep_ms(10000);
Ok(()) Ok(())
} }

View file

@ -17,7 +17,7 @@ pub struct Entry {
impl Entry { impl Entry {
pub fn new<R: std::io::Read>( pub fn new<R: std::io::Read>(
reader: &mut R, reader: &mut R,
version: &super::Version, version: super::Version,
) -> Result<Self, super::Error> { ) -> Result<Self, super::Error> {
let name = reader.read_string()?; let name = reader.read_string()?;
let offset = reader.read_u64::<LE>()?; let offset = reader.read_u64::<LE>()?;
@ -35,9 +35,9 @@ impl Entry {
compressed, compressed,
uncompressed, uncompressed,
compression_method, compression_method,
timestamp: (version == &Version::Initial).then_some(reader.read_u64::<LE>()?), timestamp: (version == Version::Initial).then_some(reader.read_u64::<LE>()?),
hash: reader.read_guid()?, hash: reader.read_guid()?,
compression_blocks: (version >= &Version::CompressionEncryption compression_blocks: (version >= Version::CompressionEncryption
&& compression_method != Compression::None) && compression_method != Compression::None)
.then_some(reader.read_array(Block::new)?), .then_some(reader.read_array(Block::new)?),
}) })

View file

@ -1,11 +1,9 @@
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error("illegal file magic of {0}")] #[error("found magic of {0:#x} instead of {:#x}", super::MAGIC)]
WrongMagic(u32), WrongMagic(u32),
#[error("used version {0} but pak is version {1}")] #[error("used version {0} but pak is version {1}")]
WrongVersion(super::Version, super::Version), WrongVersion(super::Version, super::Version),
#[error("couldn't convert {0} to boolean")]
BoolConv(u8),
#[error("io error: {0}")] #[error("io error: {0}")]
IoError(#[from] std::io::Error), IoError(#[from] std::io::Error),
#[error("enum conversion: {0}")] #[error("enum conversion: {0}")]
@ -14,6 +12,8 @@ pub enum Error {
Utf8Conv(#[from] std::string::FromUtf8Error), Utf8Conv(#[from] std::string::FromUtf8Error),
#[error("utf16 conversion: {0}")] #[error("utf16 conversion: {0}")]
Utf16Conv(#[from] std::string::FromUtf16Error), Utf16Conv(#[from] std::string::FromUtf16Error),
#[error("got {0}, which is not a boolean")]
BoolConv(u8),
#[error("{0}")] #[error("{0}")]
Other(String), Other(String),
} }

View file

@ -39,7 +39,6 @@ impl<R: std::io::Read> ReadExt for R {
fn read_string(&mut self) -> Result<String, crate::Error> { fn read_string(&mut self) -> Result<String, crate::Error> {
Ok(match self.read_i32::<LE>()? { Ok(match self.read_i32::<LE>()? {
size if size.is_positive() => String::from_utf8(self.read_len(size as usize)?)?,
size if size.is_negative() => { size if size.is_negative() => {
let mut buf = Vec::with_capacity(-size as usize); let mut buf = Vec::with_capacity(-size as usize);
for _ in 0..buf.capacity() { for _ in 0..buf.capacity() {
@ -47,12 +46,12 @@ impl<R: std::io::Read> ReadExt for R {
} }
String::from_utf16(&buf)? String::from_utf16(&buf)?
} }
_ => String::new(), size => String::from_utf8(self.read_len(size as usize)?)?,
}) })
} }
fn read_len(&mut self, len: usize) -> Result<Vec<u8>, super::Error> { fn read_len(&mut self, len: usize) -> Result<Vec<u8>, super::Error> {
let mut buf = Vec::with_capacity(len); let mut buf = vec![0; len];
self.read_exact(&mut buf)?; self.read_exact(&mut buf)?;
Ok(buf) Ok(buf)
} }

View file

@ -18,44 +18,55 @@ pub struct Footer {
} }
impl Footer { impl Footer {
pub fn new<R: std::io::Read>(reader: &mut R, version: &Version) -> Result<Self, super::Error> { pub fn new<R: std::io::Read>(reader: &mut R, version: Version) -> Result<Self, super::Error> {
let footer = Footer { let footer = Self {
encryption_uuid: (version >= &Version::EncryptionKeyGuid) encryption_uuid: match version >= Version::EncryptionKeyGuid {
.then_some(reader.read_u128::<LE>()?), true => Some(reader.read_u128::<LE>()?),
encrypted: (version >= &Version::CompressionEncryption).then_some(reader.read_bool()?), false => None,
},
encrypted: match version >= Version::IndexEncryption {
true => Some(reader.read_bool()?),
false => None,
},
magic: reader.read_u32::<LE>()?, magic: reader.read_u32::<LE>()?,
version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or_default(), version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or(version),
offset: reader.read_u64::<LE>()?, offset: reader.read_u64::<LE>()?,
size: reader.read_u64::<LE>()?, size: reader.read_u64::<LE>()?,
hash: reader.read_guid()?, hash: reader.read_guid()?,
frozen: (version == &Version::FrozenIndex).then_some(reader.read_bool()?), frozen: match version == Version::FrozenIndex {
compression: (version >= &Version::FNameBasedCompression).then_some({ true => Some(reader.read_bool()?),
let mut compression = false => None,
Vec::with_capacity(match version == &Version::FNameBasedCompression { },
true => 4, compression: match version >= Version::FNameBasedCompression {
false => 5, true => {
}); let mut compression =
for _ in 0..compression.capacity() { Vec::with_capacity(match version == Version::FNameBasedCompression {
compression.push( true => 4,
Compression::from_str( false => 5,
&reader });
.read_len(32)? for _ in 0..compression.capacity() {
.iter() compression.push(
// filter out whitespace and convert to char Compression::from_str(
.filter_map(|&ch| (ch != 0).then_some(ch as char)) &reader
.collect::<String>(), .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(),
) )
.unwrap_or_default(), }
) Some(compression)
} }
compression false => None,
}), },
}; };
if super::MAGIC != footer.magic { if super::MAGIC != footer.magic {
return Err(super::Error::WrongMagic(footer.magic)); return Err(super::Error::WrongMagic(footer.magic));
} }
if version != &footer.version { if version != footer.version {
return Err(super::Error::WrongVersion(*version, footer.version)); return Err(super::Error::WrongVersion(version, footer.version));
} }
Ok(footer) Ok(footer)
} }

View file

@ -7,8 +7,8 @@ pub enum Index {
} }
impl Index { impl Index {
pub fn new<R: std::io::Read>(reader: &mut R, version: &Version) -> Result<Self, super::Error> { pub fn new<R: std::io::Read>(reader: &mut R, version: Version) -> Result<Self, super::Error> {
Ok(match version < &Version::PathHashIndex { Ok(match version < Version::PathHashIndex {
true => Index::WithoutPathHash(IndexV1::new(reader, version)?), true => Index::WithoutPathHash(IndexV1::new(reader, version)?),
false => Index::WithPathHash, false => Index::WithPathHash,
}) })
@ -24,7 +24,7 @@ pub struct IndexV1 {
impl IndexV1 { impl IndexV1 {
pub fn new<R: std::io::Read>( pub fn new<R: std::io::Read>(
reader: &mut R, reader: &mut R,
version: &super::Version, version: super::Version,
) -> Result<Self, super::Error> { ) -> Result<Self, super::Error> {
Ok(Self { Ok(Self {
mount_point: reader.read_string()?, mount_point: reader.read_string()?,

View file

@ -12,19 +12,10 @@ pub const MAGIC: u32 = 0x5A6F12E1;
#[repr(u32)] #[repr(u32)]
#[derive( #[derive(
Default, Clone, Copy, PartialEq, Eq, PartialOrd, Debug, strum::Display, strum::FromRepr, strum::EnumIter,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Debug,
strum::Display,
strum::FromRepr,
strum::EnumIter,
)] )]
pub enum Version { pub enum Version {
Unknown, // unknown (mostly just for padding :p) Unknown, // unknown (mostly just for padding)
Initial, // initial specification Initial, // initial specification
NoTimestamps, // timestamps removed NoTimestamps, // timestamps removed
CompressionEncryption, // compression and encryption support CompressionEncryption, // compression and encryption support
@ -34,8 +25,7 @@ pub enum Version {
EncryptionKeyGuid, // include key GUID EncryptionKeyGuid, // include key GUID
FNameBasedCompression, // compression names included FNameBasedCompression, // compression names included
FrozenIndex, // frozen index byte included FrozenIndex, // frozen index byte included
#[default] PathHashIndex, // more compression methods
PathHashIndex, // more compression methods
} }
// strum shouldn't need to be installed by users // strum shouldn't need to be installed by users

View file

@ -15,9 +15,9 @@ impl Pak {
mut reader: R, mut reader: R,
) -> Result<Self, super::Error> { ) -> Result<Self, super::Error> {
reader.seek(io::SeekFrom::End(-footer_size(&version)))?; reader.seek(io::SeekFrom::End(-footer_size(&version)))?;
let footer = super::Footer::new(&mut reader, &version)?; let footer = super::Footer::new(&mut reader, version)?;
reader.seek(io::SeekFrom::Start(footer.offset))?; reader.seek(io::SeekFrom::Start(footer.offset))?;
let index = super::Index::new(&mut reader, &version)?; let index = super::Index::new(&mut reader, version)?;
Ok(Self { Ok(Self {
version, version,
footer, footer,