mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/mod.rs')
-rw-r--r--src/data/mod.rs150
1 files changed, 144 insertions, 6 deletions
diff --git a/src/data/mod.rs b/src/data/mod.rs
index 7653c27..2426f44 100644
--- a/src/data/mod.rs
+++ b/src/data/mod.rs
@@ -1,4 +1,9 @@
//! all the IO
+use flate2::{
+ Compress, CompressError, Compression, Decompress, DecompressError, FlushCompress,
+ FlushDecompress, Status,
+};
+use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::str::Utf8Error;
@@ -9,6 +14,7 @@ pub mod dynamic;
pub mod renderer;
pub mod schematic;
+#[derive(Debug)]
pub struct DataRead<'d> {
data: &'d [u8],
}
@@ -59,15 +65,15 @@ impl<'d> DataRead<'d> {
have: self.data.len(),
});
}
- let len = u16::from_be_bytes([self.data[0], self.data[1]]);
- let end = 2 + len as usize;
+ let len = self.read_u16()?;
+ let end = len as usize;
if self.data.len() < end {
return Err(ReadError::Underflow {
need: end,
have: self.data.len(),
});
}
- let result = std::str::from_utf8(&self.data[2..end])?;
+ let result = std::str::from_utf8(&self.data[..end])?;
self.data = &self.data[end..];
Ok(result)
}
@@ -95,14 +101,66 @@ impl<'d> DataRead<'d> {
self.data = &self.data[len..];
Ok(())
}
+
+ pub fn read_map(&mut self, dst: &mut HashMap<String, String>) -> Result<(), ReadError> {
+ let n = self.read_u8()?;
+ for _ in 0..n {
+ let key = self.read_utf()?;
+ let value = self.read_utf()?;
+ dst.insert(key.to_owned(), value.to_owned());
+ }
+ Ok(())
+ }
+
+ pub fn deflate(&mut self) -> Result<Vec<u8>, ReadError> {
+ let mut dec = Decompress::new(true);
+ let mut raw = Vec::<u8>::new();
+ raw.reserve(1024);
+ loop {
+ let t_in = dec.total_in();
+ let t_out = dec.total_out();
+ let res = dec.decompress_vec(self.data, &mut raw, FlushDecompress::Finish)?;
+ if dec.total_in() > t_in {
+ // we have to advance input every time, decompress_vec only knows the output position
+ self.data = &self.data[(dec.total_in() - t_in) as usize..];
+ }
+ match res {
+ // there's no more input (and the flush mode says so), we need to reserve additional space
+ Status::Ok | Status::BufError => (),
+ // input was already at the end, so this is referring to the output
+ Status::StreamEnd => break,
+ }
+ if dec.total_in() == t_in && dec.total_out() == t_out {
+ // protect against looping forever
+ return Err(ReadError::DecompressStall);
+ }
+ raw.reserve(1024);
+ }
+ assert_eq!(dec.total_out() as usize, raw.len());
+ Ok(raw)
+ }
}
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Debug)]
pub enum ReadError {
+ DecompressStall,
+ Decompress(DecompressError),
Underflow { need: usize, have: usize },
Utf8(Utf8Error),
}
+impl PartialEq for ReadError {
+ fn eq(&self, _: &Self) -> bool {
+ return false;
+ }
+}
+
+impl From<DecompressError> for ReadError {
+ fn from(value: DecompressError) -> Self {
+ Self::Decompress(value)
+ }
+}
+
impl From<Utf8Error> for ReadError {
fn from(err: Utf8Error) -> Self {
Self::Utf8(err)
@@ -115,6 +173,8 @@ impl fmt::Display for ReadError {
Self::Underflow { need, have } => {
write!(f, "buffer underflow (expected {need} but got {have})")
}
+ Self::Decompress(..) => f.write_str("zlib decompression failed"),
+ Self::DecompressStall => f.write_str("decompressor stalled before completion"),
Self::Utf8(..) => f.write_str("malformed utf-8 in string"),
}
}
@@ -124,6 +184,7 @@ impl Error for ReadError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Utf8(e) => Some(e),
+ Self::Decompress(e) => Some(e),
_ => None,
}
}
@@ -217,6 +278,55 @@ impl<'d> DataWrite<'d> {
WriteBuff::Vec(v) => v,
}
}
+
+ pub fn inflate(self, to: &mut DataWrite) -> Result<(), WriteError> {
+ // compress into the provided buffer
+ let WriteBuff::Vec( raw) = self.data else { unreachable!("write buffer not owned") };
+ let mut comp = Compress::new(Compression::default(), true);
+ // compress the immediate buffer into a temp buffer to copy it to buff? no thanks
+ match to.data {
+ WriteBuff::Ref {
+ raw: ref mut dst,
+ ref mut pos,
+ } => {
+ match comp.compress(&raw, &mut dst[*pos..], FlushCompress::Finish)? {
+ // there's no more input (and the flush mode says so), but we can't resize the output
+ Status::Ok | Status::BufError => {
+ return Err(WriteError::CompressEof(
+ raw.len() - comp.total_in() as usize,
+ ))
+ }
+ Status::StreamEnd => (),
+ }
+ }
+ WriteBuff::Vec(ref mut dst) => {
+ let mut input = raw.as_ref();
+ dst.reserve(1024);
+ loop {
+ let t_in = comp.total_in();
+ let t_out = comp.total_out();
+ let res = comp.compress_vec(input, dst, FlushCompress::Finish)?;
+ if comp.total_in() > t_in {
+ // we have to advance input every time, compress_vec only knows the output position
+ input = &input[(comp.total_in() - t_in) as usize..];
+ }
+ match res {
+ // there's no more input (and the flush mode says so), we need to reserve additional space
+ Status::Ok | Status::BufError => (),
+ // input was already at the end, so this is referring to the output
+ Status::StreamEnd => break,
+ }
+ if comp.total_in() == t_in && comp.total_out() == t_out {
+ // protect against looping forever
+ return Err(WriteError::CompressStall);
+ }
+ dst.reserve(1024);
+ }
+ }
+ }
+ assert_eq!(comp.total_in() as usize, raw.len());
+ Ok(())
+ }
}
impl Default for DataWrite<'static> {
@@ -227,10 +337,25 @@ impl Default for DataWrite<'static> {
}
}
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Debug)]
pub enum WriteError {
Overflow { need: usize, have: usize },
TooLong { len: usize },
+ Compress(CompressError),
+ CompressEof(usize),
+ CompressStall,
+}
+
+impl From<CompressError> for WriteError {
+ fn from(value: CompressError) -> Self {
+ Self::Compress(value)
+ }
+}
+
+impl PartialEq for WriteError {
+ fn eq(&self, _: &Self) -> bool {
+ return false;
+ }
}
impl fmt::Display for WriteError {
@@ -239,12 +364,25 @@ impl fmt::Display for WriteError {
Self::Overflow { need, have } => {
write!(f, "buffer overflow (expected {need} but got {have})")
}
+ Self::Compress(..) => f.write_str("zlib compression failed"),
+ Self::CompressEof(remain) => write!(
+ f,
+ "compression overflow with {remain} bytes of input remaining"
+ ),
+ Self::CompressStall => f.write_str("compressor stalled before completion"),
Self::TooLong { len } => write!(f, "string too long ({len} bytes of {})", u16::MAX),
}
}
}
-impl Error for WriteError {}
+impl Error for WriteError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::Compress(e) => Some(e),
+ _ => None,
+ }
+ }
+}
impl<'d> From<&'d mut [u8]> for DataWrite<'d> {
fn from(value: &'d mut [u8]) -> Self {
A45] text-[#a3a29c] text-end"> 2963
ui-atom.h
-rw-r--r--
112
ui-blob.c
-rw-r--r--
1677
ui-blob.h
-rw-r--r--
137
ui-clone.c
-rw-r--r--
2414
ui-clone.h
-rw-r--r--
211
ui-commit.c
-rw-r--r--
2956
ui-commit.h
-rw-r--r--
109
ui-diff.c
-rw-r--r--
7757
ui-diff.h
-rw-r--r--
259
ui-log.c
-rw-r--r--
5786
ui-log.h
-rw-r--r--
237
ui-patch.c
-rw-r--r--
3079
ui-patch.h
-rw-r--r--
105
ui-plain.c
-rw-r--r--
1687
ui-plain.h
-rw-r--r--
120
ui-refs.c
-rw-r--r--
5356
ui-refs.h
-rw-r--r--
182
ui-repolist.c
-rw-r--r--
6259
ui-repolist.h
-rw-r--r--
146
ui-shared.c
-rw-r--r--
18096
ui-shared.h
-rw-r--r--
2372
ui-snapshot.c
-rw-r--r--
5539
ui-snapshot.h
-rw-r--r--
191
ui-stats.c
-rw-r--r--
9612
ui-stats.h
-rw-r--r--
582
ui-summary.c
-rw-r--r--
1689
ui-summary.h
-rw-r--r--
142
ui-tag.c
-rw-r--r--
1981
ui-tag.h
-rw-r--r--
101
ui-tree.c
-rw-r--r--
5138
ui-tree.h
-rw-r--r--
119
README.md