mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/mod.rs')
-rw-r--r--src/data/mod.rs160
1 files changed, 84 insertions, 76 deletions
diff --git a/src/data/mod.rs b/src/data/mod.rs
index 2426f44..589a33c 100644
--- a/src/data/mod.rs
+++ b/src/data/mod.rs
@@ -7,16 +7,29 @@ use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::str::Utf8Error;
+use thiserror::Error;
mod base64;
mod command;
pub mod dynamic;
+pub mod map;
+pub mod planet;
pub mod renderer;
pub mod schematic;
+pub mod sector;
+pub mod weather;
#[derive(Debug)]
pub struct DataRead<'d> {
data: &'d [u8],
+ // used with read_chunk
+ read: usize,
+}
+
+impl fmt::Display for DataRead<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", String::from_utf8_lossy(self.data))
+ }
}
macro_rules! make_read {
@@ -32,6 +45,7 @@ macro_rules! make_read {
let mut output = [0u8; LEN];
output.copy_from_slice(&self.data[..LEN]);
self.data = &self.data[LEN..];
+ self.read += LEN;
Ok(<$type>::from_be_bytes(output))
}
};
@@ -40,7 +54,7 @@ macro_rules! make_read {
impl<'d> DataRead<'d> {
#[must_use]
pub fn new(data: &'d [u8]) -> Self {
- Self { data }
+ Self { data, read: 0 }
}
pub fn read_bool(&mut self) -> Result<bool, ReadError> {
@@ -75,6 +89,7 @@ impl<'d> DataRead<'d> {
}
let result = std::str::from_utf8(&self.data[..end])?;
self.data = &self.data[end..];
+ self.read += end;
Ok(result)
}
@@ -87,9 +102,48 @@ impl<'d> DataRead<'d> {
}
dst.copy_from_slice(&self.data[..dst.len()]);
self.data = &self.data[dst.len()..];
+ self.read += dst.len();
Ok(())
}
+ pub fn skip(&mut self, n: usize) -> Result<(), ReadError> {
+ if self.data.len() < n {
+ return Err(ReadError::Underflow {
+ need: n,
+ have: self.data.len(),
+ });
+ }
+ self.data = &self.data[n..];
+ self.read += n;
+ Ok(())
+ }
+
+ pub fn skip_chunk(&mut self) -> Result<usize, ReadError> {
+ let len = self.read_u32()? as usize;
+ self.skip(len)?;
+ Ok(len)
+ }
+
+ pub fn read_chunk<E>(&mut self, f: impl FnOnce(&mut DataRead) -> Result<(), E>) -> Result<(), E>
+ where
+ E: Error + From<ReadError>,
+ {
+ let len = self.read_u32()? as usize;
+ self.read = 0;
+ let r = f(self);
+ match r {
+ Err(e) => {
+ // skip this chunk
+ let n = len - self.read;
+ if n != 0 {
+ self.skip(n)?;
+ };
+ Err(e)
+ }
+ Ok(_) => Ok(()),
+ }
+ }
+
pub fn read_vec(&mut self, dst: &mut Vec<u8>, len: usize) -> Result<(), ReadError> {
if self.data.len() < len {
return Err(ReadError::Underflow {
@@ -99,6 +153,7 @@ impl<'d> DataRead<'d> {
}
dst.extend_from_slice(&self.data[..len]);
self.data = &self.data[len..];
+ self.read += len;
Ok(())
}
@@ -137,56 +192,31 @@ impl<'d> DataRead<'d> {
raw.reserve(1024);
}
assert_eq!(dec.total_out() as usize, raw.len());
+ self.read = 0;
Ok(raw)
}
}
-#[derive(Debug)]
+#[derive(Debug, Error)]
pub enum ReadError {
+ #[error("decompressor stalled before completion")]
DecompressStall,
- Decompress(DecompressError),
+ #[error("zlib decompession failed")]
+ Decompress(#[from] DecompressError),
+ #[error("buffer underflow (expected {need} but got {have})")]
Underflow { need: usize, have: usize },
- Utf8(Utf8Error),
+ #[error("expected {0}")]
+ Expected(&'static str),
+ #[error("malformed utf8 in string")]
+ Utf8 {
+ #[from]
+ source: 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)
- }
-}
-
-impl fmt::Display for ReadError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- 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"),
- }
- }
-}
-
-impl Error for ReadError {
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- match self {
- Self::Utf8(e) => Some(e),
- Self::Decompress(e) => Some(e),
- _ => None,
- }
+ false
}
}
@@ -281,7 +311,9 @@ impl<'d> DataWrite<'d> {
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 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 {
@@ -337,50 +369,26 @@ impl Default for DataWrite<'static> {
}
}
-#[derive(Debug)]
+#[derive(Debug, Error)]
pub enum WriteError {
+ #[error("buffer overflow (expected {need} but got {have})")]
Overflow { need: usize, have: usize },
+ #[error("string too long ({len} bytes of {})", u16::MAX)]
TooLong { len: usize },
- Compress(CompressError),
+ #[error("zlib compression failed")]
+ Compress {
+ #[from]
+ source: CompressError,
+ },
+ #[error("compression overflow with {0} bytes of input remaining")]
CompressEof(usize),
+ #[error("compressor stalled before completion")]
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 {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- 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 {
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- match self {
- Self::Compress(e) => Some(e),
- _ => None,
- }
+ false
}
}