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:
parent
0c04e466af
commit
03dccf3d4d
11 changed files with 91 additions and 90 deletions
|
|
@ -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<()> {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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])?;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,14 +88,14 @@ 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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue