1use flate2::{
3 Compress, CompressError as CError, Compression, Decompress, DecompressError as DError,
4 FlushCompress, FlushDecompress, Status,
5};
6use std::collections::HashMap;
7use std::error::Error;
8use std::fmt;
9use std::str::Utf8Error;
10use thiserror::Error;
11
12pub(crate) mod autotile;
13mod base64;
14pub mod command;
15pub mod dynamic;
16pub mod entity_mapping;
17pub mod map;
18pub mod planet;
19pub mod renderer;
20pub mod schematic;
21pub mod sector;
22pub mod weather;
23
24#[derive(Debug)]
25pub struct DataRead<'d> {
26 pub(crate) data: &'d [u8],
27 read: usize,
29}
30
31impl fmt::Display for DataRead<'_> {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 write!(f, "{}", String::from_utf8_lossy(self.data))
34 }
35}
36
37macro_rules! make_read {
38 ($name:ident, $type:ty) => {
39 pub fn $name(&mut self) -> Result<$type, ReadError> {
40 const LEN: usize = std::mem::size_of::<$type>();
41 let output = self.readN::<LEN>()?;
42 Ok(<$type>::from_be_bytes(output))
43 }
44 };
45}
46
47impl<'d> DataRead<'d> {
48 #[must_use]
49 pub const fn new(data: &'d [u8]) -> Self {
50 Self { data, read: 0 }
51 }
52
53 pub fn read_bool(&mut self) -> Result<bool, ReadError> {
54 Ok(self.read_u8()? != 0)
55 }
56
57 make_read!(read_u8, u8);
58 make_read!(read_i8, i8);
59 make_read!(read_u16, u16);
60 make_read!(read_i16, i16);
61 make_read!(read_u32, u32);
62 make_read!(read_i32, i32);
63 make_read!(read_f32, f32);
64 make_read!(read_u64, u64);
65 make_read!(read_i64, i64);
66 make_read!(read_f64, f64);
67
68 pub fn read_utf(&mut self) -> Result<&'d str, ReadError> {
69 let len = self.read_u16()?;
70 let result = std::str::from_utf8(self.eat(len as usize)?)?;
71 Ok(result)
72 }
73
74 pub fn eat(&mut self, n: usize) -> Result<&'d [u8], ReadError> {
75 self.data
76 .split_off(..n)
77 .ok_or(ReadError::Underflow {
78 need: n,
79 have: self.data.len(),
80 })
81 .inspect(|_| self.read += n)
82 }
83
84 #[allow(non_snake_case)]
85 pub fn readN<const N: usize>(&mut self) -> Result<[u8; N], ReadError> {
86 self.eat(N).map(|x| x.try_into().unwrap())
87 }
88
89 pub fn read_bytes(&mut self, dst: &mut [u8]) -> Result<(), ReadError> {
90 dst.copy_from_slice(self.eat(dst.len())?);
91 Ok(())
92 }
93
94 pub fn skip(&mut self, n: usize) -> Result<(), ReadError> {
95 self.data = self.data.get(n..).ok_or(ReadError::Underflow {
96 need: n,
97 have: self.data.len(),
98 })?;
99 self.read += n;
100 Ok(())
101 }
102
103 pub fn read_chunk<E: Error + From<ReadError>, T>(
104 &mut self,
105 big: bool,
106 f: impl FnOnce(&mut DataRead) -> Result<T, E>,
107 ) -> Result<T, E> {
108 let len = if big {
109 self.read_u32()? as usize
110 } else {
111 self.read_u16()? as usize
112 };
113 let rb4 = self.read;
114 let r = f(self);
115 let read = self.read - rb4;
116 match r {
117 Err(e) => {
118 assert!(len >= read, "overread; supposed to read {len}; read {read}");
120 let n = len - read;
121 if n != 0 {
122 #[cfg(debug_assertions)]
123 println!("supposed to read {len}; read {read} - skipping excess");
124 self.skip(n)?;
125 };
126 Err(e)
127 }
128 Ok(v) => {
129 debug_assert!(len >= read, "overread; supposed to read {len}; read {read}");
130 debug_assert!((len - read) == 0, "supposed to read {len}; read {read}");
131 Ok(v)
132 }
133 }
134 }
135
136 pub fn read_vec(&mut self, dst: &mut Vec<u8>, len: usize) -> Result<(), ReadError> {
137 dst.extend_from_slice(self.eat(len)?);
138 Ok(())
139 }
140
141 pub fn read_map(&mut self, dst: &mut HashMap<String, String>) -> Result<(), ReadError> {
142 let n = self.read_u8()?;
143 for _ in 0..n {
144 let key = self.read_utf()?;
145 let value = self.read_utf()?;
146 dst.insert(key.to_owned(), value.to_owned());
147 }
148 Ok(())
149 }
150
151 pub fn deflate(&mut self) -> Result<Vec<u8>, DecompressError> {
152 let mut dec = Decompress::new(true);
153 let mut raw = Vec::with_capacity(1024);
154 loop {
155 let t_in = dec.total_in();
156 let t_out = dec.total_out();
157 let res = dec.decompress_vec(self.data, &mut raw, FlushDecompress::None)?;
158 if dec.total_in() > t_in {
159 self.data = &self.data[(dec.total_in() - t_in) as usize..];
161 }
162 match res {
163 Status::Ok | Status::BufError => {}
165 Status::StreamEnd => break,
167 }
168 if dec.total_in() == t_in && dec.total_out() == t_out {
169 return Err(DecompressError::DecompressStall);
171 }
172 raw.reserve(1024);
173 }
174 assert_eq!(dec.total_out() as usize, raw.len());
175 self.read = 0;
176 Ok(raw)
177 }
178}
179
180#[derive(Debug, Error)]
181pub enum DecompressError {
182 #[error("zlib decompression failed")]
183 Decompress(#[from] DError),
184 #[error("decompressor stalled before completion")]
185 DecompressStall,
186}
187
188#[derive(Debug, Error)]
189pub enum ReadError {
190 #[error("buffer underflow (expected {need} but got {have})")]
191 Underflow { need: usize, have: usize },
192 #[error("expected {0}")]
193 Expected(&'static str),
194 #[error("malformed utf8 in string")]
195 Utf8 {
196 #[from]
197 source: Utf8Error,
198 },
199}
200
201impl PartialEq for ReadError {
202 fn eq(&self, _: &Self) -> bool {
203 false
204 }
205}
206
207enum WriteBuff<'d> {
208 Ref { raw: &'d mut [u8], pos: usize },
210 Vec(Vec<u8>),
211}
212
213impl<'d> WriteBuff<'d> {
214 fn check_capacity(&self, need: usize) -> Result<(), WriteError> {
215 match self {
216 Self::Ref { raw, pos } if raw.len() - pos < need => Err(WriteError::Overflow {
217 need,
218 have: raw.len() - pos,
219 }),
220 _ => Ok(()),
221 }
222 }
223
224 fn write(&mut self, data: &[u8]) {
225 match self {
226 Self::Ref { raw, pos } => {
227 let end = *pos + data.len();
228 raw[*pos..end].copy_from_slice(data);
229 *pos += data.len();
230 }
231 Self::Vec(v) => v.extend_from_slice(data),
232 }
233 }
234}
235
236pub struct DataWrite<'d> {
237 data: WriteBuff<'d>,
238}
239
240macro_rules! make_write {
241 ($name:ident, $type:ty) => {
242 pub fn $name(&mut self, val: $type) -> Result<(), WriteError> {
243 const LEN: usize = std::mem::size_of::<$type>();
244 self.data.check_capacity(LEN)?;
245 self.data.write(&<$type>::to_be_bytes(val));
246 Ok(())
247 }
248 };
249}
250
251impl<'d> DataWrite<'d> {
252 pub fn write_bool(&mut self, val: bool) -> Result<(), WriteError> {
253 self.write_u8(u8::from(val))
254 }
255
256 make_write!(write_u8, u8);
257 make_write!(write_i8, i8);
258 make_write!(write_u16, u16);
259 make_write!(write_i16, i16);
260 make_write!(write_u32, u32);
261 make_write!(write_i32, i32);
262 make_write!(write_f32, f32);
263 make_write!(write_u64, u64);
264 make_write!(write_i64, i64);
265 make_write!(write_f64, f64);
266
267 pub fn write_utf(&mut self, val: &str) -> Result<(), WriteError> {
268 if val.len() > u16::MAX as usize {
269 return Err(WriteError::TooLong { len: val.len() });
270 }
271 self.data.check_capacity(2 + val.len())?;
272 self.data.write(&u16::to_be_bytes(val.len() as u16));
273 self.data.write(val.as_bytes());
274 Ok(())
275 }
276
277 pub fn write_bytes(&mut self, val: &[u8]) -> Result<(), WriteError> {
278 self.data.check_capacity(val.len())?;
279 self.data.write(val);
280 Ok(())
281 }
282
283 #[must_use]
284 pub const fn is_owned(&self) -> bool {
285 matches!(self.data, WriteBuff::Vec(..))
286 }
287
288 #[must_use]
289 pub fn get_written(&self) -> &[u8] {
290 match &self.data {
291 WriteBuff::Ref { raw, pos } => &raw[..*pos],
292 WriteBuff::Vec(v) => v,
293 }
294 }
295
296 #[must_use]
300 pub fn consume(self) -> Vec<u8> {
301 match self.data {
302 WriteBuff::Vec(v) => v,
303 WriteBuff::Ref { .. } => unreachable!(),
304 }
305 }
306
307 pub fn inflate(self, to: &mut DataWrite) -> Result<(), CompressError> {
308 let WriteBuff::Vec(raw) = self.data else {
310 unreachable!("write buffer not owned")
311 };
312 let mut comp = Compress::new(Compression::default(), true);
313 match to.data {
315 WriteBuff::Ref {
316 raw: ref mut dst,
317 ref mut pos,
318 } => {
319 match comp.compress(&raw, &mut dst[*pos..], FlushCompress::Finish)? {
320 Status::Ok | Status::BufError => {
322 return Err(CompressError::CompressEof(
323 raw.len() - comp.total_in() as usize,
324 ))
325 }
326 Status::StreamEnd => (),
327 }
328 }
329 WriteBuff::Vec(ref mut dst) => {
330 let mut input = raw.as_ref();
331 dst.reserve(1024);
332 loop {
333 let t_in = comp.total_in();
334 let t_out = comp.total_out();
335 let res = comp.compress_vec(input, dst, FlushCompress::Finish)?;
336 if comp.total_in() > t_in {
337 input = &input[(comp.total_in() - t_in) as usize..];
339 }
340 match res {
341 Status::Ok | Status::BufError => (),
343 Status::StreamEnd => break,
345 }
346 if comp.total_in() == t_in && comp.total_out() == t_out {
347 return Err(CompressError::CompressStall);
349 }
350 dst.reserve(1024);
351 }
352 }
353 }
354 assert_eq!(comp.total_in() as usize, raw.len());
355 Ok(())
356 }
357}
358
359impl Default for DataWrite<'static> {
360 fn default() -> Self {
361 Self {
362 data: WriteBuff::Vec(Vec::new()),
363 }
364 }
365}
366
367#[derive(Debug, Error)]
368pub enum CompressError {
369 #[error(transparent)]
370 Compress(#[from] CError),
371 #[error("compression overflow with {0} bytes of input remaining")]
372 CompressEof(usize),
373 #[error("compressor stalled before completion")]
374 CompressStall,
375}
376
377#[derive(Debug, Error)]
378pub enum WriteError {
379 #[error("buffer overflow (expected {need} but got {have})")]
380 Overflow { need: usize, have: usize },
381 #[error("string too long ({len} bytes of {})", u16::MAX)]
382 TooLong { len: usize },
383}
384
385impl PartialEq for WriteError {
386 fn eq(&self, _: &Self) -> bool {
387 false
388 }
389}
390
391impl<'d> From<&'d mut [u8]> for DataWrite<'d> {
392 fn from(value: &'d mut [u8]) -> Self {
393 Self {
394 data: WriteBuff::Ref { raw: value, pos: 0 },
395 }
396 }
397}
398
399impl From<Vec<u8>> for DataWrite<'static> {
400 fn from(value: Vec<u8>) -> Self {
401 Self {
402 data: WriteBuff::Vec(value),
403 }
404 }
405}
406
407impl<'d> TryFrom<DataWrite<'d>> for Vec<u8> {
408 type Error = ();
409
410 fn try_from(value: DataWrite<'d>) -> Result<Self, Self::Error> {
411 match value.data {
412 WriteBuff::Vec(v) => Ok(v),
413 WriteBuff::Ref { .. } => Err(()),
414 }
415 }
416}
417pub trait Serializable
419where
420 Self: Sized,
421{
422 type ReadError;
423 type WriteError;
424 fn deserialize(buff: &mut DataRead<'_>) -> Result<Self, Self::ReadError>;
426 fn serialize(&self, buff: &mut DataWrite<'_>) -> Result<(), Self::WriteError>;
428}
429
430#[derive(Clone, Copy, Eq, PartialEq)]
431pub struct GridPos(pub usize, pub usize);
432
433impl From<u32> for GridPos {
434 fn from(value: u32) -> Self {
435 GridPos((value >> 16) as u16 as usize, value as u16 as usize)
436 }
437}
438
439impl From<GridPos> for u32 {
440 fn from(value: GridPos) -> Self {
445 ((value.0 << 16) | value.1) as u32
446 }
447}
448
449impl fmt::Debug for GridPos {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 write!(f, "({0}, {1})", self.0, self.1)
452 }
453}
454
455#[cfg(test)]
456mod test {
457 use super::*;
458
459 #[test]
460 fn read() {
461 let mut read = DataRead::new("Thé qûick ઉrown fox 🦘 over\0\rthe lazy dog.".as_bytes());
462 assert_eq!(read.read_u8(), Ok(84));
463 assert_eq!(read.read_i8(), Ok(104));
464 assert_eq!(read.read_i8(), Ok(-61));
465 assert_eq!(read.read_u16(), Ok(43296));
466 assert_eq!(read.read_i16(), Ok(29123));
467 assert_eq!(read.read_i16(), Ok(-17559));
468 assert_eq!(read.read_i32(), Ok(1_667_965_152));
469 assert_eq!(read.read_i32(), Ok(-1_433_832_849));
470 assert_eq!(read.read_i64(), Ok(8_605_851_562_280_493_296));
471 assert_eq!(read.read_i64(), Ok(-6_942_694_510_468_635_278));
472 assert_eq!(read.read_utf(), Ok("the lazy dog."));
473 }
474
475 #[test]
476 fn write() {
477 let mut write = DataWrite::default();
478 assert_eq!(write.write_u8(84), Ok(()));
479 assert_eq!(write.write_i8(104), Ok(()));
480 assert_eq!(write.write_i8(-61), Ok(()));
481 assert_eq!(write.write_u16(43296), Ok(()));
482 assert_eq!(write.write_i16(29123), Ok(()));
483 assert_eq!(write.write_i16(-17559), Ok(()));
484 assert_eq!(write.write_i32(1_667_965_152), Ok(()));
485 assert_eq!(write.write_i32(-1_433_832_849), Ok(()));
486 assert_eq!(write.write_i64(8_605_851_562_280_493_296), Ok(()));
487 assert_eq!(write.write_i64(-6_942_694_510_468_635_278), Ok(()));
488 assert_eq!(write.write_utf("the lazy dog."), Ok(()));
489 assert_eq!(
490 write.get_written(),
491 "Thé qûick ઉrown fox 🦘 over\0\rthe lazy dog.".as_bytes()
492 );
493 }
494}