Skip to content

Commit

Permalink
Build feature
Browse files Browse the repository at this point in the history
  • Loading branch information
LinkOFF7 authored Aug 30, 2024
1 parent cbd3596 commit 849d940
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ edition = "2021"

[dependencies]
binary-stream = "9.1.0"
log = "0.4.22"
26 changes: 22 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,29 @@ mod mpk;

fn main() {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
println!("Emio – The Smiling Man: Famicom Detective Club MPK Extractor\n");
println!("Usage: {} INPUT_MPK", &args[0]);
if args.len() != 3 {
print_usage(&args[0]);
process::exit(1);
} else {
let _ = mpk::extract(&args[1]);
if &args[1] == "extract" {
let _ = match mpk::extract(&args[2]) {
Err(e) => panic!("{}", e),
Ok(r) => r
};
} else if &args[1] == "build" {
let _ = match mpk::build(&args[2]) {
Err(e) => panic!("{}", e),
Ok(r) => r
};
} else {
print_usage(&args[0]);
process::exit(1);
}
}
}

fn print_usage(arg: &str) {
println!("Emio – The Smiling Man: Famicom Detective Club MPK Extractor\n");
println!("Usage: {} <mode> <mpk/directory>\n", &arg);
println!("MODES:\n extract\tExtract all files from archive\n build\t\tCreate new archive from folder");
}
91 changes: 88 additions & 3 deletions src/mpk.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fs;
use std::{fs};
use std::fs::File;
use std::io::{SeekFrom};
use std::io::{BufRead, BufReader, Read, SeekFrom, Write};
use std::path::Path;
use binary_stream::{BinaryReader, BinaryWriter, Options};

Expand Down Expand Up @@ -34,6 +34,7 @@ pub fn extract(mpk_path: &str) -> Result<(), std::io::Error> {

let files = reader.read_u64().unwrap();
let _ = reader.seek(SeekFrom::Current(0x30));
let mut file_order: Vec<String> = Vec::new();

for _i in 0..files{
let var00 = reader.read_i32().unwrap();
Expand All @@ -42,14 +43,16 @@ pub fn extract(mpk_path: &str) -> Result<(), std::io::Error> {
let var10 = reader.read_u64().unwrap();
let var18 = reader.read_u64().unwrap();
let var20 = reader.read_bytes(224).unwrap();
let filename = String::from_utf8(var20).unwrap().replace("\0", "");
file_order.push(filename.clone());

entries.push(Entry {
field00: var00,
index: var04,
offset: var08,
compressed_size: var10,
uncompressed_size: var18,
file_path: String::from_utf8(var20).unwrap().replace("\0", "")
file_path: filename.clone()
});
}
let output_dir = Path::new(mpk_path).file_stem().unwrap();
Expand All @@ -73,5 +76,87 @@ pub fn extract(mpk_path: &str) -> Result<(), std::io::Error> {
let _ = writer.write_bytes(buffer.unwrap());
}

let mut fo_f = File::create(Path::new(output_dir).join("_fileorder.txt"))?;
for line in &file_order {
let l = line.clone() + "\n";
fo_f.write_all(l.as_bytes()).unwrap();
}

Ok(())
}

pub fn build(input_dir: &str) -> Result<(), std::io::Error> {
let files_count = fs::read_dir(&input_dir).unwrap().count() - 1;
assert_ne!(files_count, 0);

let f = match File::open(Path::new(input_dir).join("_fileorder.txt")) {
Err(e) => panic!("_fileorder.txt: {}", e),
Ok(f) => f
};
let reader = BufReader::new(f);
let files: Vec<_> = reader.lines().collect();

let mpk_name = input_dir.to_string() + ".mpk";
let mut data_start = 0x40 + (0x100 * files_count);
if data_start % 0x800 != 0 {
data_start += 0x800 - data_start % 0x800
};
let mut entries = Vec::<Entry>::new();

let mpk_f = match File::create(&mpk_name) {
Err(e) => panic!("{:?}", e),
Ok(out_f) => out_f,
};
let mut writer = BinaryWriter::new(mpk_f, Options::default());

let _ = writer.write_u32(0x4B504D);
let _ = writer.write_u32(0x20000);
let _ = writer.write_u64(files_count as u64);
let _ = writer.seek(SeekFrom::Start(data_start as u64));

let mut index = 0;
for file in files {
let path = Path::new(input_dir).join(file.unwrap());
println!("Import: {}", &path.display());
let mut f = match File::open(&path) {
Err(e) => panic!("{}", e),
Ok(f) => f,
};
let metadata = fs::metadata(&path)?;
let mut buffer = vec![0; metadata.len() as usize];
f.read(&mut buffer).expect("buffer overflow");
let fname = path.file_name().unwrap();
entries.push(Entry{
field00: 0,
index,
offset: writer.stream_position().unwrap(),
compressed_size: metadata.len(),
uncompressed_size: metadata.len(),
file_path: String::from(fname.to_str().unwrap())
});

let _ = writer.write_bytes(&buffer);

let pos = writer.stream_position().unwrap();
if pos % 0x800 != 0 {
let _ = writer.seek(SeekFrom::Current((0x800 - pos % 0x800) as i64));
}

index += 1;
}

let _ = writer.seek(SeekFrom::Start(0x40));
for entry in entries.iter(){
let _ = writer.write_i32(&entry.field00);
let _ = writer.write_i32(&entry.index);
let _ = writer.write_u64(&entry.offset);
let _ = writer.write_u64(&entry.compressed_size);
let _ = writer.write_u64(&entry.uncompressed_size);
let mut buf = vec![0u8; 224];
let str_buf = &entry.file_path.as_bytes();
buf[..str_buf.len()].copy_from_slice(&str_buf);
let _ = writer.write_bytes(&buf);
}

Ok(())
}

0 comments on commit 849d940

Please sign in to comment.