begin working on write support

This commit is contained in:
lifning 2021-01-15 03:37:56 -08:00
parent aabd45b5fd
commit ccc06c81d1
5 changed files with 86 additions and 37 deletions

View File

@ -4,8 +4,8 @@ version = "0.1.0"
authors = ["lifning <lifning+git@pm.me>"]
[dependencies]
argh = "0.1"
binread = "1"
binwrite = "0.2"
byteorder = "1"
prs-rust = { path = "../prs-rust" }
log = "0.4"
prs-rust = { path = "../prs-rust" }

View File

@ -1,26 +1,50 @@
extern crate one_rust;
#[macro_use] extern crate argh;
extern crate binread;
extern crate one_rust;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use binread::prelude::*;
use one_rust::JodOne;
use std::path::PathBuf;
/// Unpack .one archives from NiGHTS: Journey of Dreams
#[derive(FromArgs)]
struct Args {
#[argh(subcommand)]
action: Action,
}
#[derive(FromArgs)]
#[argh(subcommand)]
enum Action {
ExtractFile(ExtractFile)
}
/// Unpack and decompress the files inside a .one archive.
#[derive(FromArgs)]
#[argh(subcommand, name = "xf")]
struct ExtractFile {
/// path to the .one file
#[argh(positional)]
file: PathBuf,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
for arg in &args[1..] {
let mut infile = File::open(arg)?;
let archive: JodOne = infile.read_le()?;
let entries = archive.unpack();
let dir = PathBuf::from(format!("{}.d", arg));
for (name, data) in entries {
let full_path = dir.join(name);
if let Some(path) = full_path.parent() {
std::fs::create_dir_all(path)?;
let args: Args = argh::from_env();
match args.action {
Action::ExtractFile(ex) => {
let mut infile = File::open(&ex.file)?;
let archive: JodOne = infile.read_le()?;
let entries = archive.unpack();
let dir = PathBuf::from(format!("{}.d", ex.file.to_string_lossy()));
for (name, data) in entries {
let full_path = dir.join(name);
if let Some(path) = full_path.parent() {
std::fs::create_dir_all(path)?;
}
File::create(full_path)?.write_all(&data)?;
}
File::create(full_path)?.write_all(&data)?;
}
}
Ok(())

View File

@ -1,8 +1,8 @@
extern crate byteorder;
extern crate prs_rust;
#![feature(fixed_size_array)]
#[macro_use] extern crate binread;
#[macro_use] extern crate binwrite;
#[macro_use] extern crate log;
extern crate prs_rust;
mod one;
pub use one::*;

View File

@ -1,20 +1,37 @@
use binread::{FilePtr, NullString};
use prs_rust::prs;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;
use std::fmt::Formatter;
use std::path::PathBuf;
fn string_binread_helper(x: NullString) -> String {
unsafe {
String::from_utf8_unchecked(x.0)
}
}
fn string_binwrite_helper(pad_to_len: usize) -> impl Fn(&String) -> Vec<u8> {
move |x: &String| {
let mut v = x.as_bytes().to_vec();
v.resize(pad_to_len, 0);
v
}
}
// i'm having trouble thinking atm because noisy ps3 game being played next to me
#[derive(BinRead)]
#[derive(BinWrite)]
#[br(little, magic = b"ThisIsOneFile\0\0\0")]
#[binwrite(little)]
pub struct JodOne {
// usually 0xCC... format version maybe?
// but i've seen 0xCA in Test04/disp/Test04.one and 0xCB in Test05/disp/stg2010_sun.one
_unknown1: u32,
// usually "Default" or "landData"
#[br(pad_size_to = 32)]
pub category: NullString,
#[br(pad_size_to = 32, map = string_binread_helper)]
#[binwrite(preprocessor(string_binwrite_helper(32)))]
pub category: String,
#[br(pad_after = 128)]
pub count: u32,
#[br(count = count)]
@ -22,7 +39,9 @@ pub struct JodOne {
}
#[derive(BinRead)]
#[derive(BinWrite)]
#[br(little, assert(id_again == id))]
#[binwrite(little)]
pub struct JodOneEntry {
pub _unknown1: u32,
pub id: u32,
@ -31,9 +50,11 @@ pub struct JodOneEntry {
pub size_dec: u32,
pub id_again: u32,
#[br(count = size_cmp)]
#[binwrite(preprocessor(|x: &FilePtr<u32, Vec<u8>>| x.ptr))]
pub data: FilePtr<u32, Vec<u8>>,
#[br(pad_size_to = 188)]
pub name: NullString,
#[br(pad_size_to = 188, map = string_binread_helper)]
#[binwrite(preprocessor(string_binwrite_helper(188)))]
pub name: String,
}
impl std::fmt::Debug for JodOneEntry {
@ -43,21 +64,25 @@ impl std::fmt::Debug for JodOneEntry {
}
impl JodOne {
pub fn unpack(self) -> BTreeMap<PathBuf, Vec<u8>> {
let mut map = BTreeMap::new();
for entry in self.entries {
pub fn pack(inputs: impl Iterator<Item = (PathBuf, Vec<u8>)>, category: Option<&str>) -> Self {
JodOne {
_unknown1: 0xCC,
category: category.unwrap_or("Default").to_string(),
count: 0,
entries: vec![]
}
}
pub fn unpack(self) -> impl Iterator<Item = (PathBuf, Vec<u8>)> {
self.entries.into_iter().map(|entry| {
debug!("{:?}", entry);
let os_string = OsString::from_vec(entry.name.0.into_iter()
.map(|c| if char::from(c) == '\\' { std::path::MAIN_SEPARATOR as u8 } else { c })
.collect());
let key = PathBuf::from(os_string);
let key = PathBuf::from(entry.name.replace('\\', std::path::MAIN_SEPARATOR.encode_utf8(&mut [0u8; 4])));
if entry.size_dec == 0 {
map.insert(key, entry.data.into_inner());
(key, entry.data.into_inner())
} else {
let dec_buf = prs::Decompressor::new(entry.data.into_inner(), Some(entry.size_dec as usize)).decompress();
map.insert(key, dec_buf);
(key, dec_buf)
}
}
map
})
}
}

@ -1 +1 @@
Subproject commit 288e8bf588cc84cc6d23ee3476a4119ad3fb2cb5
Subproject commit c2757ca1ba88ea51b386d1f48af0b9fa01829cc7