initial Heroes list/extract support
This commit is contained in:
parent
d8a0ecf273
commit
416875502a
|
@ -1,3 +1,5 @@
|
|||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
use binread::FilePtr;
|
||||
use binwrite::BinWrite;
|
||||
use one::{OneArchive, OneArchiveEntry, WriteSeek};
|
||||
|
@ -6,9 +8,6 @@ use std::fmt::Formatter;
|
|||
use std::mem::size_of;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
|
||||
// stats on version, comment, and category:
|
||||
// $ find . -name \*.one -exec bash -c "onear tf "{}" > "{}".txt" \;
|
||||
// $ fd one.txt | xargs cat | sed 's/count: .*/..}/' | grep '^JodOne{' | sort | uniq -c
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
use binread::BinRead;
|
||||
use binwrite::BinWrite;
|
||||
use one::{OneArchive, OneArchiveEntry, WriteSeek};
|
||||
use prs_rust::prs;
|
||||
use std::fmt::Formatter;
|
||||
use std::mem::size_of;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const SIZE_OF_PRE_HEADER: u32 = 3 * size_of::<u32>() as u32;
|
||||
const SIZE_OF_FILENAME: usize = 0x40;
|
||||
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)
|
||||
))]
|
||||
#[binwrite(little)]
|
||||
pub struct HerOne {
|
||||
/// 0. conceptually the ID of the "entry" containing the entire archive
|
||||
id_archive: 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: 0x1400ffff from GCN version
|
||||
version: u32,
|
||||
/// 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,
|
||||
version_again: u32,
|
||||
#[br(count = string_table_size as usize / self::SIZE_OF_FILENAME)]
|
||||
pub string_table: Vec<HerOneFilename>,
|
||||
#[br(
|
||||
count = string_table.iter().skip(2).position(|x| x.0.is_empty()).unwrap_or(0),
|
||||
args(version, string_table.as_ptr())
|
||||
)]
|
||||
pub entries: Vec<HerOneEntry>,
|
||||
}
|
||||
|
||||
#[derive(BinRead, BinWrite, Clone)]
|
||||
pub struct HerOneFilename(
|
||||
#[br(pad_size_to = self::SIZE_OF_FILENAME, map = string_binread_helper)]
|
||||
#[binwrite(preprocessor(string_binwrite_helper(self::SIZE_OF_FILENAME)))]
|
||||
pub 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,
|
||||
import(version_hdr: u32, string_table: *const HerOneFilename),
|
||||
assert(version == version_hdr)
|
||||
)]
|
||||
#[binwrite(little)]
|
||||
pub struct HerOneEntry {
|
||||
pub id: u32,
|
||||
pub size_cmp: u32,
|
||||
version: u32,
|
||||
#[br(count = size_cmp)]
|
||||
pub data: Vec<u8>,
|
||||
#[br(calc = unsafe { (*string_table.add(id as usize)).0.clone() })]
|
||||
#[binwrite(ignore)]
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for HerOne {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "HerOne{{version: 0x{:x}, ..}}", self.version)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for HerOneEntry {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"HerOneEntry{{id: {}, name: {:?}, size_cmp: {}, ..}}",
|
||||
self.id, self.name, self.size_cmp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl OneArchiveEntry for HerOneEntry {}
|
||||
|
||||
impl OneArchive for HerOne {
|
||||
fn write(&self, mut writer: &mut dyn WriteSeek) -> std::io::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn pack(contents: impl IntoIterator<Item = (PathBuf, Vec<u8>)>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unpack(self) -> Box<dyn Iterator<Item = (PathBuf, Vec<u8>)>> {
|
||||
Box::new(self.entries.into_iter().map(|entry| {
|
||||
let key = PathBuf::from(entry.name);
|
||||
let dec_buf = prs::Decompressor::new(entry.data, None).decompress();
|
||||
(key, dec_buf)
|
||||
}))
|
||||
}
|
||||
|
||||
fn entries(&self) -> Vec<&dyn OneArchiveEntry> {
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let y: &dyn OneArchiveEntry = x;
|
||||
y
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use binread::io::SeekFrom;
|
||||
use binread::BinReaderExt;
|
||||
use one::dreams::JodOne;
|
||||
use one::heroes::HerOne;
|
||||
use one::rings::SsrOne;
|
||||
use one::shadow::ShadOne;
|
||||
use std::error::Error;
|
||||
|
@ -9,6 +10,7 @@ use std::io::{Read, Seek, Write};
|
|||
use std::path::PathBuf;
|
||||
|
||||
pub(crate) mod dreams;
|
||||
pub(crate) mod heroes;
|
||||
pub(crate) mod rings;
|
||||
pub(crate) mod shadow;
|
||||
|
||||
|
@ -32,6 +34,7 @@ pub enum DynOneArchive {
|
|||
JodOne(JodOne),
|
||||
SsrOne(SsrOne),
|
||||
ShadOne(ShadOne),
|
||||
HerOne(HerOne),
|
||||
}
|
||||
|
||||
impl Debug for DynOneArchive {
|
||||
|
@ -40,6 +43,7 @@ impl Debug for DynOneArchive {
|
|||
DynOneArchive::JodOne(one) => one.fmt(f),
|
||||
DynOneArchive::SsrOne(one) => one.fmt(f),
|
||||
DynOneArchive::ShadOne(one) => one.fmt(f),
|
||||
DynOneArchive::HerOne(one) => one.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +54,7 @@ impl OneArchive for DynOneArchive {
|
|||
DynOneArchive::JodOne(one) => one.write(writer),
|
||||
DynOneArchive::SsrOne(one) => one.write(writer),
|
||||
DynOneArchive::ShadOne(one) => one.write(writer),
|
||||
DynOneArchive::HerOne(one) => one.write(writer),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +70,7 @@ impl OneArchive for DynOneArchive {
|
|||
DynOneArchive::JodOne(one) => one.unpack(),
|
||||
DynOneArchive::SsrOne(one) => one.unpack(),
|
||||
DynOneArchive::ShadOne(one) => one.unpack(),
|
||||
DynOneArchive::HerOne(one) => one.unpack(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +79,7 @@ impl OneArchive for DynOneArchive {
|
|||
DynOneArchive::JodOne(one) => one.entries(),
|
||||
DynOneArchive::SsrOne(one) => one.entries(),
|
||||
DynOneArchive::ShadOne(one) => one.entries(),
|
||||
DynOneArchive::HerOne(one) => one.entries(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,5 +100,10 @@ pub fn read_one_archive(mut reader: impl Read + Seek) -> Result<DynOneArchive, B
|
|||
Ok(one) => return Ok(DynOneArchive::ShadOne(one)),
|
||||
Err(e) => info!("Not a Shadow the Hedgehog archive: {}", e),
|
||||
}
|
||||
reader.seek(SeekFrom::Start(rewind))?;
|
||||
match reader.read_le::<heroes::HerOne>() {
|
||||
Ok(one) => return Ok(DynOneArchive::HerOne(one)),
|
||||
Err(e) => info!("Not a Sonic Heroes archive: {}", e),
|
||||
}
|
||||
Err("No valid .one archive found".into())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
use binread::FilePtr;
|
||||
use binwrite::BinWrite;
|
||||
use one::{OneArchive, OneArchiveEntry, WriteSeek};
|
||||
|
@ -7,9 +9,6 @@ use std::io::SeekFrom;
|
|||
use std::mem::size_of;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
|
||||
const SIZE_OF_HEADER: u32 = 4 * size_of::<u32>() as u32;
|
||||
const SIZE_OF_FILENAME: usize = 32;
|
||||
const SIZE_OF_ENTRY: u32 = (4 * size_of::<u32>() + SIZE_OF_FILENAME) as u32;
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
use binread::io::{Read, Seek, SeekFrom};
|
||||
use binread::{BinRead, BinResult, FilePtr, ReadOptions};
|
||||
use binwrite::BinWrite;
|
||||
use one::{OneArchive, OneArchiveEntry, WriteSeek};
|
||||
use std::fmt::Formatter;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::string_binread_helper;
|
||||
use crate::string_binwrite_helper;
|
||||
use prs_rust::prs;
|
||||
use std::fmt::Formatter;
|
||||
use std::mem::size_of;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// stats on version, comment, and count
|
||||
// $ find . -name \*.one -exec bash -c "onear tf "{}" > "{}".txt" \;
|
||||
|
|
Loading…
Reference in New Issue