tweaks to assertions, do them as soon as relevant fields are available

This commit is contained in:
lifning 2021-01-17 12:51:53 -08:00
parent 19e7dfa238
commit 7310755a79
5 changed files with 31 additions and 22 deletions

View File

@ -30,10 +30,10 @@ const SIZE_OF_ENTRY: u32 = (6 * size_of::<u32>() + SIZE_OF_FILENAME) as u32;
// not using binread's built-in [br(magic=...)] because it doesn't let me reference self::MAGIC
#[derive(BinRead, BinWrite)]
#[br(little, assert(magic == self::MAGIC))]
#[br(little)]
#[binwrite(little)]
pub struct JodOne {
#[br(pad_size_to = self::SIZE_OF_MAGIC, map = string_binread_helper)]
#[br(pad_size_to = self::SIZE_OF_MAGIC, map = string_binread_helper, assert(magic == self::MAGIC))]
#[binwrite(preprocessor(string_binwrite_helper(self::SIZE_OF_MAGIC)))]
pub magic: String,
/// usually 0xCC... archive creator version?

View File

@ -14,21 +14,27 @@ const TYPICAL_STRING_TABLE_COUNT: usize = 0x100;
#[derive(BinRead, BinWrite)]
#[br(little, assert(
id_archive == 0 && id_string_table == 1 && version == version_again &&
entries.iter().enumerate().all(|(i, ent)| ent.id as usize == i + 2)
entries.iter().enumerate().all(|(i, ent)| ent.id as usize == i + 2 && ent.version == version) &&
archive_size_minus_12 == (
entries.iter().map(|e| self::SIZE_OF_ENTRY + e.size_cmp).sum::<u32>() +
SIZE_OF_ENTRY + (string_table.len() * SIZE_OF_FILENAME) as u32
)
))]
#[binwrite(little)]
pub struct HerOne {
/// 0. conceptually the ID of the "entry" containing the entire archive
#[br(assert(id_archive == 0))]
id_archive: u32,
/// the size of the archive, not counting the "pre-header" of these first three u32's
/// the size of the archive, not counting the "first entry" of these first three u32's
archive_size_minus_12: u32,
/// presumably the archiver version. known values: 0x1400ffff from GCN version
version: u32,
#[br(assert(id_string_table == 1))]
/// 1. conceptually the ID of the (uncompressed) array of filenames, indexed by ID.
id_string_table: u32,
/// usually 0x4000. size of string table in bytes.
string_table_size: u32,
#[br(assert(version == version_again))]
version_again: u32,
#[br(count = string_table_size as usize / self::SIZE_OF_FILENAME)]
pub string_table: Vec<HerOneFilename>,
@ -46,8 +52,6 @@ pub struct HerOneFilename {
pub inner: String,
}
// there is one file for which the assertion can't be (size_dec == 0) == (is_compressed == 0).
// event/event8006_sceneE.one: EVENT8006.CEN, whose size_dec is 0x20, its in-archive size.
#[derive(BinRead, BinWrite)]
#[br(
little,

View File

@ -91,11 +91,6 @@ pub fn read_one_archive(mut reader: impl Read + Seek) -> Result<DynOneArchive, B
Err(e) => info!("Not a NiGHTS Journey of Dreams archive: {}", e),
}
reader.seek(SeekFrom::Start(rewind))?;
match reader.read_be::<rings::SsrOne>() {
Ok(one) => return Ok(DynOneArchive::SsrOne(one)),
Err(e) => info!("Not a Sonic and the Secret Rings archive: {}", e),
}
reader.seek(SeekFrom::Start(rewind))?;
match reader.read_le::<shadow::ShadOne>() {
Ok(one) => return Ok(DynOneArchive::ShadOne(one)),
Err(e) => info!("Not a Shadow the Hedgehog archive: {}", e),
@ -105,5 +100,11 @@ pub fn read_one_archive(mut reader: impl Read + Seek) -> Result<DynOneArchive, B
Ok(one) => return Ok(DynOneArchive::HerOne(one)),
Err(e) => info!("Not a Sonic Heroes archive: {}", e),
}
// last 'cause it's the least-specific in terms of assertions
reader.seek(SeekFrom::Start(rewind))?;
match reader.read_be::<rings::SsrOne>() {
Ok(one) => return Ok(DynOneArchive::SsrOne(one)),
Err(e) => info!("Not a Sonic and the Secret Rings archive: {}", e),
}
Err("No valid .one archive found".into())
}

View File

@ -24,22 +24,21 @@ const SIZE_OF_ENTRY: u32 = (4 * size_of::<u32>() + SIZE_OF_FILENAME) as u32;
// 5105 SsrOneEntry{size_cmp: 1+, size_dec: 1+, ..}
#[derive(BinRead, BinWrite)]
#[br(big, assert(
entries.ptr == self::SIZE_OF_HEADER &&
data_offset == entries.ptr + count * self::SIZE_OF_ENTRY
))]
#[br(big)]
#[binwrite(big)]
pub struct SsrOne {
/// number of files stored in the .one
pub count: u32,
/// the location of the table of contents. always 0x10, just after this header
#[br(count = count)]
#[br(count = count, assert(entries.ptr == self::SIZE_OF_HEADER))]
#[binwrite(preprocessor(|x: &FilePtr<u32, _>| x.ptr))]
pub entries: FilePtr<u32, Vec<SsrOneEntry>>,
/// location of the end of the toc/beginning of data. TODO: assertion
/// location of the end of the toc/beginning of data.
#[br(assert(data_offset == entries.ptr + count * self::SIZE_OF_ENTRY))]
pub data_offset: u32,
/// always 0
pub _padding: u32,
#[br(assert(_padding == 0))]
_padding: u32,
}
#[derive(BinRead, BinWrite)]
@ -53,7 +52,7 @@ pub struct SsrOneEntry {
// note: seek_before/restore_position shenanigans because we need _size_cmp for data's count
#[br(seek_before = SeekFrom::Current(4), restore_position)]
#[binwrite(ignore)]
pub _size_cmp: u32,
_size_cmp: u32,
#[br(count = _size_cmp)]
#[binwrite(preprocessor(|x: &FilePtr<u32, _>| x.ptr))]
pub data: FilePtr<u32, Vec<u8>>,

View File

@ -52,16 +52,21 @@ fn compute_size_cmp<R: Read + Seek>(
}
#[derive(BinRead, BinWrite)]
#[br(little, assert(start == 0 && matches!(magic.as_str(), self::MAGIC_60 | self::MAGIC_50)))]
#[br(little)]
#[binwrite(little)]
pub struct ShadOne {
/// 0. presumably where data starts, not counting the "pre-header" of these first three u32's
#[br(assert(start == 0))]
start: u32,
/// the size of the archive, not counting the "pre-header" of these first three u32's
archive_size_minus_12: u32,
/// presumably the archiver version. known values: 0x1c020037 and 0x1c020020 from GCN version
pub version: u32,
#[br(pad_size_to = self::SIZE_OF_MAGIC, map = string_binread_helper)]
#[br(
pad_size_to = self::SIZE_OF_MAGIC,
map = string_binread_helper,
assert(matches!(magic.as_str(), self::MAGIC_60 | self::MAGIC_50))
)]
#[binwrite(preprocessor(string_binwrite_helper(self::SIZE_OF_MAGIC)))]
pub magic: String,
/// number of files stored in the .one