world decoding and encoding is fully implemented
This commit is contained in:
parent
5a3241e071
commit
7003a764d4
7 changed files with 86 additions and 95 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -14,6 +14,12 @@ version = "1.0.75"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deflate"
|
name = "deflate"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -28,6 +34,7 @@ name = "fot-save-edit"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
"deflate",
|
"deflate",
|
||||||
"inflate",
|
"inflate",
|
||||||
"memmem",
|
"memmem",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
|
byteorder = "1.4.3"
|
||||||
deflate = "1.0.0"
|
deflate = "1.0.0"
|
||||||
inflate = "0.4.5"
|
inflate = "0.4.5"
|
||||||
memmem = "0.1.1"
|
memmem = "0.1.1"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod raw;
|
mod raw;
|
||||||
mod decoder;
|
mod decoder;
|
||||||
mod tag;
|
mod tag;
|
||||||
|
mod world;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
103
src/fot/save.rs
103
src/fot/save.rs
|
|
@ -1,111 +1,36 @@
|
||||||
use std::io::Write;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use anyhow::Result;
|
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::raw::Raw;
|
||||||
use crate::fot::decoder;
|
use crate::fot::world::World;
|
||||||
use crate::fot::tag::Tag;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
use super::decoder::Decoder;
|
||||||
pub struct World {
|
|
||||||
pub offset: usize,
|
|
||||||
pub size: usize,
|
|
||||||
pub data: Vec<u8>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl World {
|
|
||||||
const DATA_OFFSET: usize = 0x13;
|
|
||||||
|
|
||||||
fn decode(raw: &[u8], offset: usize, size: usize) -> Result<Self> {
|
|
||||||
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<u8> {
|
|
||||||
deflate_bytes_zlib(&self.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dump(&self, path: &Path) -> Result<()> {
|
|
||||||
Ok(fs::write(path, &self.data)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Save {
|
pub struct Save {
|
||||||
pub raw: Vec<u8>,
|
pub raw: Raw,
|
||||||
pub worlds: Vec<World>
|
pub world: World
|
||||||
//world: World
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Save {
|
impl Save {
|
||||||
const WORLD_HDR: &str = "<world>";
|
const WORLD_HDR: &str = "<world>";
|
||||||
const WORLD_HDR_LEN: usize = Self::WORLD_HDR.len();
|
|
||||||
|
|
||||||
pub fn load(path: &Path) -> Result<Self> {
|
pub fn load(path: &Path) -> Result<Self> {
|
||||||
let raw = fs::read(path)?;
|
let raw = Raw::load_file(path)?;
|
||||||
let file_end = raw.len();
|
/*let world_offset = match raw.find_str_backwards(Self::WORLD_HDR) {
|
||||||
let mut offsets: Vec<usize> = Vec::new();
|
Some(offset) => offset,
|
||||||
for i in 0..raw.len()-Self::WORLD_HDR_LEN {
|
None => return Err(anyhow!("no world found in file"))
|
||||||
let keyword = match str::from_utf8(&raw[i..i+Self::WORLD_HDR_LEN]) {
|
};*/
|
||||||
Ok(keyword) => keyword,
|
let world = World::decode(&raw, 0x99A84, 0x3809B)?;
|
||||||
Err(_) => continue
|
Ok(Save { raw, world })
|
||||||
};
|
|
||||||
|
|
||||||
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<World> = 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 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self, path: &Path) -> Result<()> {
|
pub fn save(&self, path: &Path) -> Result<()> {
|
||||||
let raw = Raw { offset: 0, size: self.raw.len(), mem: self.raw.clone() };
|
self.raw.assemble_file(path, vec![
|
||||||
println!("found world at {:x}", raw.find_str_backwards("<world>").unwrap());
|
self.world.encode()
|
||||||
|
])?;
|
||||||
|
|
||||||
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<Raw> = 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);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ pub struct Tag {
|
||||||
pub version: String
|
pub version: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Tag {
|
||||||
|
pub fn get_tag_len(&self) -> usize {
|
||||||
|
self.name.len() + 1 + self.version.len() + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Decoder for Tag {
|
impl Decoder for Tag {
|
||||||
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> {
|
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> {
|
||||||
let name = String::decode(raw, offset, size)?;
|
let name = String::decode(raw, offset, size)?;
|
||||||
|
|
@ -16,8 +22,7 @@ impl Decoder for Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(&self) -> Raw {
|
fn encode(&self) -> Raw {
|
||||||
let len = self.name.len() + 1 + self.version.len() + 1;
|
Raw::join(0, self.get_tag_len(), &mut [
|
||||||
Raw::join(0, len, &mut [
|
|
||||||
self.name.encode(),
|
self.name.encode(),
|
||||||
self.version.encode()
|
self.version.encode()
|
||||||
])
|
])
|
||||||
|
|
|
||||||
52
src/fot/world.rs
Normal file
52
src/fot/world.rs
Normal file
|
|
@ -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<Self> {
|
||||||
|
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::<LittleEndian>()?;
|
||||||
|
|
||||||
|
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::<LittleEndian>(self.uncompressed_size);
|
||||||
|
let _ = wdr.write_u32::<LittleEndian>(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}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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() {
|
for w in save.worlds.iter() {
|
||||||
println!("World {:x} size {}", w.offset, w.size);
|
println!("World {:x} size {}", w.offset, w.size);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//save.save(Path::new("out.sav")).expect("failed to save");
|
let save = Save::load(Path::new(save_path)).expect("load save");
|
||||||
save.test().expect("test");
|
save.save(Path::new("out.sav")).expect("failed to save");
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue