Decoder::decode now uses ReadStream mut reference instead of raw offset size, therefore less allocations needed, because there is only one ReadStream that being passed around decoders

This commit is contained in:
mykola2312 2023-09-07 16:54:35 +03:00
parent 0c04e466af
commit 03dccf3d4d
11 changed files with 91 additions and 90 deletions

View file

@ -1,27 +1,29 @@
use super::raw::Raw; use super::stream::{ReadStream, WriteStream};
use super::stream::WriteStream; use anyhow::{anyhow, Result};
use anyhow::Result;
use std::str; use std::str;
pub trait Decoder: Sized { pub trait Decoder: Sized {
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self>; fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self>;
fn encode(&self, wd: &mut WriteStream) -> Result<()>; fn encode(&self, wd: &mut WriteStream) -> Result<()>;
fn get_enc_size(&self) -> usize; fn get_enc_size(&self) -> usize;
} }
pub trait DecoderCtx<DCtx, ECtx>: Sized { pub trait DecoderCtx<DCtx, ECtx>: Sized {
fn decode(raw: &Raw, offset: usize, size: usize, ctx: DCtx) -> Result<Self>; fn decode<'a>(rd: &mut ReadStream<'a>, ctx: DCtx) -> Result<Self>;
fn encode(&self, wd: &mut WriteStream, ctx: ECtx) -> Result<()>; fn encode(&self, wd: &mut WriteStream, ctx: ECtx) -> Result<()>;
fn get_enc_size(&self) -> usize; fn get_enc_size(&self) -> usize;
} }
impl Decoder for String { impl Decoder for String {
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let str = &raw.mem[offset..]; let bytes = rd.as_byte_arr();
match str.iter().position(|&c| c == 0) { let pos = match bytes.iter().position(|&c| c == 0) {
Some(pos) => Ok(str::from_utf8(&str[..pos])?.to_string()), Some(pos) => pos,
None => Ok(str::from_utf8(&raw.mem[offset..offset + size])?.to_string()), 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<()> { fn encode(&self, wd: &mut WriteStream) -> Result<()> {

View file

@ -1,7 +1,6 @@
use super::decoder::DecoderCtx; use super::decoder::DecoderCtx;
use super::entitylist::{EntityEncoding, EntityList}; use super::entitylist::{EntityEncoding, EntityList};
use super::esh::ESH; use super::esh::ESH;
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use anyhow::Result; use anyhow::Result;
@ -16,13 +15,13 @@ pub struct Entity {
} }
impl DecoderCtx<&mut EntityList, &EntityList> for Entity { impl DecoderCtx<&mut EntityList, &EntityList> for Entity {
fn decode(raw: &Raw, offset: usize, _: usize, ctx: &mut EntityList) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>, ctx: &mut EntityList) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let offset = rd.offset();
Ok(match ctx.get_entity_encoding() { Ok(match ctx.get_entity_encoding() {
EntityEncoding::File => { EntityEncoding::File => {
let flags = NO_FLAGS; let flags = NO_FLAGS;
let type_idx = ctx.add_or_get_type(rd.read(0)?); let type_idx = ctx.add_or_get_type(rd.read()?);
let esh: ESH = rd.read(0)?; let esh: ESH = rd.read()?;
let enc_size = rd.offset() - offset; let enc_size = rd.offset() - offset;
Entity { Entity {
flags, flags,
@ -35,7 +34,7 @@ impl DecoderCtx<&mut EntityList, &EntityList> for Entity {
let flags = rd.read_u32()?; let flags = rd.read_u32()?;
let type_idx = rd.read_u16()? as usize; let type_idx = rd.read_u16()? as usize;
let esh: Option<ESH> = if type_idx != NO_ESH { let esh: Option<ESH> = if type_idx != NO_ESH {
Some(rd.read(0)?) Some(rd.read()?)
} else { } else {
None None
}; };

View file

@ -1,7 +1,6 @@
use super::decoder::{DecoderCtx, Decoder}; use super::decoder::{DecoderCtx, Decoder};
use super::entity::Entity; use super::entity::Entity;
use super::fstring::{FString, FStringEncoding}; use super::fstring::{FString, FStringEncoding};
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use super::tag::{Tag, CTag}; use super::tag::{Tag, CTag};
use std::path::Path; use std::path::Path;
@ -79,8 +78,8 @@ impl EntityList {
} }
impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList { impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList {
fn decode(raw: &Raw, offset: usize, size: usize, ctx: EntityEncoding) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>, ctx: EntityEncoding) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let offset = rd.offset();
let mut ent_list = EntityList { let mut ent_list = EntityList {
encoding: ctx, encoding: ctx,
entity_file_tag: None, entity_file_tag: None,
@ -94,14 +93,14 @@ impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList {
Ok(match ctx { Ok(match ctx {
EntityEncoding::File => { EntityEncoding::File => {
let mut first = true; let mut first = true;
while rd.offset() < size { while !rd.is_end() {
let tag: Tag = rd.read(0)?; let tag: Tag = rd.read()?;
if first { if first {
ent_list.entity_tag = Some(tag); ent_list.entity_tag = Some(tag);
first = false; 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); ent_list.ents.push(ent);
} }
@ -110,16 +109,16 @@ impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList {
} }
EntityEncoding::World => { 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()?; let type_count = rd.read_u32()?;
for _ in 0..type_count { for _ in 0..type_count {
ent_list.types.push(rd.read(0)?); ent_list.types.push(rd.read()?);
} }
let ent_count = rd.read_u16()?; let ent_count = rd.read_u16()?;
ent_list.unk1 = rd.read_u32()?; ent_list.unk1 = rd.read_u32()?;
for _ in 1..ent_count { 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); ent_list.ents.push(ent);
} }
@ -137,7 +136,7 @@ impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList {
continue; continue;
} }
wd.write(self.get_entity_tag())?; wd.write(self.get_entity_tag())?;
wd.write_opt(ent, &self)?; wd.write_ctx(ent, &self)?;
} }
} }
EntityEncoding::World => { EntityEncoding::World => {
@ -150,7 +149,7 @@ impl DecoderCtx<EntityEncoding, EntityEncoding> for EntityList {
wd.write_u16((self.ents.len() + 1) as u16)?; wd.write_u16((self.ents.len() + 1) as u16)?;
wd.write_u32(self.unk1)?; wd.write_u32(self.unk1)?;
for ent in self.ents.iter() { for ent in self.ents.iter() {
wd.write_opt(ent, &self)?; wd.write_ctx(ent, &self)?;
} }
} }
} }

View file

@ -1,6 +1,5 @@
use super::decoder::Decoder; use super::decoder::Decoder;
use super::fstring::FString; use super::fstring::FString;
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use super::tag::Tag; use super::tag::Tag;
use anyhow::Result; use anyhow::Result;
@ -76,8 +75,8 @@ impl ESHValue {
} }
impl Decoder for ESHValue { impl Decoder for ESHValue {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let offset = rd.offset();
let data_type = rd.read_u32()?; let data_type = rd.read_u32()?;
let data_size = 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_BOOL => ESHValue::Bool(rd.read_u8()? == 1),
Self::TYPE_FLOAT => ESHValue::Float(rd.read_f32()?), Self::TYPE_FLOAT => ESHValue::Float(rd.read_f32()?),
Self::TYPE_INT => ESHValue::Int(rd.read_i32()?), Self::TYPE_INT => ESHValue::Int(rd.read_i32()?),
Self::TYPE_STRING => ESHValue::String(rd.read::<FString>(0)?), Self::TYPE_STRING => ESHValue::String(rd.read::<FString>()?),
Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::<FString>(0)?), Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::<FString>()?),
Self::TYPE_ESBIN => ESHValue::Binary(rd.read_bytes(data_size as usize)?), Self::TYPE_ESBIN => ESHValue::Binary(rd.read_bytes(data_size as usize)?),
Self::TYPE_ENTTITYFLAGS => { Self::TYPE_ENTTITYFLAGS => {
let entity_id = rd.read_u16()?; let entity_id = rd.read_u16()?;
@ -247,15 +246,15 @@ pub struct ESH {
} }
impl Decoder for ESH { impl Decoder for ESH {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let offset = rd.offset();
let tag: Tag = rd.read(0)?; let tag: Tag = rd.read()?;
let n = rd.read_u32()? as usize; let n = rd.read_u32()? as usize;
let mut props: IndexMap<FString, ESHValue> = IndexMap::with_capacity(n); let mut props: IndexMap<FString, ESHValue> = IndexMap::with_capacity(n);
for _ in 0..n { for _ in 0..n {
let name: FString = rd.read(0)?; let name: FString = rd.read()?;
let value: ESHValue = rd.read(0)?; let value: ESHValue = rd.read()?;
props.insert(name, value); props.insert(name, value);
} }

View file

@ -1,13 +1,10 @@
use super::decoder::Decoder; use super::decoder::Decoder;
use super::raw::Raw; use super::stream::{ReadStream, WriteStream};
use super::stream::WriteStream;
use anyhow::Result; use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use encoding_rs::WINDOWS_1251; use encoding_rs::WINDOWS_1251;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::io::Cursor;
// FString - Fallout // FString - Fallout
@ -25,14 +22,14 @@ pub struct FString {
} }
impl Decoder for FString { impl Decoder for FString {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rdr = Cursor::new(&raw.mem[offset..]); //let mut rdr = Cursor::new(&raw.mem[offset..]);
let flen = rdr.read_u32::<LittleEndian>()? as usize; let flen = rd.read_u32()? as usize;
let len = flen & !(1 << 31); let len = flen & !(1 << 31);
let start = offset + 4;
if flen & (1 << 31) == 0 { if flen & (1 << 31) == 0 {
// ANSI // 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 { Ok(FString {
encoding: FStringEncoding::ANSI, encoding: FStringEncoding::ANSI,
enc_len: len, enc_len: len,
@ -40,7 +37,8 @@ impl Decoder for FString {
}) })
} else { } else {
// WCS2 // WCS2
let chars: Vec<u8> = raw.mem[start..start + len * 2] let bytes = rd.as_bytes(len * 2)?;
let chars: Vec<u8> = bytes
.iter() .iter()
.step_by(2) .step_by(2)
.copied() .copied()

View file

@ -1,6 +1,6 @@
use super::decoder::Decoder; use super::decoder::{Decoder, DecoderCtx};
use super::raw::Raw; use super::raw::Raw;
use super::stream::WriteStream; use super::stream::{ReadStream, WriteStream};
use super::world::World; use super::world::World;
use anyhow::anyhow; use anyhow::anyhow;
use anyhow::Result; use anyhow::Result;
@ -46,14 +46,15 @@ impl Save {
return Err(anyhow!("Unable to determine world block size")); 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 }) Ok(Save { raw, world })
} }
pub fn save(&self, path: &Path) -> Result<()> { pub fn save(&self, path: &Path) -> Result<()> {
let raw = { let raw = {
let mut wd = WriteStream::new(0); let mut wd = WriteStream::new(0);
wd.write(&self.world)?; wd.write_ctx(&self.world, ())?;
wd.into_raw(self.world.offset, self.world.size) wd.into_raw(self.world.offset, self.world.size)
}; };
self.raw.assemble_file(path, vec![raw])?; self.raw.assemble_file(path, vec![raw])?;

View file

@ -1,6 +1,5 @@
use super::decoder::Decoder; use super::decoder::Decoder;
use super::fstring::FString; use super::fstring::FString;
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use super::tag::Tag; use super::tag::Tag;
use anyhow::Result; use anyhow::Result;
@ -15,16 +14,16 @@ pub struct SGD {
} }
impl Decoder for SGD { impl Decoder for SGD {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let offset = rd.offset();
let tag: Tag = rd.read(0)?; let tag: Tag = rd.read()?;
let unk1 = rd.read_bytes(0x48)?; let unk1 = rd.read_bytes(0x48)?;
let mut dialogs: IndexMap<FString, Vec<FString>> = IndexMap::new(); let mut dialogs: IndexMap<FString, Vec<FString>> = IndexMap::new();
let n = rd.read_u32()? as usize; let n = rd.read_u32()? as usize;
let mut names: Vec<FString> = Vec::with_capacity(n); let mut names: Vec<FString> = Vec::with_capacity(n);
for _ in 0..n { for _ in 0..n {
names.push(rd.read::<FString>(0)?); names.push(rd.read::<FString>()?);
} }
let m = rd.read_u32()? as usize; let m = rd.read_u32()? as usize;
@ -33,7 +32,7 @@ impl Decoder for SGD {
let k = rd.read_u32()? as usize; let k = rd.read_u32()? as usize;
let mut lines: Vec<FString> = Vec::with_capacity(k); let mut lines: Vec<FString> = Vec::with_capacity(k);
for _ in 0..k { for _ in 0..k {
lines.push(rd.read::<FString>(0)?); lines.push(rd.read::<FString>()?);
} }
dialogs.insert(names.remove(0), lines); dialogs.insert(names.remove(0), lines);

View file

@ -1,5 +1,4 @@
use super::decoder::Decoder; use super::decoder::Decoder;
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use super::tag::Tag; use super::tag::Tag;
use anyhow::Result; use anyhow::Result;
@ -11,9 +10,8 @@ pub struct SSG {
} }
impl Decoder for SSG { impl Decoder for SSG {
fn decode(raw: &Raw, offset: usize, _: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let tag: Tag = rd.read()?;
let tag: Tag = rd.read(0)?;
let unk1 = rd.read_bytes(0x14)?; let unk1 = rd.read_bytes(0x14)?;
Ok(SSG { tag, unk1 }) Ok(SSG { tag, unk1 })
} }

View file

@ -25,7 +25,19 @@ impl<'a> ReadStream<'a> {
self.rdr.set_position(self.rdr.position() + size as u64); 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() { if self.offset() + size > self.raw.mem.len() {
dbg!(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")) 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 // read_opt - decode with optional paramters. required for complex structure
// with different origins (save / entfile) like entities // with different origins (save / entfile) like entities
pub fn read_opt<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>( pub fn read_ctx<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>(
&mut self, &mut self,
size: usize, size: usize,
ctx: DCtx, ctx: DCtx,
) -> Result<T> { ) -> Result<T> {
let val = T::decode(&self.raw, self.offset(), size, ctx)?; Ok(T::decode(self, ctx)?)
self.skip(val.get_enc_size());
Ok(val)
} }
pub fn read<T: Decoder>(&mut self, size: usize) -> Result<T> { pub fn read<T: Decoder>(&mut self) -> Result<T> {
let val = T::decode(&self.raw, self.offset(), size)?; Ok(T::decode(self)?)
self.skip(val.get_enc_size());
Ok(val)
} }
pub fn read_u8(&mut self) -> Result<u8> { pub fn read_u8(&mut self) -> Result<u8> {
@ -120,7 +128,7 @@ impl WriteStream {
self.buf.get_mut().reserve(size); self.buf.get_mut().reserve(size);
} }
pub fn write_opt<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>( pub fn write_ctx<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>(
&mut self, &mut self,
val: &T, val: &T,
ctx: ECtx, ctx: ECtx,

View file

@ -1,5 +1,4 @@
use super::decoder::Decoder; use super::decoder::Decoder;
use super::raw::Raw;
use super::stream::{ReadStream, WriteStream}; use super::stream::{ReadStream, WriteStream};
use anyhow::Result; use anyhow::Result;
@ -10,10 +9,9 @@ pub struct Tag {
} }
impl Decoder for Tag { impl Decoder for Tag {
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> { fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset); let name: String = rd.read()?;
let name: String = rd.read(0)?; let version: String = rd.read()?;
let version: String = rd.read(0)?;
Ok(Tag { name, version }) Ok(Tag { name, version })
} }

View file

@ -8,10 +8,8 @@ use super::stream::{ReadStream, WriteStream};
use super::tag::Tag; use super::tag::Tag;
use anyhow::anyhow; use anyhow::anyhow;
use anyhow::Result; use anyhow::Result;
use byteorder::{LittleEndian, WriteBytesExt};
use deflate::deflate_bytes_zlib; use deflate::deflate_bytes_zlib;
use inflate::inflate_bytes_zlib; use inflate::inflate_bytes_zlib;
use std::io::Cursor;
use std::path::Path; use std::path::Path;
@ -48,11 +46,13 @@ impl World {
} }
} }
impl Decoder for World { pub type WorldOffsetSize = (usize,usize);
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> { impl DecoderCtx<WorldOffsetSize,()> for World {
let mut enc = ReadStream::new(raw, offset); fn decode<'a>(enc: &mut ReadStream<'a>, ctx: WorldOffsetSize) -> Result<Self> {
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()?; let uncompressed_size = enc.read_u32()?;
enc.skip(4); enc.skip(4);
@ -66,11 +66,11 @@ impl Decoder for World {
}; };
let mut rd = ReadStream::new(&data, 0); let mut rd = ReadStream::new(&data, 0);
let mission: FString = rd.read(0)?; let mission: FString = rd.read()?;
let sgd: SGD = rd.read(0)?; let sgd: SGD = rd.read()?;
let ssg: SSG = rd.read(0)?; 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())?; let unparsed = rd.read_bytes(data.mem.len() - rd.offset())?;
@ -88,14 +88,14 @@ impl Decoder for World {
}) })
} }
fn encode(&self, wd: &mut WriteStream) -> Result<()> { fn encode(&self, wd: &mut WriteStream, _: ()) -> Result<()> {
let data = { let data = {
let mut wd = WriteStream::new(self.uncompressed_size as usize); let mut wd = WriteStream::new(self.uncompressed_size as usize);
wd.write(&self.mission)?; wd.write(&self.mission)?;
wd.write(&self.sgd)?; wd.write(&self.sgd)?;
wd.write(&self.ssg)?; wd.write(&self.ssg)?;
wd.write_opt(&self.entlist, EntityEncoding::World)?; wd.write_ctx(&self.entlist, EntityEncoding::World)?;
wd.write_bytes(&self.unparsed); wd.write_bytes(&self.unparsed);
let raw = wd.into_raw(0, 0); let raw = wd.into_raw(0, 0);