first bit of Shadow .one creation
This commit is contained in:
parent
b7c670b37b
commit
5ac56fb114
|
@ -25,6 +25,7 @@ enum Action {
|
|||
CreateFile(CreateFile),
|
||||
CreateJodFile(CreateJodFile),
|
||||
CreateSsrFile(CreateSsrFile),
|
||||
CreateShadFile(CreateShadFile),
|
||||
}
|
||||
|
||||
enum GameType {
|
||||
|
@ -112,6 +113,18 @@ struct CreateSsrFile {
|
|||
contents: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
/// Create a _S_hadow the Hedgehog .one archive.
|
||||
#[derive(FromArgs)]
|
||||
#[argh(subcommand, name = "cSf")]
|
||||
struct CreateShadFile {
|
||||
/// path of the .one file to create
|
||||
#[argh(positional)]
|
||||
file: PathBuf,
|
||||
/// paths of the files to pack into the archive
|
||||
#[argh(positional)]
|
||||
contents: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
fn create_one(subcmd: CreateFile) -> Result<(), Box<dyn Error>> {
|
||||
if subcmd.file.exists() {
|
||||
return Err(format!("{:?} already exists, refusing to overwrite", subcmd.file).into());
|
||||
|
@ -127,7 +140,7 @@ fn create_one(subcmd: CreateFile) -> Result<(), Box<dyn Error>> {
|
|||
let archive: Box<dyn OneArchive> = match subcmd.game {
|
||||
GameType::Dreams => Box::new(JodOne::pack(contents)),
|
||||
GameType::Rings => Box::new(SsrOne::pack(contents)),
|
||||
GameType::Shadow => todo!(),
|
||||
GameType::Shadow => Box::new(ShadOne::pack(contents)),
|
||||
GameType::Heroes => todo!(),
|
||||
};
|
||||
let mut outfile = File::create(&subcmd.file)?;
|
||||
|
@ -179,5 +192,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
};
|
||||
create_one(subcmd)
|
||||
}
|
||||
Action::CreateShadFile(subcmd) => {
|
||||
let subcmd = CreateFile {
|
||||
game: GameType::Shadow,
|
||||
file: subcmd.file,
|
||||
contents: subcmd.contents,
|
||||
};
|
||||
create_one(subcmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ const MAGIC_60: &'static str = "One Ver 0.60";
|
|||
|
||||
const SIZE_OF_MAGIC: usize = 16;
|
||||
const SIZE_OF_COMMENT: usize = 0x90;
|
||||
const SIZE_OF_HEADER: u32 = (4 * size_of::<u32>() + SIZE_OF_MAGIC + SIZE_OF_COMMENT) as u32;
|
||||
const SIZE_OF_PRE_HEADER: u32 = (3 * size_of::<u32>()) as u32;
|
||||
const SIZE_OF_HEADER: u32 = SIZE_OF_PRE_HEADER + (size_of::<u32>() + SIZE_OF_MAGIC + SIZE_OF_COMMENT) as u32;
|
||||
|
||||
const SIZE_OF_FILENAME: usize = 0x2c;
|
||||
const SIZE_OF_ENTRY: u32 = (3 * size_of::<u32>() + SIZE_OF_FILENAME) as u32;
|
||||
|
@ -55,16 +56,16 @@ fn compute_size_cmp<R: Read + Seek>(
|
|||
#[binwrite(little)]
|
||||
pub struct ShadOne {
|
||||
/// 0. presumably where data starts, not counting the "pre-header" of these first three u32's
|
||||
pub start: u32,
|
||||
start: u32,
|
||||
/// the size of the archive, not counting the "pre-header" of these first three u32's
|
||||
pub archive_size_minus_twelve: u32,
|
||||
archive_size_minus_twelve: 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)]
|
||||
#[binwrite(preprocessor(string_binwrite_helper(self::SIZE_OF_MAGIC)))]
|
||||
pub magic: String,
|
||||
/// number of files stored in the .one
|
||||
pub count: u32,
|
||||
count: u32,
|
||||
#[br(pad_size_to = self::SIZE_OF_COMMENT, map = string_binread_helper)]
|
||||
#[binwrite(preprocessor(string_binwrite_helper(self::SIZE_OF_COMMENT)))]
|
||||
pub comment: String,
|
||||
|
@ -91,8 +92,8 @@ pub struct ShadOneEntry {
|
|||
#[br(restore_position, parse_with = compute_size_cmp, args(count, arc_size))]
|
||||
#[binwrite(ignore)]
|
||||
pub _size_cmp: u32,
|
||||
#[br(offset = 12, count = _size_cmp)]
|
||||
#[binwrite(preprocessor(|x: &FilePtr<u32, _>| x.ptr))]
|
||||
#[br(offset = self::SIZE_OF_PRE_HEADER as u64, count = _size_cmp)]
|
||||
#[binwrite(preprocessor(|x: &FilePtr<u32, _>| x.ptr - self::SIZE_OF_PRE_HEADER))]
|
||||
pub data: FilePtr<u32, Vec<u8>>, // TODO: compute size by finding PRS length?
|
||||
pub is_compressed: u32,
|
||||
}
|
||||
|
@ -127,11 +128,57 @@ impl OneArchive for ShadOne {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn pack(_contents: impl IntoIterator<Item = (PathBuf, Vec<u8>)>) -> Self
|
||||
fn pack(contents: impl IntoIterator<Item = (PathBuf, Vec<u8>)>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
todo!()
|
||||
let mut entries = Vec::new();
|
||||
for (path, data) in contents.into_iter() {
|
||||
let cmp = prs::Compressor::new(&data, None).compress();
|
||||
let name = path.to_string_lossy().to_uppercase();
|
||||
if cmp.len() < data.len() {
|
||||
entries.push(ShadOneEntry {
|
||||
name,
|
||||
size_dec: data.len() as u32,
|
||||
_size_cmp: cmp.len() as u32,
|
||||
data: FilePtr {
|
||||
ptr: 0,
|
||||
value: Some(cmp),
|
||||
},
|
||||
is_compressed: 1,
|
||||
});
|
||||
} else {
|
||||
entries.push(ShadOneEntry {
|
||||
name,
|
||||
size_dec: 0,
|
||||
_size_cmp: data.len() as u32,
|
||||
data: FilePtr {
|
||||
ptr: 0,
|
||||
value: Some(data),
|
||||
},
|
||||
is_compressed: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let data_offset = SIZE_OF_HEADER + SIZE_OF_ENTRY * entries.len() as u32;
|
||||
let mut loc = data_offset;
|
||||
for entry in &mut entries {
|
||||
entry.data.ptr = loc;
|
||||
loc += entry.data.value.as_ref().unwrap().len() as u32;
|
||||
loc = ((loc + 3) / 4) * 4; // round up to 4 byte alignment
|
||||
}
|
||||
|
||||
// user can overwrite string/version fields afterward
|
||||
ShadOne {
|
||||
start: 0,
|
||||
archive_size_minus_twelve: loc - SIZE_OF_PRE_HEADER,
|
||||
version: 0x1c020037,
|
||||
magic: MAGIC_60.to_string(),
|
||||
count: entries.len() as u32,
|
||||
comment: "".to_string(),
|
||||
entries,
|
||||
}
|
||||
}
|
||||
|
||||
fn unpack(self) -> Box<dyn Iterator<Item = (PathBuf, Vec<u8>)>> {
|
||||
|
|
Loading…
Reference in New Issue