jmrenamer: rewrite to use package.toc
The package.toc file contains all the file names, except for itself (but we know it always so this isn't a problem). Therefore, we don't need to store a hardcoded string table! Yay!
This commit is contained in:
parent
11abf7668a
commit
15d438f294
|
@ -16,23 +16,23 @@ pub struct PackageTocEntry {
|
|||
}
|
||||
|
||||
impl PackageTocEntry {
|
||||
fn file_name(&self) -> Option<String> {
|
||||
pub fn file_name(&self) -> Option<String> {
|
||||
make_c_string(&self.file_name)
|
||||
}
|
||||
|
||||
fn file_name_hash(&self) -> u32 {
|
||||
pub fn file_name_hash(&self) -> u32 {
|
||||
self.file_name_hash
|
||||
}
|
||||
|
||||
fn toc_start_offset(&self) -> u32 {
|
||||
pub fn toc_start_offset(&self) -> u32 {
|
||||
self.toc_start_offset
|
||||
}
|
||||
|
||||
fn toc_size(&self) -> u32 {
|
||||
pub fn toc_size(&self) -> u32 {
|
||||
self.toc_size
|
||||
}
|
||||
|
||||
fn toc_file_count(&self) -> u32 {
|
||||
pub fn toc_file_count(&self) -> u32 {
|
||||
self.toc_file_count
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,3 +16,9 @@ pub fn dat_filename(filename: &str) -> String {
|
|||
pub fn met_filename(filename: &str) -> String {
|
||||
format!("{:X}.MET", hash_string(String::from(filename)))
|
||||
}
|
||||
|
||||
/// Make a .DAT filename from a pre-created hash.
|
||||
/// This is notably used to re-use hashes from `package.toc`.
|
||||
pub fn dat_filename_from_hash(hash: u32) -> String {
|
||||
format!("{:X}.DAT", hash)
|
||||
}
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
//! High-level readers
|
||||
|
||||
pub mod package_toc;
|
||||
|
||||
pub mod texture;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
use std::fs::File;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::path::{PathBuf};
|
||||
|
||||
use crate::format::{
|
||||
package_toc::*
|
||||
};
|
||||
|
||||
use binext::BinaryRead;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("underlying I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("file too small to hold package toc entry")]
|
||||
FileTooSmall,
|
||||
|
||||
/// Under-read of data
|
||||
#[error("underread")]
|
||||
ReadTooSmall,
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub fn read_package_toc(path: PathBuf) -> Result<Vec<PackageTocEntry>> {
|
||||
let mut toc_file = File::open(path.clone())?;
|
||||
|
||||
let file_size = toc_file.seek(SeekFrom::End(0))?;
|
||||
toc_file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
let vec_size : usize = file_size as usize / std::mem::size_of::<PackageTocEntry>();
|
||||
|
||||
if vec_size == 0 {
|
||||
return Err(Error::FileTooSmall);
|
||||
}
|
||||
|
||||
let mut vec : Vec<PackageTocEntry> = Vec::with_capacity(vec_size);
|
||||
|
||||
for _ in 0..vec_size {
|
||||
vec.push(toc_file.read_binary::<PackageTocEntry>()?);
|
||||
}
|
||||
|
||||
drop(toc_file);
|
||||
Ok(vec)
|
||||
}
|
|
@ -1,68 +1,55 @@
|
|||
//! A reimplemntation of jmmt_renamer in Rust.
|
||||
//! A reimplementation of jmmt_renamer in Rust.
|
||||
//! This program should be run in the root directory
|
||||
//! of an extracted (from image) copy of the game.
|
||||
|
||||
use std::{fs, io, path::Path};
|
||||
use std::{fs, path::Path};
|
||||
use jmmt::hash::filename::*;
|
||||
use jmmt::read::package_toc::{read_package_toc};
|
||||
|
||||
const FILENAME_TABLE : [&str; 20] = [
|
||||
// First loaded by the game
|
||||
"package.toc",
|
||||
|
||||
// General packs
|
||||
"config.pak",
|
||||
|
||||
// This file is referenced in the game files,
|
||||
// but doesn't seem to exist anymore in the final build.
|
||||
//"shell.pak",
|
||||
|
||||
"shell_character_select.pak",
|
||||
"shell_main.pak",
|
||||
"shell_title.pak",
|
||||
"shell_venue.pak",
|
||||
"shell_event.pak",
|
||||
"shell_option.pak",
|
||||
"win_screens.pak",
|
||||
|
||||
// Game levels
|
||||
"SF_san_fran.pak",
|
||||
"DC_washington.pak",
|
||||
"MK_MT_KILI.pak",
|
||||
"MP_MACHU_PIHU.pak",
|
||||
"LV_Las_Vegas.pak",
|
||||
"AN_ANTARTICA.pak",
|
||||
"NP_Nepal.pak",
|
||||
"TH_TAHOE.pak",
|
||||
"VA_Valdez_alaska.pak",
|
||||
"RV_Rome.pak",
|
||||
"TR_training.pak"
|
||||
];
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
// TODO: A mode that will re-name everything back? This wouldn't be too hard to implement
|
||||
|
||||
fn main() {
|
||||
// A relatively simple idiot-check. Later on utilities might have a shared library
|
||||
// of code which validates game root stuff and can open it up/etc.
|
||||
if !Path::new("DATA").is_dir() {
|
||||
println!("This program should be run in the root of an extracted copy.");
|
||||
std::process::exit(1);
|
||||
return ();
|
||||
}
|
||||
|
||||
// Go through the clearname table and rename files in the DATA directory
|
||||
for clearname in FILENAME_TABLE.iter() {
|
||||
let dat_filename = dat_filename(clearname);
|
||||
let dat_src = format!("DATA/{}", dat_filename);
|
||||
let dat_clearname = format!("DATA/{}", String::from(*clearname));
|
||||
let package_toc_filename = format!("DATA/{}", dat_filename("package.toc"));
|
||||
|
||||
let src_path = Path::new(dat_src.as_str());
|
||||
let dest_path = Path::new(dat_clearname.as_str());
|
||||
match read_package_toc(Path::new(package_toc_filename.as_str()).to_path_buf()) {
|
||||
Ok(toc) => {
|
||||
for toc_entry in toc {
|
||||
let dat_src = format!("DATA/{}", dat_filename_from_hash(toc_entry.file_name_hash()));
|
||||
let src_path = Path::new(dat_src.as_str());
|
||||
let dat_clearname = format!("DATA/{}", toc_entry.file_name().expect("How did invalid ASCII get here?"));
|
||||
let dest_path = Path::new(dat_clearname.as_str());
|
||||
|
||||
if src_path.exists() {
|
||||
fs::rename(src_path, dest_path)?;
|
||||
println!("moved {} -> {}", src_path.display(), dest_path.display());
|
||||
} else if dest_path.exists() {
|
||||
println!("{} already exists", dest_path.display());
|
||||
if src_path.exists() {
|
||||
match fs::rename(src_path, dest_path) {
|
||||
Ok(_) => {},
|
||||
Err(error) => {
|
||||
println!("Error renaming {}: {}", src_path.display(), error);
|
||||
return ();
|
||||
}
|
||||
};
|
||||
println!("moved {} -> {}", src_path.display(), dest_path.display());
|
||||
}
|
||||
}
|
||||
|
||||
match fs::rename(Path::new(package_toc_filename.as_str()), Path::new("DATA/package.toc")) {
|
||||
Ok(_) => {},
|
||||
Err(error) => {
|
||||
println!("Error renaming TOC file: {}", error);
|
||||
return ();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Err(error) => {
|
||||
println!("Error reading package.toc file: {}", error);
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue