begin working on write support
This commit is contained in:
parent
aabd45b5fd
commit
ccc06c81d1
|
@ -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" }
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
2
prs-rust
2
prs-rust
|
@ -1 +1 @@
|
|||
Subproject commit 288e8bf588cc84cc6d23ee3476a4119ad3fb2cb5
|
||||
Subproject commit c2757ca1ba88ea51b386d1f48af0b9fa01829cc7
|
Loading…
Reference in New Issue