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::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<Self>;
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self>;
fn encode(&self, wd: &mut WriteStream) -> Result<()>;
fn get_enc_size(&self) -> usize;
}
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 get_enc_size(&self) -> usize;
}
impl Decoder for String {
fn decode(raw: &Raw, offset: usize, size: usize) -> Result<Self> {
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<Self> {
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<()> {

View file

@ -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<Self> {
let mut rd = ReadStream::new(raw, offset);
fn decode<'a>(rd: &mut ReadStream<'a>, ctx: &mut EntityList) -> Result<Self> {
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<ESH> = if type_idx != NO_ESH {
Some(rd.read(0)?)
Some(rd.read()?)
} else {
None
};

View file

@ -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<EntityEncoding, EntityEncoding> for EntityList {
fn decode(raw: &Raw, offset: usize, size: usize, ctx: EntityEncoding) -> Result<Self> {
let mut rd = ReadStream::new(raw, offset);
fn decode<'a>(rd: &mut ReadStream<'a>, ctx: EntityEncoding) -> Result<Self> {
let offset = rd.offset();
let mut ent_list = EntityList {
encoding: ctx,
entity_file_tag: None,
@ -94,14 +93,14 @@ impl DecoderCtx<EntityEncoding, EntityEncoding> 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<EntityEncoding, EntityEncoding> 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<EntityEncoding, EntityEncoding> 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<EntityEncoding, EntityEncoding> 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)?;
}
}
}

View file

@ -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<Self> {
let mut rd = ReadStream::new(raw, offset);
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
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::<FString>(0)?),
Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::<FString>(0)?),
Self::TYPE_STRING => ESHValue::String(rd.read::<FString>()?),
Self::TYPE_SPRITE => ESHValue::Sprite(rd.read::<FString>()?),
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<Self> {
let mut rd = ReadStream::new(raw, offset);
let tag: Tag = rd.read(0)?;
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let offset = rd.offset();
let tag: Tag = rd.read()?;
let n = rd.read_u32()? as usize;
let mut props: IndexMap<FString, ESHValue> = 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);
}

View file

@ -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<Self> {
let mut rdr = Cursor::new(&raw.mem[offset..]);
let flen = rdr.read_u32::<LittleEndian>()? as usize;
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
//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<u8> = raw.mem[start..start + len * 2]
let bytes = rd.as_bytes(len * 2)?;
let chars: Vec<u8> = bytes
.iter()
.step_by(2)
.copied()

View file

@ -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])?;

View file

@ -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<Self> {
let mut rd = ReadStream::new(raw, offset);
let tag: Tag = rd.read(0)?;
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let offset = rd.offset();
let tag: Tag = rd.read()?;
let unk1 = rd.read_bytes(0x48)?;
let mut dialogs: IndexMap<FString, Vec<FString>> = IndexMap::new();
let n = rd.read_u32()? as usize;
let mut names: Vec<FString> = Vec::with_capacity(n);
for _ in 0..n {
names.push(rd.read::<FString>(0)?);
names.push(rd.read::<FString>()?);
}
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<FString> = Vec::with_capacity(k);
for _ in 0..k {
lines.push(rd.read::<FString>(0)?);
lines.push(rd.read::<FString>()?);
}
dialogs.insert(names.remove(0), lines);

View file

@ -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<Self> {
let mut rd = ReadStream::new(raw, offset);
let tag: Tag = rd.read(0)?;
fn decode<'a>(rd: &mut ReadStream<'a>) -> Result<Self> {
let tag: Tag = rd.read()?;
let unk1 = rd.read_bytes(0x14)?;
Ok(SSG { tag, unk1 })
}

View file

@ -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<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>(
pub fn read_ctx<T: DecoderCtx<DCtx, ECtx>, DCtx, ECtx>(
&mut self,
size: usize,
ctx: DCtx,
) -> Result<T> {
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<T: Decoder>(&mut self, size: usize) -> Result<T> {
let val = T::decode(&self.raw, self.offset(), size)?;
self.skip(val.get_enc_size());
Ok(val)
pub fn read<T: Decoder>(&mut self) -> Result<T> {
Ok(T::decode(self)?)
}
pub fn read_u8(&mut self) -> Result<u8> {
@ -120,7 +128,7 @@ impl WriteStream {
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,
val: &T,
ctx: ECtx,

View file

@ -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<Self> {
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<Self> {
let name: String = rd.read()?;
let version: String = rd.read()?;
Ok(Tag { name, version })
}

View file

@ -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<Self> {
let mut enc = ReadStream::new(raw, offset);
pub type WorldOffsetSize = (usize,usize);
impl DecoderCtx<WorldOffsetSize,()> for World {
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()?;
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)?;