diff --git a/Cargo.lock b/Cargo.lock index 6120ed2..b267b9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,12 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "deflate" version = "1.0.0" @@ -28,6 +34,7 @@ name = "fot-save-edit" version = "0.1.0" dependencies = [ "anyhow", + "byteorder", "deflate", "inflate", "memmem", diff --git a/Cargo.toml b/Cargo.toml index a2941a9..5cfa5b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.75" +byteorder = "1.4.3" deflate = "1.0.0" inflate = "0.4.5" memmem = "0.1.1" diff --git a/src/fot.rs b/src/fot.rs index f0803aa..44d99e5 100644 --- a/src/fot.rs +++ b/src/fot.rs @@ -1,4 +1,5 @@ mod raw; mod decoder; mod tag; +mod world; pub mod save; \ No newline at end of file diff --git a/src/fot/save.rs b/src/fot/save.rs index dcccb39..e04dec1 100644 --- a/src/fot/save.rs +++ b/src/fot/save.rs @@ -1,111 +1,36 @@ -use std::io::Write; use std::str; use std::fs; -use std::fs::OpenOptions; use std::path::Path; use anyhow::anyhow; use anyhow::Result; -use inflate::inflate_bytes_zlib; -use deflate::deflate_bytes_zlib; -use crate::fot::decoder::Decoder; use crate::fot::raw::Raw; -use crate::fot::decoder; -use crate::fot::tag::Tag; +use crate::fot::world::World; -#[derive(Debug)] -pub struct World { - pub offset: usize, - pub size: usize, - pub data: Vec -} - -impl World { - const DATA_OFFSET: usize = 0x13; - - fn decode(raw: &[u8], offset: usize, size: usize) -> Result { - let data_start = offset + World::DATA_OFFSET; - let data_end = offset + size; - let data = inflate_bytes_zlib(&raw[data_start..data_end]) - .map_err(|e| anyhow!(e))?; - - Ok(Self { offset, size, data }) - } - - fn encode(&self) -> Vec { - deflate_bytes_zlib(&self.data) - } - - pub fn dump(&self, path: &Path) -> Result<()> { - Ok(fs::write(path, &self.data)?) - } -} +use super::decoder::Decoder; #[derive(Debug)] pub struct Save { - pub raw: Vec, - pub worlds: Vec - //world: World + pub raw: Raw, + pub world: World } impl Save { const WORLD_HDR: &str = ""; - const WORLD_HDR_LEN: usize = Self::WORLD_HDR.len(); pub fn load(path: &Path) -> Result { - let raw = fs::read(path)?; - let file_end = raw.len(); - let mut offsets: Vec = Vec::new(); - for i in 0..raw.len()-Self::WORLD_HDR_LEN { - let keyword = match str::from_utf8(&raw[i..i+Self::WORLD_HDR_LEN]) { - Ok(keyword) => keyword, - Err(_) => continue - }; - - if keyword == Self::WORLD_HDR { - offsets.push(i); - } - } - if offsets.is_empty() { - return Err(anyhow!("no offsets found")); - } - offsets.push(file_end); - - let mut worlds: Vec = Vec::new(); - /*for i in offsets.windows(2) { - match World::decode(&raw, i[0], i[1] - i[0]) { - Ok(world) => worlds.push(world), - Err(e) => println!("world 0x{:x} decode error {}", i[0], e) - }; - }*/ - - Ok(Self { raw, worlds }) + let raw = Raw::load_file(path)?; + /*let world_offset = match raw.find_str_backwards(Self::WORLD_HDR) { + Some(offset) => offset, + None => return Err(anyhow!("no world found in file")) + };*/ + let world = World::decode(&raw, 0x99A84, 0x3809B)?; + Ok(Save { raw, world }) } pub fn save(&self, path: &Path) -> Result<()> { - let raw = Raw { offset: 0, size: self.raw.len(), mem: self.raw.clone() }; - println!("found world at {:x}", raw.find_str_backwards("").unwrap()); - - - const START: usize = 0x99A84; - const END: usize = 0xD1B1E; //0xD1B1E; - const SIZE: usize = 0x38088; - //let world = self.worlds.last().unwrap(); - let world = World::decode(&self.raw, START, END - START)?; - let enc = world.encode(); - - let mut blocks: Vec = Vec::new(); - blocks.push(Raw {offset: START, size: 0x13, mem: self.raw[START..START+0x13].to_vec()}); - blocks.push(Raw {offset: START+0x13, size: SIZE, mem: enc}); - - raw.assemble_file(path, blocks)?; - - Ok(()) - } - - pub fn test(&self) -> Result<()> { - let raw = Raw { offset: 0, size: self.raw.len(), mem: self.raw.clone() }; - let tag = Tag::decode(&raw, 0x99A84, 7); - dbg!(&tag); + self.raw.assemble_file(path, vec![ + self.world.encode() + ])?; Ok(()) } diff --git a/src/fot/tag.rs b/src/fot/tag.rs index 72ba07b..e3c6502 100644 --- a/src/fot/tag.rs +++ b/src/fot/tag.rs @@ -8,6 +8,12 @@ pub struct Tag { pub version: String } +impl Tag { + pub fn get_tag_len(&self) -> usize { + self.name.len() + 1 + self.version.len() + 1 + } +} + impl Decoder for Tag { fn decode(raw: &Raw, offset: usize, size: usize) -> Result { let name = String::decode(raw, offset, size)?; @@ -16,8 +22,7 @@ impl Decoder for Tag { } fn encode(&self) -> Raw { - let len = self.name.len() + 1 + self.version.len() + 1; - Raw::join(0, len, &mut [ + Raw::join(0, self.get_tag_len(), &mut [ self.name.encode(), self.version.encode() ]) diff --git a/src/fot/world.rs b/src/fot/world.rs new file mode 100644 index 0000000..b5e1710 --- /dev/null +++ b/src/fot/world.rs @@ -0,0 +1,52 @@ +use crate::fot::decoder::Decoder; +use crate::fot::raw::Raw; +use crate::fot::tag::Tag; +use anyhow::anyhow; +use anyhow::Result; +use std::io::Cursor; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use inflate::inflate_bytes_zlib; +use deflate::deflate_bytes_zlib; + +#[derive(Debug)] +pub struct World { + pub tag: Tag, + pub uncompressed_size: u32, + + pub data: Raw +} + +impl World { + const WORLD_TAG_LEN: usize = 11; + const WORLD_HDR_LEN: usize = 0x13; +} + +impl Decoder for World { + fn decode(raw: &Raw, offset: usize, size: usize) -> Result { + let tag = Tag::decode(raw, offset, Self::WORLD_TAG_LEN)?; + + let mut rdr = Cursor::new(&raw.mem[offset+Self::WORLD_TAG_LEN..]); + let uncompressed_size = rdr.read_u32::()?; + + let data_start = offset + Self::WORLD_HDR_LEN; + let data = inflate_bytes_zlib(&raw.mem[data_start..data_start+size]) + .map_err(|e| anyhow!(e))?; + Ok(World { tag, uncompressed_size, data: Raw { offset, size, mem: data } }) + } + + fn encode(&self) -> Raw { + let mut hdr = [0u8; 8]; + { + let mut wdr = Cursor::new(&mut hdr[..]); + let _ = wdr.write_u32::(self.uncompressed_size); + let _ = wdr.write_u32::(self.uncompressed_size); + } + let data = deflate_bytes_zlib(&self.data.mem); + + Raw::join(self.data.offset, self.data.size, &mut [ + self.tag.encode(), + Raw { offset: Self::WORLD_TAG_LEN, size: 8, mem: hdr.to_vec()}, + Raw { offset: Self::WORLD_HDR_LEN, size: data.len(), mem: data} + ]) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7e64e22..6c4695c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,11 +13,11 @@ fn main() { };*/ - let save = Save::load(Path::new(save_path)).expect("load save"); + /*let save = Save::load(Path::new(save_path)).expect("load save"); for w in save.worlds.iter() { println!("World {:x} size {}", w.offset, w.size); - } + }*/ - //save.save(Path::new("out.sav")).expect("failed to save"); - save.test().expect("test"); + let save = Save::load(Path::new(save_path)).expect("load save"); + save.save(Path::new("out.sav")).expect("failed to save"); } \ No newline at end of file