diff options
| author | Valentin Popov <valentin@popov.link> | 2026-02-10 11:57:00 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-02-10 11:57:00 +0300 |
| commit | ba1789f10607f5a6cba5863128d31f776b8e59cc (patch) | |
| tree | cc090228196bddc5a700c5ec32ec61f53c44a4b4 /crates/nres | |
| parent | 842f4a85693b418af81560738aa3136ac500d9b1 (diff) | |
| download | fparkan-ba1789f10607f5a6cba5863128d31f776b8e59cc.tar.xz fparkan-ba1789f10607f5a6cba5863128d31f776b8e59cc.zip | |
fix: обработка выхода за пределы индекса сортировки в архиве и улучшение декодирования LZSS с поддержкой XOR
Diffstat (limited to 'crates/nres')
| -rw-r--r-- | crates/nres/src/lib.rs | 9 | ||||
| -rw-r--r-- | crates/nres/src/tests.rs | 46 |
2 files changed, 53 insertions, 2 deletions
diff --git a/crates/nres/src/lib.rs b/crates/nres/src/lib.rs index 0cd9e22..1fa3b39 100644 --- a/crates/nres/src/lib.rs +++ b/crates/nres/src/lib.rs @@ -111,7 +111,9 @@ impl Archive { let mut high = self.entries.len(); while low < high { let mid = low + (high - low) / 2; - let target_idx = self.entries[mid].meta.sort_index as usize; + let Ok(target_idx) = usize::try_from(self.entries[mid].meta.sort_index) else { + break; + }; if target_idx >= self.entries.len() { break; } @@ -396,7 +398,10 @@ fn parse_archive(bytes: &[u8], raw_mode: bool) -> Result<(Vec<EntryRecord>, u64) name }, }; - return Ok((vec![entry], bytes.len() as u64)); + return Ok(( + vec![entry], + u64::try_from(bytes.len()).map_err(|_| Error::IntegerOverflow)?, + )); } if bytes.len() < 16 { diff --git a/crates/nres/src/tests.rs b/crates/nres/src/tests.rs index 47aad53..43f155f 100644 --- a/crates/nres/src/tests.rs +++ b/crates/nres/src/tests.rs @@ -610,6 +610,52 @@ fn nres_synthetic_read_find_and_edit() { } #[test] +fn nres_find_falls_back_when_sort_index_is_out_of_range() { + let mut bytes = build_nres_bytes(&[ + SyntheticEntry { + kind: 1, + attr1: 0, + attr2: 0, + attr3: 0, + name: "Alpha", + data: b"a", + }, + SyntheticEntry { + kind: 2, + attr1: 0, + attr2: 0, + attr3: 0, + name: "Beta", + data: b"b", + }, + SyntheticEntry { + kind: 3, + attr1: 0, + attr2: 0, + attr3: 0, + name: "Gamma", + data: b"c", + }, + ]); + + let entry_count = 3usize; + let directory_offset = bytes + .len() + .checked_sub(entry_count * 64) + .expect("directory offset underflow"); + let mid_entry_sort_index = directory_offset + 64 + 60; + bytes[mid_entry_sort_index..mid_entry_sort_index + 4].copy_from_slice(&u32::MAX.to_le_bytes()); + + let archive = Archive::open_bytes(Arc::from(bytes.into_boxed_slice()), OpenOptions::default()) + .expect("open archive with corrupted sort index failed"); + + assert_eq!(archive.find("alpha"), Some(EntryId(0))); + assert_eq!(archive.find("BETA"), Some(EntryId(1))); + assert_eq!(archive.find("gamma"), Some(EntryId(2))); + assert_eq!(archive.find("missing"), None); +} + +#[test] fn nres_validation_error_cases() { let valid = build_nres_bytes(&[SyntheticEntry { kind: 1, |
