mirror of
https://github.com/xavo95/repak.git
synced 2025-01-18 10:54:38 +00:00
Refactor version handling to handle subversions and correctly parse v8a
This commit is contained in:
parent
af3ef60f30
commit
529bdcac4e
5 changed files with 82 additions and 35 deletions
27
src/entry.rs
27
src/entry.rs
|
@ -1,4 +1,4 @@
|
|||
use super::{ext::ReadExt, Compression, Version};
|
||||
use super::{ext::ReadExt, Compression, Version, VersionMajor};
|
||||
use byteorder::{ReadBytesExt, LE};
|
||||
use std::io;
|
||||
|
||||
|
@ -45,8 +45,11 @@ impl Entry {
|
|||
size += 8; // offset
|
||||
size += 8; // compressed
|
||||
size += 8; // uncompressed
|
||||
size += 4; // compression
|
||||
size += match version == Version::Initial {
|
||||
size += match version != Version::V8A {
|
||||
true => 4, // 32 bit compression
|
||||
false => 1, // 8 bit compression
|
||||
};
|
||||
size += match version.version_major() == VersionMajor::Initial {
|
||||
true => 8, // timestamp
|
||||
false => 0,
|
||||
};
|
||||
|
@ -56,7 +59,7 @@ impl Entry {
|
|||
false => 0,
|
||||
};
|
||||
size += 1; // encrypted
|
||||
size += match version >= Version::CompressionEncryption {
|
||||
size += match version.version_major() >= VersionMajor::CompressionEncryption {
|
||||
true => 4, // blocks uncompressed
|
||||
false => 0,
|
||||
};
|
||||
|
@ -68,7 +71,7 @@ impl Entry {
|
|||
let offset = reader.read_u64::<LE>()?;
|
||||
let compressed = reader.read_u64::<LE>()?;
|
||||
let uncompressed = reader.read_u64::<LE>()?;
|
||||
let compression = match reader.read_u32::<LE>()? {
|
||||
let compression = match if version == Version::V8A { reader.read_u8()? as u32 } else { reader.read_u32::<LE>()? } {
|
||||
0x01 | 0x10 | 0x20 => Compression::Zlib,
|
||||
_ => Compression::None,
|
||||
};
|
||||
|
@ -77,19 +80,19 @@ impl Entry {
|
|||
compressed,
|
||||
uncompressed,
|
||||
compression,
|
||||
timestamp: match version == Version::Initial {
|
||||
timestamp: match version.version_major() == VersionMajor::Initial {
|
||||
true => Some(reader.read_u64::<LE>()?),
|
||||
false => None,
|
||||
},
|
||||
hash: Some(reader.read_guid()?),
|
||||
blocks: match version >= Version::CompressionEncryption
|
||||
blocks: match version.version_major() >= VersionMajor::CompressionEncryption
|
||||
&& compression != Compression::None
|
||||
{
|
||||
true => Some(reader.read_array(Block::new)?),
|
||||
false => None,
|
||||
},
|
||||
encrypted: version >= Version::CompressionEncryption && reader.read_bool()?,
|
||||
block_uncompressed: match version >= Version::CompressionEncryption {
|
||||
encrypted: version.version_major() >= VersionMajor::CompressionEncryption && reader.read_bool()?,
|
||||
block_uncompressed: match version.version_major() >= VersionMajor::CompressionEncryption {
|
||||
true => Some(reader.read_u32::<LE>()?),
|
||||
false => None,
|
||||
},
|
||||
|
@ -140,7 +143,7 @@ impl Entry {
|
|||
};
|
||||
|
||||
let offset_base =
|
||||
match version >= super::Version::RelativeChunkOffsets {
|
||||
match version.version_major() >= VersionMajor::RelativeChunkOffsets {
|
||||
true => 0,
|
||||
false => offset,
|
||||
} + Entry::get_serialized_size(version, compression, compression_block_count);
|
||||
|
@ -189,7 +192,7 @@ impl Entry {
|
|||
pub fn read<R: io::Read + io::Seek, W: io::Write>(
|
||||
&self,
|
||||
reader: &mut R,
|
||||
version: super::Version,
|
||||
version: Version,
|
||||
key: Option<&aes::Aes256Dec>,
|
||||
buf: &mut W,
|
||||
) -> Result<(), super::Error> {
|
||||
|
@ -217,7 +220,7 @@ impl Entry {
|
|||
for block in blocks {
|
||||
io::copy(
|
||||
&mut <$decompressor>::new(
|
||||
&data[match version >= Version::RelativeChunkOffsets {
|
||||
&data[match version.version_major() >= VersionMajor::RelativeChunkOffsets {
|
||||
true => {
|
||||
(block.start - (data_offset - self.offset)) as usize
|
||||
..(block.end - (data_offset - self.offset)) as usize
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{ext::ReadExt, Compression, Version};
|
||||
use super::{ext::ReadExt, Compression, Version, VersionMajor};
|
||||
use byteorder::{ReadBytesExt, LE};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub struct Footer {
|
|||
pub encrypted: bool,
|
||||
pub magic: u32,
|
||||
pub version: Version,
|
||||
pub version_major: VersionMajor,
|
||||
pub index_offset: u64,
|
||||
pub index_size: u64,
|
||||
pub hash: [u8; 20],
|
||||
|
@ -18,21 +19,22 @@ pub struct Footer {
|
|||
impl Footer {
|
||||
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 {
|
||||
encryption_uuid: match version.version_major() >= VersionMajor::EncryptionKeyGuid {
|
||||
true => Some(reader.read_u128::<LE>()?),
|
||||
false => None,
|
||||
},
|
||||
encrypted: version >= Version::IndexEncryption && reader.read_bool()?,
|
||||
encrypted: version.version_major() >= VersionMajor::IndexEncryption && reader.read_bool()?,
|
||||
magic: reader.read_u32::<LE>()?,
|
||||
version: Version::from_repr(reader.read_u32::<LE>()?).unwrap_or(version),
|
||||
version,
|
||||
version_major: VersionMajor::from_repr(reader.read_u32::<LE>()?).unwrap_or(version.version_major()),
|
||||
index_offset: reader.read_u64::<LE>()?,
|
||||
index_size: reader.read_u64::<LE>()?,
|
||||
hash: reader.read_guid()?,
|
||||
frozen: version == Version::FrozenIndex && reader.read_bool()?,
|
||||
frozen: version.version_major() == VersionMajor::FrozenIndex && reader.read_bool()?,
|
||||
compression: {
|
||||
let mut compression = Vec::with_capacity(match version {
|
||||
ver if ver < Version::FNameBasedCompression => 0,
|
||||
Version::FNameBasedCompression => 4,
|
||||
ver if ver < Version::V8A => 0,
|
||||
ver if ver < Version::V8B => 4,
|
||||
_ => 5,
|
||||
});
|
||||
for _ in 0..compression.capacity() {
|
||||
|
@ -54,7 +56,7 @@ impl Footer {
|
|||
if super::MAGIC != footer.magic {
|
||||
return Err(super::Error::Magic(footer.magic));
|
||||
}
|
||||
if version != footer.version {
|
||||
if version.version_major() != footer.version_major {
|
||||
return Err(super::Error::Version {
|
||||
used: version,
|
||||
version: footer.version,
|
||||
|
|
56
src/lib.rs
56
src/lib.rs
|
@ -9,12 +9,31 @@ pub use {error::*, pak::*};
|
|||
|
||||
pub const MAGIC: u32 = 0x5A6F12E1;
|
||||
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Debug, strum::Display, strum::FromRepr, strum::EnumIter,
|
||||
)]
|
||||
pub enum Version {
|
||||
V0,
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
V4,
|
||||
V5,
|
||||
V6,
|
||||
V7,
|
||||
V8A,
|
||||
V8B,
|
||||
V9,
|
||||
V10,
|
||||
V11,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Debug, strum::Display, strum::FromRepr, strum::EnumIter,
|
||||
)]
|
||||
|
||||
pub enum Version {
|
||||
/// Version actually written to the pak file
|
||||
pub enum VersionMajor {
|
||||
Unknown, // v0 unknown (mostly just for padding)
|
||||
Initial, // v1 initial specification
|
||||
NoTimestamps, // v2 timestamps removed
|
||||
|
@ -38,24 +57,47 @@ impl Version {
|
|||
pub fn size(self) -> i64 {
|
||||
// (magic + version): u32 + (offset + size): u64 + hash: [u8; 20]
|
||||
let mut size = 4 + 4 + 8 + 8 + 20;
|
||||
if self >= Version::EncryptionKeyGuid {
|
||||
if self.version_major() >= VersionMajor::EncryptionKeyGuid {
|
||||
// encryption uuid: u128
|
||||
size += 16;
|
||||
}
|
||||
if self >= Version::IndexEncryption {
|
||||
if self.version_major() >= VersionMajor::IndexEncryption {
|
||||
// encrypted: bool
|
||||
size += 1;
|
||||
}
|
||||
if self == Version::FrozenIndex {
|
||||
if self.version_major() == VersionMajor::FrozenIndex {
|
||||
// frozen index: bool
|
||||
size += 1;
|
||||
}
|
||||
if self >= Version::FNameBasedCompression {
|
||||
if self >= Version::V8A {
|
||||
// compression names: [[u8; 32]; 5]
|
||||
size += 32 * 5;
|
||||
size += 32 * 4;
|
||||
}
|
||||
if self >= Version::V8B {
|
||||
// compression names: [[u8; 32]; 5]
|
||||
size += 32 * 1;
|
||||
}
|
||||
size
|
||||
}
|
||||
|
||||
/// Losslessly convert full version into major version
|
||||
pub fn version_major(&self) -> VersionMajor {
|
||||
match self {
|
||||
Version::V0 => VersionMajor::Unknown,
|
||||
Version::V1 => VersionMajor::Initial,
|
||||
Version::V2 => VersionMajor::NoTimestamps,
|
||||
Version::V3 => VersionMajor::CompressionEncryption,
|
||||
Version::V4 => VersionMajor::IndexEncryption,
|
||||
Version::V5 => VersionMajor::RelativeChunkOffsets,
|
||||
Version::V6 => VersionMajor::DeleteRecords,
|
||||
Version::V7 => VersionMajor::EncryptionKeyGuid,
|
||||
Version::V8A => VersionMajor::FNameBasedCompression,
|
||||
Version::V8B => VersionMajor::FNameBasedCompression,
|
||||
Version::V9 => VersionMajor::FrozenIndex,
|
||||
Version::V10 => VersionMajor::PathHashIndex,
|
||||
Version::V11 => VersionMajor::Fnv64BugFix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, strum::Display, strum::EnumString)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::Version;
|
||||
use super::{Version, VersionMajor};
|
||||
use hashbrown::HashMap;
|
||||
use std::io::{self, Seek};
|
||||
|
||||
|
@ -102,7 +102,7 @@ impl<R: io::Read + io::Seek> PakReader<R> {
|
|||
let mount_point = index.read_string()?;
|
||||
let len = index.read_u32::<LE>()? as usize;
|
||||
|
||||
let index = if version >= Version::PathHashIndex {
|
||||
let index = if version.version_major() >= VersionMajor::PathHashIndex {
|
||||
let path_hash_seed = index.read_u64::<LE>()?;
|
||||
|
||||
let path_hash_index = if index.read_u32::<LE>()? != 0 {
|
||||
|
|
|
@ -65,12 +65,12 @@ macro_rules! encryptindex {
|
|||
|
||||
matrix_test!(
|
||||
(
|
||||
"v5" unpak::Version::RelativeChunkOffsets,
|
||||
"v7" unpak::Version::EncryptionKeyGuid,
|
||||
"v8a" unpak::Version::FNameBasedCompression,
|
||||
"v8b" unpak::Version::FNameBasedCompression,
|
||||
"v9" unpak::Version::FrozenIndex,
|
||||
"v11" unpak::Version::Fnv64BugFix,
|
||||
"v5" unpak::Version::V5,
|
||||
"v7" unpak::Version::V7,
|
||||
"v8a" unpak::Version::V8A,
|
||||
"v8b" unpak::Version::V8B,
|
||||
"v9" unpak::Version::V9,
|
||||
"v11" unpak::Version::V11,
|
||||
),
|
||||
("", "_compress"),
|
||||
("", "_encrypt"),
|
||||
|
|
Loading…
Reference in a new issue