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