diff --git a/src/fot/decoder.rs b/src/fot/decoder.rs index 0610243..2bf77ae 100644 --- a/src/fot/decoder.rs +++ b/src/fot/decoder.rs @@ -1,10 +1,11 @@ use super::raw::Raw; +use super::stream::WriteStream; use anyhow::Result; use std::str; pub trait Decoder: Sized { fn decode(raw: &Raw, offset: usize, size: usize) -> Result; - fn encode(&self) -> Result; + fn encode(&self, wd: &mut WriteStream) -> Result<()>; fn get_enc_size(&self) -> usize; } @@ -23,14 +24,10 @@ impl Decoder for String { } } - fn encode(&self) -> Result { - let mut str = self.as_bytes().to_vec(); - str.push(0); - Ok(Raw { - offset: 0, - size: str.len(), - mem: str, - }) + fn encode(&self, wd: &mut WriteStream) -> Result<()> { + wd.write_bytes(self.as_bytes()); + wd.write_u8(0)?; + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/esh.rs b/src/fot/esh.rs index e5c1cee..d81adfd 100644 --- a/src/fot/esh.rs +++ b/src/fot/esh.rs @@ -119,8 +119,7 @@ impl Decoder for ESHValue { }) } - fn encode(&self) -> Result { - let mut wd = WriteStream::new(self.get_enc_size()); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { match self { ESHValue::Unknown(unk) => { wd.write_u32(unk.data_type)?; @@ -191,7 +190,7 @@ impl Decoder for ESHValue { } }; - Ok(wd.into_raw(0, 0)) + Ok(()) } fn get_enc_size(&self) -> usize { @@ -268,8 +267,7 @@ impl Decoder for ESH { }) } - fn encode(&self) -> Result { - let mut wd = WriteStream::new(self.get_enc_size()); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { wd.write(&self.tag)?; wd.write_u32(self.props.len() as u32)?; @@ -278,7 +276,7 @@ impl Decoder for ESH { wd.write(value)?; } - Ok(wd.into_raw(0, 0)) + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/fstring.rs b/src/fot/fstring.rs index 84f0539..3d4d7e6 100644 --- a/src/fot/fstring.rs +++ b/src/fot/fstring.rs @@ -1,7 +1,8 @@ use super::decoder::Decoder; use super::raw::Raw; +use super::stream::WriteStream; use anyhow::Result; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use byteorder::{LittleEndian, ReadBytesExt}; use encoding_rs::WINDOWS_1251; use std::borrow::Borrow; use std::fmt; @@ -53,26 +54,20 @@ impl Decoder for FString { } } - fn encode(&self) -> Result { - let mut buf = vec![0u8; 4]; - let mut wdr = Cursor::new(&mut buf[..]); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { let (chars, _, _) = WINDOWS_1251.encode(self.str.as_str()); if self.encoding == FStringEncoding::ANSI { - wdr.write_u32::(chars.len() as u32 & !(1 << 31))?; - buf.extend(chars.iter()); + wd.write_u32(chars.len() as u32 & !(1 << 31))?; + wd.write_bytes(&chars); } else { // WCS2 - wdr.write_u32::(chars.len() as u32 | (1 << 31))?; + wd.write_u32(chars.len() as u32 | (1 << 31))?; for &c in chars.iter() { - buf.push(c); - buf.push(0); + wd.write_u8(c)?; + wd.write_u8(0)?; } }; - Ok(Raw { - offset: 0, - size: buf.len(), - mem: buf, - }) + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/save.rs b/src/fot/save.rs index 8a2ce50..f3897ee 100644 --- a/src/fot/save.rs +++ b/src/fot/save.rs @@ -1,5 +1,6 @@ use super::decoder::Decoder; use super::raw::Raw; +use super::stream::WriteStream; use super::world::World; use anyhow::anyhow; use anyhow::Result; @@ -50,7 +51,12 @@ impl Save { } pub fn save(&self, path: &Path) -> Result<()> { - self.raw.assemble_file(path, vec![self.world.encode()?])?; + let raw = { + let mut wd = WriteStream::new(0); + wd.write(&self.world)?; + wd.into_raw(self.world.offset, self.world.size) + }; + self.raw.assemble_file(path, vec![raw])?; Ok(()) } diff --git a/src/fot/sgd.rs b/src/fot/sgd.rs index 7f5526e..29a6503 100644 --- a/src/fot/sgd.rs +++ b/src/fot/sgd.rs @@ -48,8 +48,7 @@ impl Decoder for SGD { }) } - fn encode(&self) -> Result { - let mut wd = WriteStream::new(self.enc_size); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { wd.write(&self.tag)?; wd.write_bytes(&self.unk1); @@ -66,7 +65,7 @@ impl Decoder for SGD { } } - Ok(wd.into_raw(0, 0)) + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/ssg.rs b/src/fot/ssg.rs index 86186fe..ada266d 100644 --- a/src/fot/ssg.rs +++ b/src/fot/ssg.rs @@ -18,11 +18,10 @@ impl Decoder for SSG { Ok(SSG { tag, unk1 }) } - fn encode(&self) -> Result { - let mut wd = WriteStream::new(self.get_enc_size()); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { wd.write(&self.tag)?; wd.write_bytes(&self.unk1); - Ok(wd.into_raw(0, 0x14)) + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/stream.rs b/src/fot/stream.rs index 07a9908..db34383 100644 --- a/src/fot/stream.rs +++ b/src/fot/stream.rs @@ -116,6 +116,10 @@ impl WriteStream { self.buf.get_mut().extend(bytes.iter()); } + pub fn reserve(&mut self, size: usize) { + self.buf.get_mut().reserve(size); + } + pub fn write_opt, DCtx, ECtx>( &mut self, val: &T, @@ -128,9 +132,11 @@ impl WriteStream { } pub fn write(&mut self, val: &T) -> Result<()> { - let mut raw = val.encode()?; - self.skip(raw.mem.len()); - self.buf.get_mut().append(&mut raw.mem); + //let mut raw = val.encode()?; + //self.skip(raw.mem.len()); + //self.buf.get_mut().append(&mut raw.mem); + self.reserve(val.get_enc_size()); + val.encode(self)?; Ok(()) } diff --git a/src/fot/tag.rs b/src/fot/tag.rs index b939f68..58224fd 100644 --- a/src/fot/tag.rs +++ b/src/fot/tag.rs @@ -17,11 +17,10 @@ impl Decoder for Tag { Ok(Tag { name, version }) } - fn encode(&self) -> Result { - let mut wd = WriteStream::new(self.get_enc_size()); + fn encode(&self, wd: &mut WriteStream) -> Result<()> { wd.write(&self.name)?; wd.write(&self.version)?; - Ok(wd.into_raw(0, self.get_enc_size())) + Ok(()) } fn get_enc_size(&self) -> usize { diff --git a/src/fot/world.rs b/src/fot/world.rs index 5d013b2..dc82ee1 100644 --- a/src/fot/world.rs +++ b/src/fot/world.rs @@ -88,7 +88,7 @@ impl Decoder for World { }) } - fn encode(&self) -> Result { + fn encode(&self, wd: &mut WriteStream) -> Result<()> { let data = { let mut wd = WriteStream::new(self.uncompressed_size as usize); @@ -101,14 +101,13 @@ impl Decoder for World { let raw = wd.into_raw(0, 0); deflate_bytes_zlib(&raw.mem) }; - - let mut wd = WriteStream::new(self.get_enc_size()); + wd.write(&self.tag)?; wd.write_u32(self.uncompressed_size)?; wd.write_u32(self.uncompressed_size)?; wd.write_bytes(&data); - Ok(wd.into_raw(self.offset, self.size)) + Ok(()) } fn get_enc_size(&self) -> usize {