Restructure footer and pak reading to make debugging custom serialization easier

This commit is contained in:
Truman Kilen 2023-09-17 16:57:21 -05:00
parent a749449f8c
commit ff3c9b265b
3 changed files with 79 additions and 69 deletions

View file

@ -1,4 +1,4 @@
use super::{ext::ReadExt, Compression, Version, VersionMajor}; use super::{ext::BoolExt, ext::ReadExt, Compression, Version, VersionMajor};
use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::io; use std::io;
@ -88,7 +88,7 @@ impl Entry {
reader: &mut R, reader: &mut R,
version: super::Version, version: super::Version,
) -> Result<Self, super::Error> { ) -> Result<Self, super::Error> {
// since i need the compression flags, i have to store these as variables which is mildly annoying let ver = version.version_major();
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>()?;
@ -100,32 +100,26 @@ impl Entry {
0 => None, 0 => None,
n => Some(n - 1), n => Some(n - 1),
}; };
let timestamp = (ver == VersionMajor::Initial).then_try(|| reader.read_u64::<LE>())?;
let hash = Some(reader.read_guid()?);
let blocks = (ver >= VersionMajor::CompressionEncryption && compression.is_some())
.then_try(|| reader.read_array(Block::read))?;
let flags = (ver >= VersionMajor::CompressionEncryption)
.then_try(|| reader.read_u8())?
.unwrap_or(0);
let compression_block_size = (ver >= VersionMajor::CompressionEncryption)
.then_try(|| reader.read_u32::<LE>())?
.unwrap_or(0);
Ok(Self { Ok(Self {
offset, offset,
compressed, compressed,
uncompressed, uncompressed,
compression, compression,
timestamp: match version.version_major() == VersionMajor::Initial { timestamp,
true => Some(reader.read_u64::<LE>()?), hash,
false => None, blocks,
}, flags,
hash: Some(reader.read_guid()?), compression_block_size,
blocks: match version.version_major() >= VersionMajor::CompressionEncryption
&& compression.is_some()
{
true => Some(reader.read_array(Block::read)?),
false => None,
},
flags: match version.version_major() >= VersionMajor::CompressionEncryption {
true => reader.read_u8()?,
false => 0,
},
compression_block_size: match version.version_major()
>= VersionMajor::CompressionEncryption
{
true => reader.read_u32::<LE>()?,
false => 0,
},
}) })
} }

View file

@ -1,5 +1,15 @@
use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use byteorder::{ReadBytesExt, WriteBytesExt, LE};
pub trait BoolExt<T, E, F: FnOnce() -> Result<T, E>> {
fn then_try(&self, f: F) -> Result<Option<T>, E>;
}
impl<T, E, F: FnOnce() -> Result<T, E>> BoolExt<T, E, F> for bool {
fn then_try(&self, f: F) -> Result<Option<T>, E> {
self.then(f).transpose()
}
}
pub trait ReadExt { pub trait ReadExt {
fn read_bool(&mut self) -> Result<bool, super::Error>; fn read_bool(&mut self) -> Result<bool, super::Error>;
fn read_guid(&mut self) -> Result<[u8; 20], super::Error>; fn read_guid(&mut self) -> Result<[u8; 20], super::Error>;

View file

@ -1,4 +1,4 @@
use crate::ext::WriteExt; use crate::ext::{BoolExt, WriteExt};
use super::{ext::ReadExt, Compression, Version, VersionMajor}; use super::{ext::ReadExt, Compression, Version, VersionMajor};
use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use byteorder::{ReadBytesExt, WriteBytesExt, LE};
@ -20,58 +20,64 @@ pub struct Footer {
impl Footer { impl Footer {
pub fn read<R: std::io::Read>(reader: &mut R, version: Version) -> Result<Self, super::Error> { pub fn read<R: std::io::Read>(reader: &mut R, version: Version) -> Result<Self, super::Error> {
let footer = Self { let encryption_uuid = (version.version_major() >= VersionMajor::EncryptionKeyGuid)
encryption_uuid: match version.version_major() >= VersionMajor::EncryptionKeyGuid { .then_try(|| reader.read_u128::<LE>())?;
true => Some(reader.read_u128::<LE>()?), let encrypted =
false => None, version.version_major() >= VersionMajor::IndexEncryption && reader.read_bool()?;
}, let magic = reader.read_u32::<LE>()?;
encrypted: version.version_major() >= VersionMajor::IndexEncryption let version_major =
&& reader.read_bool()?, VersionMajor::from_repr(reader.read_u32::<LE>()?).unwrap_or(version.version_major());
magic: reader.read_u32::<LE>()?, let index_offset = reader.read_u64::<LE>()?;
version, let index_size = reader.read_u64::<LE>()?;
version_major: VersionMajor::from_repr(reader.read_u32::<LE>()?) let hash = reader.read_guid()?;
.unwrap_or(version.version_major()), let frozen = version.version_major() == VersionMajor::FrozenIndex && reader.read_bool()?;
index_offset: reader.read_u64::<LE>()?, let compression = {
index_size: reader.read_u64::<LE>()?, let mut compression = Vec::with_capacity(match version {
hash: reader.read_guid()?, ver if ver < Version::V8A => 0,
frozen: version.version_major() == VersionMajor::FrozenIndex && reader.read_bool()?, ver if ver < Version::V8B => 4,
compression: { _ => 5,
let mut compression = Vec::with_capacity(match version { });
ver if ver < Version::V8A => 0, for _ in 0..compression.capacity() {
ver if ver < Version::V8B => 4, compression.push(
_ => 5, Compression::from_str(
}); &reader
for _ in 0..compression.capacity() { .read_len(32)?
compression.push( .iter()
Compression::from_str( // filter out whitespace and convert to char
&reader .filter_map(|&ch| (ch != 0).then_some(ch as char))
.read_len(32)? .collect::<String>(),
.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(),
if version < Version::V8A { )
compression.push(Compression::Zlib); }
compression.push(Compression::Gzip); if version < Version::V8A {
compression.push(Compression::Oodle); compression.push(Compression::Zlib);
} compression.push(Compression::Gzip);
compression compression.push(Compression::Oodle);
}, }
compression
}; };
if super::MAGIC != footer.magic { if super::MAGIC != magic {
return Err(super::Error::Magic(footer.magic)); return Err(super::Error::Magic(magic));
} }
if version.version_major() != footer.version_major { if version.version_major() != version_major {
return Err(super::Error::Version { return Err(super::Error::Version {
used: version.version_major(), used: version.version_major(),
version: footer.version_major, version: version_major,
}); });
} }
Ok(footer) Ok(Self {
encryption_uuid,
encrypted,
magic,
version,
version_major,
index_offset,
index_size,
hash,
frozen,
compression,
})
} }
pub fn write<W: std::io::Write>(&self, writer: &mut W) -> Result<(), super::Error> { pub fn write<W: std::io::Write>(&self, writer: &mut W) -> Result<(), super::Error> {