Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 25 additions & 21 deletions crates/paksmith-core/src/container/pak/index/entry_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ use byteorder::{LittleEndian, ReadBytesExt};
use super::compression::{CompressionBlock, CompressionMethod};
use crate::container::pak::version::PakVersion;
use crate::digest::Sha1Digest;
use crate::error::{BoundsUnit, EncodedFault, IndexParseFault, OverflowSite, PaksmithError};
use crate::error::{
AllocationContext, BoundsUnit, EncodedFault, IndexParseFault, OverflowSite, PaksmithError,
WireField,
};

/// Sanity ceiling on compression block count per entry (~16M blocks of
/// 64KiB would be a 1TiB entry).
Expand Down Expand Up @@ -194,7 +197,7 @@ impl PakEntryHeader {
if block_count > MAX_BLOCKS_PER_ENTRY {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "block_count",
field: WireField::BlockCount,
value: u64::from(block_count),
limit: u64::from(MAX_BLOCKS_PER_ENTRY),
unit: BoundsUnit::Items,
Expand All @@ -214,8 +217,9 @@ impl PakEntryHeader {
.try_reserve_exact(block_count as usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "compression blocks",
context: AllocationContext::InlineCompressionBlocks,
requested: block_count as usize,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down Expand Up @@ -414,8 +418,9 @@ impl PakEntryHeader {
.try_reserve_exact(block_count as usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "encoded compression blocks",
context: AllocationContext::EncodedCompressionBlocks,
requested: block_count as usize,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down Expand Up @@ -538,7 +543,7 @@ impl PakEntryHeader {
if uncompressed_size > max_uncompressed {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "uncompressed_size",
field: WireField::UncompressedSize,
value: uncompressed_size,
limit: max_uncompressed,
unit: BoundsUnit::Bytes,
Expand Down Expand Up @@ -581,41 +586,40 @@ impl PakEntryHeader {
/// past the in-data record into the payload region; a mismatch here would
/// silently shift the payload boundary.
pub fn matches_payload(&self, payload: &Self, path: &str) -> crate::Result<()> {
let mismatch =
|field: &'static str, idx: String, dat: String| PaksmithError::InvalidIndex {
fault: IndexParseFault::FieldMismatch {
path: path.to_string(),
field,
index_value: idx,
payload_value: dat,
},
};
let mismatch = |field: WireField, idx: String, dat: String| PaksmithError::InvalidIndex {
fault: IndexParseFault::FieldMismatch {
path: path.to_string(),
field,
index_value: idx,
payload_value: dat,
},
};
let lhs = self.common();
let rhs = payload.common();
if lhs.compressed_size != rhs.compressed_size {
return Err(mismatch(
"compressed_size",
WireField::CompressedSize,
lhs.compressed_size.to_string(),
rhs.compressed_size.to_string(),
));
}
if lhs.uncompressed_size != rhs.uncompressed_size {
return Err(mismatch(
"uncompressed_size",
WireField::UncompressedSize,
lhs.uncompressed_size.to_string(),
rhs.uncompressed_size.to_string(),
));
}
if lhs.compression_method != rhs.compression_method {
return Err(mismatch(
"compression_method",
WireField::CompressionMethod,
format!("{:?}", lhs.compression_method),
format!("{:?}", rhs.compression_method),
));
}
if lhs.is_encrypted != rhs.is_encrypted {
return Err(mismatch(
"is_encrypted",
WireField::IsEncrypted,
lhs.is_encrypted.to_string(),
rhs.is_encrypted.to_string(),
));
Expand All @@ -637,7 +641,7 @@ impl PakEntryHeader {
if let (Some(lhs_sha), Some(rhs_sha)) = (self.sha1(), payload.sha1()) {
if lhs_sha != rhs_sha {
return Err(mismatch(
"sha1",
WireField::Sha1,
lhs_sha.short().to_string(),
rhs_sha.short().to_string(),
));
Expand Down Expand Up @@ -678,11 +682,11 @@ impl PakEntryHeader {
format!("{} blocks", rhs.compression_blocks.len()),
),
};
return Err(mismatch("compression_blocks", lhs_desc, rhs_desc));
return Err(mismatch(WireField::CompressionBlocks, lhs_desc, rhs_desc));
}
if lhs.compression_block_size != rhs.compression_block_size {
return Err(mismatch(
"compression_block_size",
WireField::CompressionBlockSize,
lhs.compression_block_size.to_string(),
rhs.compression_block_size.to_string(),
));
Expand Down
7 changes: 4 additions & 3 deletions crates/paksmith-core/src/container/pak/index/flat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::compression::CompressionMethod;
use super::fstring::read_fstring;
use super::{ENTRY_MIN_RECORD_BYTES, PakIndex, PakIndexEntry};
use crate::container::pak::version::PakVersion;
use crate::error::{BoundsUnit, IndexParseFault, PaksmithError};
use crate::error::{AllocationContext, BoundsUnit, IndexParseFault, PaksmithError, WireField};

// Cross-file `impl PakIndex` block: adds the v3-v9 parser entry point.
// The type itself, the version dispatcher, and the shared `from_entries`
Expand Down Expand Up @@ -46,7 +46,7 @@ impl PakIndex {
if u64::from(entry_count) > max_entries {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "entry_count",
field: WireField::EntryCount,
value: u64::from(entry_count),
limit: max_entries,
unit: BoundsUnit::Items,
Expand All @@ -63,8 +63,9 @@ impl PakIndex {
.try_reserve_exact(entry_count as usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "entries",
context: AllocationContext::FlatIndexEntries,
requested: entry_count as usize,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down
20 changes: 11 additions & 9 deletions crates/paksmith-core/src/container/pak/index/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use std::io::{Read, Seek, SeekFrom};
use tracing::warn;

use crate::container::pak::version::PakVersion;
use crate::error::{IndexParseFault, PaksmithError};
use crate::error::{AllocationContext, BoundsUnit, IndexParseFault, PaksmithError};

use fstring::read_fstring;

Expand Down Expand Up @@ -371,8 +371,9 @@ impl PakIndex {
seen.try_reserve(entries_len)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "dedup tracker for entries",
context: AllocationContext::DedupTracker,
requested: entries_len,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down Expand Up @@ -409,8 +410,9 @@ impl PakIndex {
.try_reserve(entries.len())
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "by-path lookup entries",
context: AllocationContext::ByPathLookup,
requested: entries.len(),
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down Expand Up @@ -463,7 +465,7 @@ mod tests {
use super::entry_header::encoded_entry_in_data_record_size;
use super::*;
use crate::digest::Sha1Digest;
use crate::error::{BoundsUnit, EncodedFault, FStringFault, OverflowSite};
use crate::error::{BoundsUnit, EncodedFault, FStringFault, OverflowSite, WireField};
// Issue #68: V10+ fixture builder shared with the integration
// proptest under `tests/index_proptest.rs`. Gated behind
// `__test_utils`, which is auto-enabled during `cargo test` via
Expand Down Expand Up @@ -2009,7 +2011,7 @@ mod tests {
else {
panic!("expected InvalidIndex BoundsExceeded with Bytes unit and no path, got: {err:?}")
};
assert_eq!(*field, "uncompressed_size");
assert_eq!(*field, WireField::UncompressedSize);
assert_eq!(*value, 0x10_0000_u64);
// 3 blocks × 0x1000 each = 0x3000 cap.
assert_eq!(*limit, 0x3000_u64);
Expand Down Expand Up @@ -2331,7 +2333,7 @@ mod tests {
&err,
PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "fdi_size",
field: WireField::FdiSize,
..
}
}
Expand Down Expand Up @@ -2377,7 +2379,7 @@ mod tests {
&err,
PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "non_encoded_count",
field: WireField::NonEncodedCount,
..
}
}
Expand Down Expand Up @@ -2538,7 +2540,7 @@ mod tests {
&err,
PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "dir_count",
field: WireField::DirCount,
..
},
}
Expand Down Expand Up @@ -2688,7 +2690,7 @@ mod tests {
&err,
PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "dir_count",
field: WireField::DirCount,
value: 2,
limit: 1,
..
Expand Down
35 changes: 21 additions & 14 deletions crates/paksmith-core/src/container/pak/index/path_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ use super::entry_header::PakEntryHeader;
use super::fstring::read_fstring;
use super::{ENTRY_MIN_RECORD_BYTES, PakIndex, PakIndexEntry};
use crate::container::pak::version::PakVersion;
use crate::error::{BoundsUnit, EncodedFault, IndexParseFault, PaksmithError};
use crate::error::{
AllocationContext, BoundsUnit, EncodedFault, IndexParseFault, PaksmithError, WireField,
};

/// Standalone ceiling on the v10+ FDI region byte size. A real-world
/// full directory index for a 100k-file pak is typically a few MB;
Expand Down Expand Up @@ -87,7 +89,7 @@ impl PakIndex {
let index_size_usize =
usize::try_from(index_size).map_err(|_| PaksmithError::InvalidIndex {
fault: IndexParseFault::U64ExceedsPlatformUsize {
field: "index_size",
field: WireField::IndexSize,
value: index_size,
path: None,
},
Expand All @@ -97,8 +99,9 @@ impl PakIndex {
.try_reserve_exact(index_size_usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "bytes for v10+ index",
context: AllocationContext::V10MainIndexBytes,
requested: index_size_usize,
unit: BoundsUnit::Bytes,
source,
path: None,
},
Expand Down Expand Up @@ -168,7 +171,7 @@ impl PakIndex {
let encoded_entries_size_usize =
usize::try_from(encoded_entries_size).map_err(|_| PaksmithError::InvalidIndex {
fault: IndexParseFault::U64ExceedsPlatformUsize {
field: "encoded_entries_size",
field: WireField::EncodedEntriesSize,
value: u64::from(encoded_entries_size),
path: None,
},
Expand All @@ -179,7 +182,7 @@ impl PakIndex {
if u64::from(encoded_entries_size) > index_size {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "encoded_entries_size",
field: WireField::EncodedEntriesSize,
value: u64::from(encoded_entries_size),
limit: index_size,
unit: BoundsUnit::Bytes,
Expand All @@ -192,8 +195,9 @@ impl PakIndex {
.try_reserve_exact(encoded_entries_size_usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "bytes for v10+ encoded entries",
context: AllocationContext::V10EncodedEntriesBytes,
requested: encoded_entries_size_usize,
unit: BoundsUnit::Bytes,
source,
path: None,
},
Expand All @@ -209,7 +213,7 @@ impl PakIndex {
if u64::from(non_encoded_count) > max_non_encoded {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "non_encoded_count",
field: WireField::NonEncodedCount,
value: u64::from(non_encoded_count),
limit: max_non_encoded,
unit: BoundsUnit::Items,
Expand All @@ -222,8 +226,9 @@ impl PakIndex {
.try_reserve_exact(non_encoded_count as usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "non-encoded entries for v10+ index",
context: AllocationContext::V10NonEncodedEntries,
requested: non_encoded_count as usize,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand All @@ -240,7 +245,7 @@ impl PakIndex {
if fdi_size > MAX_FDI_BYTES {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "fdi_size",
field: WireField::FdiSize,
value: fdi_size,
limit: MAX_FDI_BYTES,
unit: BoundsUnit::Bytes,
Expand All @@ -252,7 +257,7 @@ impl PakIndex {
let fdi_size_usize =
usize::try_from(fdi_size).map_err(|_| PaksmithError::InvalidIndex {
fault: IndexParseFault::U64ExceedsPlatformUsize {
field: "fdi_size",
field: WireField::FdiSize,
value: fdi_size,
path: None,
},
Expand All @@ -262,8 +267,9 @@ impl PakIndex {
.try_reserve_exact(fdi_size_usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "bytes for v10+ full directory index",
context: AllocationContext::V10FdiBytes,
requested: fdi_size_usize,
unit: BoundsUnit::Bytes,
source,
path: None,
},
Expand All @@ -282,7 +288,7 @@ impl PakIndex {
if u64::from(dir_count) > max_dirs_for_fdi {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "dir_count",
field: WireField::DirCount,
value: u64::from(dir_count),
limit: max_dirs_for_fdi,
unit: BoundsUnit::Items,
Expand All @@ -299,7 +305,7 @@ impl PakIndex {
if u64::from(file_count) > max_files_for_fdi {
return Err(PaksmithError::InvalidIndex {
fault: IndexParseFault::BoundsExceeded {
field: "file_count",
field: WireField::FileCount,
value: u64::from(file_count),
limit: max_files_for_fdi,
unit: BoundsUnit::Items,
Expand All @@ -312,8 +318,9 @@ impl PakIndex {
.try_reserve_exact(file_count as usize)
.map_err(|source| PaksmithError::InvalidIndex {
fault: IndexParseFault::AllocationFailed {
context: "entries for v10+ index",
context: AllocationContext::V10IndexEntries,
requested: file_count as usize,
unit: BoundsUnit::Items,
source,
path: None,
},
Expand Down
Loading
Loading