diff --git a/src/fot/decoder.rs b/src/fot/decoder.rs index a0f24eb..e21be3d 100644 --- a/src/fot/decoder.rs +++ b/src/fot/decoder.rs @@ -1,27 +1,29 @@ -use super::raw::Raw; -use super::stream::WriteStream; -use anyhow::Result; +use super::stream::{ReadStream, WriteStream}; +use anyhow::{anyhow, Result}; use std::str; pub trait Decoder: Sized { - fn decode(raw: &Raw, offset: usize, size: usize) -> Result; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result; fn encode(&self, wd: &mut WriteStream) -> Result<()>; fn get_enc_size(&self) -> usize; } pub trait DecoderCtx: Sized { - fn decode(raw: &Raw, offset: usize, size: usize, ctx: DCtx) -> Result; + fn decode<'a>(rd: &mut ReadStream<'a>, ctx: DCtx) -> Result; fn encode(&self, wd: &mut WriteStream, ctx: ECtx) -> Result<()>; fn get_enc_size(&self) -> usize; } impl Decoder for String { - fn decode(raw: &Raw, offset: usize, size: usize) -> Result { - let str = &raw.mem[offset..]; - match str.iter().position(|&c| c == 0) { - Some(pos) => Ok(str::from_utf8(&str[..pos])?.to_string()), - None => Ok(str::from_utf8(&raw.mem[offset..offset + size])?.to_string()), - } + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let bytes = rd.as_byte_arr(); + let pos = match bytes.iter().position(|&c| c == 0) { + Some(pos) => pos, + None => return Err(anyhow!("No zero-terminator found")) + }; + let str = str::from_utf8(rd.as_bytes(pos)?)?; + rd.skip(1); + Ok(str.to_string()) } fn encode(&self, wd: &mut WriteStream) -> Result<()> { diff --git a/src/fot/entity.rs b/src/fot/entity.rs index 8acfb24..7ac0473 100644 --- a/src/fot/entity.rs +++ b/src/fot/entity.rs @@ -1,7 +1,6 @@ use super::decoder::DecoderCtx; use super::entitylist::{EntityEncoding, EntityList}; use super::esh::ESH; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use anyhow::Result; @@ -16,13 +15,13 @@ pub struct Entity { } impl DecoderCtx<&mut EntityList, &EntityList> for Entity { - fn decode(raw: &Raw, offset: usize, _: usize, ctx: &mut EntityList) -> Result { - let mut rd = ReadStream::new(raw, offset); + fn decode<'a>(rd: &mut ReadStream<'a>, ctx: &mut EntityList) -> Result { + let offset = rd.offset(); Ok(match ctx.get_entity_encoding() { EntityEncoding::File => { let flags = NO_FLAGS; - let type_idx = ctx.add_or_get_type(rd.read(0)?); - let esh: ESH = rd.read(0)?; + let type_idx = ctx.add_or_get_type(rd.read()?); + let esh: ESH = rd.read()?; let enc_size = rd.offset() - offset; Entity { flags, @@ -35,7 +34,7 @@ impl DecoderCtx<&mut EntityList, &EntityList> for Entity { let flags = rd.read_u32()?; let type_idx = rd.read_u16()? as usize; let esh: Option = if type_idx != NO_ESH { - Some(rd.read(0)?) + Some(rd.read()?) } else { None }; diff --git a/src/fot/entitylist.rs b/src/fot/entitylist.rs index 12b2206..f6996d6 100644 --- a/src/fot/entitylist.rs +++ b/src/fot/entitylist.rs @@ -1,7 +1,6 @@ use super::decoder::{DecoderCtx, Decoder}; use super::entity::Entity; use super::fstring::{FString, FStringEncoding}; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use super::tag::{Tag, CTag}; use std::path::Path; @@ -79,8 +78,8 @@ impl EntityList { } impl DecoderCtx for EntityList { - fn decode(raw: &Raw, offset: usize, size: usize, ctx: EntityEncoding) -> Result { - let mut rd = ReadStream::new(raw, offset); + fn decode<'a>(rd: &mut ReadStream<'a>, ctx: EntityEncoding) -> Result { + let offset = rd.offset(); let mut ent_list = EntityList { encoding: ctx, entity_file_tag: None, @@ -94,14 +93,14 @@ impl DecoderCtx for EntityList { Ok(match ctx { EntityEncoding::File => { let mut first = true; - while rd.offset() < size { - let tag: Tag = rd.read(0)?; + while !rd.is_end() { + let tag: Tag = rd.read()?; if first { ent_list.entity_tag = Some(tag); first = false; } - let ent: Entity = rd.read_opt(0, &mut ent_list)?; + let ent: Entity = rd.read_ctx(0, &mut ent_list)?; ent_list.ents.push(ent); } @@ -110,16 +109,16 @@ impl DecoderCtx for EntityList { } EntityEncoding::World => { - ent_list.entity_file_tag = Some(rd.read(0)?); + ent_list.entity_file_tag = Some(rd.read()?); let type_count = rd.read_u32()?; for _ in 0..type_count { - ent_list.types.push(rd.read(0)?); + ent_list.types.push(rd.read()?); } let ent_count = rd.read_u16()?; ent_list.unk1 = rd.read_u32()?; for _ in 1..ent_count { - let ent: Entity = rd.read_opt(0, &mut ent_list)?; + let ent: Entity = rd.read_ctx(0, &mut ent_list)?; ent_list.ents.push(ent); } @@ -137,7 +136,7 @@ impl DecoderCtx for EntityList { continue; } wd.write(self.get_entity_tag())?; - wd.write_opt(ent, &self)?; + wd.write_ctx(ent, &self)?; } } EntityEncoding::World => { @@ -150,7 +149,7 @@ impl DecoderCtx for EntityList { wd.write_u16((self.ents.len() + 1) as u16)?; wd.write_u32(self.unk1)?; for ent in self.ents.iter() { - wd.write_opt(ent, &self)?; + wd.write_ctx(ent, &self)?; } } } diff --git a/src/fot/esh.rs b/src/fot/esh.rs index d81adfd..773ccbf 100644 --- a/src/fot/esh.rs +++ b/src/fot/esh.rs @@ -1,6 +1,5 @@ use super::decoder::Decoder; use super::fstring::FString; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use super::tag::Tag; use anyhow::Result; @@ -76,8 +75,8 @@ impl ESHValue { } impl Decoder for ESHValue { - fn decode(raw: &Raw, offset: usize, _: usize) -> Result { - let mut rd = ReadStream::new(raw, offset); + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let offset = rd.offset(); let data_type = rd.read_u32()?; let data_size = rd.read_u32()?; @@ -85,8 +84,8 @@ impl Decoder for ESHValue { Self::TYPE_BOOL => ESHValue::Bool(rd.read_u8()? == 1), Self::TYPE_FLOAT => ESHValue::Float(rd.read_f32()?), Self::TYPE_INT => ESHValue::Int(rd.read_i32()?), - Self::TYPE_STRING => ESHValue::String(rd.read::(0)?), - Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::(0)?), + Self::TYPE_STRING => ESHValue::String(rd.read::()?), + Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::()?), Self::TYPE_ESBIN => ESHValue::Binary(rd.read_bytes(data_size as usize)?), Self::TYPE_ENTTITYFLAGS => { let entity_id = rd.read_u16()?; @@ -247,15 +246,15 @@ pub struct ESH { } impl Decoder for ESH { - fn decode(raw: &Raw, offset: usize, _: usize) -> Result { - let mut rd = ReadStream::new(raw, offset); - let tag: Tag = rd.read(0)?; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let offset = rd.offset(); + let tag: Tag = rd.read()?; let n = rd.read_u32()? as usize; let mut props: IndexMap = IndexMap::with_capacity(n); for _ in 0..n { - let name: FString = rd.read(0)?; - let value: ESHValue = rd.read(0)?; + let name: FString = rd.read()?; + let value: ESHValue = rd.read()?; props.insert(name, value); } diff --git a/src/fot/fstring.rs b/src/fot/fstring.rs index 3d4d7e6..b687563 100644 --- a/src/fot/fstring.rs +++ b/src/fot/fstring.rs @@ -1,13 +1,10 @@ use super::decoder::Decoder; -use super::raw::Raw; -use super::stream::WriteStream; +use super::stream::{ReadStream, WriteStream}; use anyhow::Result; -use byteorder::{LittleEndian, ReadBytesExt}; use encoding_rs::WINDOWS_1251; use std::borrow::Borrow; use std::fmt; use std::hash::{Hash, Hasher}; -use std::io::Cursor; // FString - Fallout @@ -25,14 +22,14 @@ pub struct FString { } impl Decoder for FString { - fn decode(raw: &Raw, offset: usize, _: usize) -> Result { - let mut rdr = Cursor::new(&raw.mem[offset..]); - let flen = rdr.read_u32::()? as usize; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + //let mut rdr = Cursor::new(&raw.mem[offset..]); + let flen = rd.read_u32()? as usize; let len = flen & !(1 << 31); - let start = offset + 4; if flen & (1 << 31) == 0 { // ANSI - let (str, _, _) = WINDOWS_1251.decode(&raw.mem[start..start + len]); + let bytes = rd.as_bytes(len)?; + let (str, _, _) = WINDOWS_1251.decode(bytes); Ok(FString { encoding: FStringEncoding::ANSI, enc_len: len, @@ -40,7 +37,8 @@ impl Decoder for FString { }) } else { // WCS2 - let chars: Vec = raw.mem[start..start + len * 2] + let bytes = rd.as_bytes(len * 2)?; + let chars: Vec = bytes .iter() .step_by(2) .copied() diff --git a/src/fot/save.rs b/src/fot/save.rs index f3897ee..ba28224 100644 --- a/src/fot/save.rs +++ b/src/fot/save.rs @@ -1,6 +1,6 @@ -use super::decoder::Decoder; +use super::decoder::{Decoder, DecoderCtx}; use super::raw::Raw; -use super::stream::WriteStream; +use super::stream::{ReadStream, WriteStream}; use super::world::World; use anyhow::anyhow; use anyhow::Result; @@ -46,14 +46,15 @@ impl Save { return Err(anyhow!("Unable to determine world block size")); } - let world = World::decode(&raw, world_offset, world_size)?; + let mut rd = ReadStream::new(&raw, world_offset); + let world = World::decode(&mut rd, (world_offset, world_size))?; Ok(Save { raw, world }) } pub fn save(&self, path: &Path) -> Result<()> { let raw = { let mut wd = WriteStream::new(0); - wd.write(&self.world)?; + wd.write_ctx(&self.world, ())?; wd.into_raw(self.world.offset, self.world.size) }; self.raw.assemble_file(path, vec![raw])?; diff --git a/src/fot/sgd.rs b/src/fot/sgd.rs index 29a6503..d3996b8 100644 --- a/src/fot/sgd.rs +++ b/src/fot/sgd.rs @@ -1,6 +1,5 @@ use super::decoder::Decoder; use super::fstring::FString; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use super::tag::Tag; use anyhow::Result; @@ -15,16 +14,16 @@ pub struct SGD { } impl Decoder for SGD { - fn decode(raw: &Raw, offset: usize, _: usize) -> Result { - let mut rd = ReadStream::new(raw, offset); - let tag: Tag = rd.read(0)?; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let offset = rd.offset(); + let tag: Tag = rd.read()?; let unk1 = rd.read_bytes(0x48)?; let mut dialogs: IndexMap> = IndexMap::new(); let n = rd.read_u32()? as usize; let mut names: Vec = Vec::with_capacity(n); for _ in 0..n { - names.push(rd.read::(0)?); + names.push(rd.read::()?); } let m = rd.read_u32()? as usize; @@ -33,7 +32,7 @@ impl Decoder for SGD { let k = rd.read_u32()? as usize; let mut lines: Vec = Vec::with_capacity(k); for _ in 0..k { - lines.push(rd.read::(0)?); + lines.push(rd.read::()?); } dialogs.insert(names.remove(0), lines); diff --git a/src/fot/ssg.rs b/src/fot/ssg.rs index ada266d..a49fc2b 100644 --- a/src/fot/ssg.rs +++ b/src/fot/ssg.rs @@ -1,5 +1,4 @@ use super::decoder::Decoder; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use super::tag::Tag; use anyhow::Result; @@ -11,9 +10,8 @@ pub struct SSG { } impl Decoder for SSG { - fn decode(raw: &Raw, offset: usize, _: usize) -> Result { - let mut rd = ReadStream::new(raw, offset); - let tag: Tag = rd.read(0)?; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let tag: Tag = rd.read()?; let unk1 = rd.read_bytes(0x14)?; Ok(SSG { tag, unk1 }) } diff --git a/src/fot/stream.rs b/src/fot/stream.rs index f159c93..77081a8 100644 --- a/src/fot/stream.rs +++ b/src/fot/stream.rs @@ -25,7 +25,19 @@ impl<'a> ReadStream<'a> { self.rdr.set_position(self.rdr.position() + size as u64); } - pub fn as_bytes(&mut self, size: usize) -> Result<&[u8]> { + pub fn size(&self) -> usize { + self.raw.mem.len() + } + + pub fn is_end(&self) -> bool { + self.offset() >= self.size() + } + + pub fn as_byte_arr(&self) -> &[u8] { + &self.raw.mem[self.offset()..] + } + + pub fn as_bytes(&mut self, size: usize) -> Result<&'a [u8]> { if self.offset() + size > self.raw.mem.len() { dbg!(self.offset(), size, self.raw.mem.len()); Err(anyhow!("as_bytes/read_bytes size is bigger than buffer")) @@ -46,20 +58,16 @@ impl<'a> ReadStream<'a> { // read_opt - decode with optional paramters. required for complex structure // with different origins (save / entfile) like entities - pub fn read_opt, DCtx, ECtx>( + pub fn read_ctx, DCtx, ECtx>( &mut self, size: usize, ctx: DCtx, ) -> Result { - let val = T::decode(&self.raw, self.offset(), size, ctx)?; - self.skip(val.get_enc_size()); - Ok(val) + Ok(T::decode(self, ctx)?) } - pub fn read(&mut self, size: usize) -> Result { - let val = T::decode(&self.raw, self.offset(), size)?; - self.skip(val.get_enc_size()); - Ok(val) + pub fn read(&mut self) -> Result { + Ok(T::decode(self)?) } pub fn read_u8(&mut self) -> Result { @@ -120,7 +128,7 @@ impl WriteStream { self.buf.get_mut().reserve(size); } - pub fn write_opt, DCtx, ECtx>( + pub fn write_ctx, DCtx, ECtx>( &mut self, val: &T, ctx: ECtx, diff --git a/src/fot/tag.rs b/src/fot/tag.rs index 58224fd..31ff898 100644 --- a/src/fot/tag.rs +++ b/src/fot/tag.rs @@ -1,5 +1,4 @@ use super::decoder::Decoder; -use super::raw::Raw; use super::stream::{ReadStream, WriteStream}; use anyhow::Result; @@ -10,10 +9,9 @@ pub struct Tag { } impl Decoder for Tag { - fn decode(raw: &Raw, offset: usize, size: usize) -> Result { - let mut rd = ReadStream::new(raw, offset); - let name: String = rd.read(0)?; - let version: String = rd.read(0)?; + fn decode<'a>(rd: &mut ReadStream<'a>) -> Result { + let name: String = rd.read()?; + let version: String = rd.read()?; Ok(Tag { name, version }) } diff --git a/src/fot/world.rs b/src/fot/world.rs index dc82ee1..7025758 100644 --- a/src/fot/world.rs +++ b/src/fot/world.rs @@ -8,10 +8,8 @@ use super::stream::{ReadStream, WriteStream}; use super::tag::Tag; use anyhow::anyhow; use anyhow::Result; -use byteorder::{LittleEndian, WriteBytesExt}; use deflate::deflate_bytes_zlib; use inflate::inflate_bytes_zlib; -use std::io::Cursor; use std::path::Path; @@ -48,11 +46,13 @@ impl World { } } -impl Decoder for World { - fn decode(raw: &Raw, offset: usize, size: usize) -> Result { - let mut enc = ReadStream::new(raw, offset); +pub type WorldOffsetSize = (usize,usize); +impl DecoderCtx for World { + fn decode<'a>(enc: &mut ReadStream<'a>, ctx: WorldOffsetSize) -> Result { + let offset = ctx.0; + let size = ctx.1; - let tag: Tag = enc.read(Self::WORLD_TAG_LEN)?; + let tag: Tag = enc.read()?; let uncompressed_size = enc.read_u32()?; enc.skip(4); @@ -66,11 +66,11 @@ impl Decoder for World { }; let mut rd = ReadStream::new(&data, 0); - let mission: FString = rd.read(0)?; - let sgd: SGD = rd.read(0)?; - let ssg: SSG = rd.read(0)?; + let mission: FString = rd.read()?; + let sgd: SGD = rd.read()?; + let ssg: SSG = rd.read()?; - let entlist: EntityList = rd.read_opt(0, EntityEncoding::World)?; + let entlist: EntityList = rd.read_ctx(0, EntityEncoding::World)?; let unparsed = rd.read_bytes(data.mem.len() - rd.offset())?; @@ -88,20 +88,20 @@ impl Decoder for World { }) } - fn encode(&self, wd: &mut WriteStream) -> Result<()> { + fn encode(&self, wd: &mut WriteStream, _: ()) -> Result<()> { let data = { let mut wd = WriteStream::new(self.uncompressed_size as usize); wd.write(&self.mission)?; wd.write(&self.sgd)?; wd.write(&self.ssg)?; - wd.write_opt(&self.entlist, EntityEncoding::World)?; + wd.write_ctx(&self.entlist, EntityEncoding::World)?; wd.write_bytes(&self.unparsed); let raw = wd.into_raw(0, 0); deflate_bytes_zlib(&raw.mem) }; - + wd.write(&self.tag)?; wd.write_u32(self.uncompressed_size)?; wd.write_u32(self.uncompressed_size)?;