azalea_buf/
read.rs

1use std::{
2    backtrace::Backtrace,
3    collections::HashMap,
4    hash::Hash,
5    io::{self, Cursor, Read},
6    sync::Arc,
7};
8
9use byteorder::{BE, ReadBytesExt};
10use indexmap::IndexMap;
11use thiserror::Error;
12use tracing::warn;
13
14use super::{MAX_STRING_LENGTH, UnsizedByteArray};
15
16#[derive(Error, Debug)]
17pub enum BufReadError {
18    #[error("Invalid VarInt")]
19    InvalidVarInt,
20    #[error("Invalid VarLong")]
21    InvalidVarLong,
22    #[error("Error reading bytes")]
23    CouldNotReadBytes,
24    #[error(
25        "The received encoded string buffer length is longer than maximum allowed ({length} > {max_length})"
26    )]
27    StringLengthTooLong { length: u32, max_length: u32 },
28    #[error("The received Vec length is longer than maximum allowed ({length} > {max_length})")]
29    VecLengthTooLong { length: u32, max_length: u32 },
30    #[error("{source}")]
31    Io {
32        #[from]
33        #[backtrace]
34        source: io::Error,
35    },
36    #[error("Invalid UTF-8: {bytes:?} (lossy: {lossy:?})")]
37    InvalidUtf8 {
38        bytes: Vec<u8>,
39        lossy: String,
40        // backtrace: Backtrace,
41    },
42    #[error("Unexpected enum variant {id}")]
43    UnexpectedEnumVariant { id: i32 },
44    #[error("Unexpected enum variant {id}")]
45    UnexpectedStringEnumVariant { id: String },
46    #[error("Tried to read {attempted_read} bytes but there were only {actual_read}")]
47    UnexpectedEof {
48        attempted_read: usize,
49        actual_read: usize,
50        backtrace: Backtrace,
51    },
52    #[error("{0}")]
53    Custom(String),
54    #[cfg(feature = "serde_json")]
55    #[error("{source}")]
56    Deserialization {
57        #[from]
58        #[backtrace]
59        source: serde_json::Error,
60    },
61    #[error("{source}")]
62    Nbt {
63        #[from]
64        #[backtrace]
65        source: simdnbt::Error,
66    },
67    #[error("{source}")]
68    DeserializeNbt {
69        #[from]
70        #[backtrace]
71        source: simdnbt::DeserializeError,
72    },
73}
74
75fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8], BufReadError> {
76    if length > (buf.get_ref().len() - buf.position() as usize) {
77        return Err(BufReadError::UnexpectedEof {
78            attempted_read: length,
79            actual_read: buf.get_ref().len() - buf.position() as usize,
80            backtrace: Backtrace::capture(),
81        });
82    }
83    let initial_position = buf.position() as usize;
84    buf.set_position(buf.position() + length as u64);
85    let data = &buf.get_ref()[initial_position..initial_position + length];
86    Ok(data)
87}
88
89fn read_utf_with_len(buf: &mut Cursor<&[u8]>, max_length: u32) -> Result<String, BufReadError> {
90    let length = u32::azalea_read_var(buf)?;
91    // i don't know why it's multiplied by 4 but it's like that in mojang's code so
92    if length > max_length * 4 {
93        return Err(BufReadError::StringLengthTooLong {
94            length,
95            max_length: max_length * 4,
96        });
97    }
98
99    let buffer = read_bytes(buf, length as usize)?;
100    let string = std::str::from_utf8(buffer)
101        .map_err(|_| BufReadError::InvalidUtf8 {
102            bytes: buffer.to_vec(),
103            lossy: String::from_utf8_lossy(buffer).to_string(),
104            // backtrace: Backtrace::capture(),
105        })?
106        .to_string();
107    if string.len() > length as usize {
108        return Err(BufReadError::StringLengthTooLong { length, max_length });
109    }
110
111    Ok(string)
112}
113
114pub trait AzaleaRead
115where
116    Self: Sized,
117{
118    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>;
119}
120
121pub trait AzaleaReadVar
122where
123    Self: Sized,
124{
125    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>;
126}
127
128// note that there's no Write equivalent for this trait since we don't really
129// care if we're writing over the limit (and maybe we already know that the
130// server implementation accepts it)
131pub trait AzaleaReadLimited
132where
133    Self: Sized,
134{
135    fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: usize) -> Result<Self, BufReadError>;
136}
137
138impl AzaleaRead for () {
139    fn azalea_read(_buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
140        Ok(())
141    }
142}
143
144impl AzaleaRead for i32 {
145    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
146        Ok(buf.read_i32::<BE>()?)
147    }
148}
149
150impl AzaleaReadVar for i32 {
151    /// Read a single varint from the reader and return the value
152    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
153        // fast varint impl based on https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67
154        let mut buffer = [0];
155        let mut ans = 0;
156        for i in 0..5 {
157            buf.read_exact(&mut buffer)?;
158            ans |= ((buffer[0] & 0b0111_1111) as i32) << (7 * i);
159            if buffer[0] & 0b1000_0000 == 0 {
160                break;
161            }
162        }
163        Ok(ans)
164    }
165}
166
167impl AzaleaReadVar for i64 {
168    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
169        let mut buffer = [0];
170        let mut ans = 0;
171        for i in 0..10 {
172            buf.read_exact(&mut buffer)
173                .map_err(|_| BufReadError::InvalidVarLong)?;
174            ans |= ((buffer[0] & 0b0111_1111) as i64) << (7 * i);
175            if buffer[0] & 0b1000_0000 == 0 {
176                break;
177            }
178        }
179        Ok(ans)
180    }
181}
182impl AzaleaReadVar for u64 {
183    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
184        i64::azalea_read_var(buf).map(|i| i as u64)
185    }
186}
187
188impl AzaleaRead for UnsizedByteArray {
189    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
190        // read to end of the buffer
191        let data = buf.get_ref()[buf.position() as usize..].to_vec();
192        buf.set_position((buf.position()) + data.len() as u64);
193        Ok(UnsizedByteArray(data))
194    }
195}
196
197macro_rules! impl_for_map_type {
198    ($ty: ident) => {
199        impl<K: AzaleaRead + Send + Eq + Hash, V: AzaleaRead + Send> AzaleaRead for $ty<K, V> {
200            fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
201                let length = i32::azalea_read_var(buf)? as usize;
202                let mut contents = Self::with_capacity(usize::min(length, 65536));
203                for _ in 0..length {
204                    contents.insert(K::azalea_read(buf)?, V::azalea_read(buf)?);
205                }
206                Ok(contents)
207            }
208        }
209        impl<K: AzaleaRead + Send + Eq + Hash, V: AzaleaReadVar + Send> AzaleaReadVar
210            for $ty<K, V>
211        {
212            fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
213                let length = i32::azalea_read_var(buf)? as usize;
214                let mut contents = Self::with_capacity(usize::min(length, 65536));
215                for _ in 0..length {
216                    contents.insert(K::azalea_read(buf)?, V::azalea_read_var(buf)?);
217                }
218                Ok(contents)
219            }
220        }
221    };
222}
223
224impl_for_map_type!(HashMap);
225impl_for_map_type!(IndexMap);
226
227macro_rules! impl_for_list_type {
228    ($ty: ty) => {
229        impl<T: AzaleaRead> AzaleaRead for $ty {
230            default fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
231                let length = u32::azalea_read_var(buf)? as usize;
232                // we limit the capacity to not get exploited into allocating a bunch
233                let mut contents = Vec::with_capacity(usize::min(length, 65536));
234                for _ in 0..length {
235                    contents.push(T::azalea_read(buf)?);
236                }
237                Ok(contents.into())
238            }
239        }
240        impl<T: AzaleaReadVar> AzaleaReadVar for $ty {
241            fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
242                let length = i32::azalea_read_var(buf)? as usize;
243                let mut contents = Vec::with_capacity(usize::min(length, 65536));
244                for _ in 0..length {
245                    contents.push(T::azalea_read_var(buf)?);
246                }
247                Ok(contents.into())
248            }
249        }
250        impl<T: AzaleaRead> AzaleaReadLimited for $ty {
251            fn azalea_read_limited(
252                buf: &mut Cursor<&[u8]>,
253                limit: usize,
254            ) -> Result<Self, BufReadError> {
255                let length = u32::azalea_read_var(buf)? as usize;
256                if length > limit {
257                    return Err(BufReadError::VecLengthTooLong {
258                        length: length as u32,
259                        max_length: limit as u32,
260                    });
261                }
262
263                let mut contents = Vec::with_capacity(usize::min(length, 65536));
264                for _ in 0..length {
265                    contents.push(T::azalea_read(buf)?);
266                }
267                Ok(contents.into())
268            }
269        }
270    };
271}
272
273impl_for_list_type!(Vec<T>);
274impl_for_list_type!(Box<[T]>);
275
276impl AzaleaRead for Vec<u8> {
277    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
278        let length = i32::azalea_read_var(buf)? as usize;
279        read_bytes(buf, length).map(|b| b.to_vec())
280    }
281}
282
283impl AzaleaRead for String {
284    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
285        read_utf_with_len(buf, MAX_STRING_LENGTH.into())
286    }
287}
288impl AzaleaReadLimited for String {
289    fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: usize) -> Result<Self, BufReadError> {
290        read_utf_with_len(buf, limit as u32)
291    }
292}
293
294impl AzaleaRead for u32 {
295    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
296        Ok(i32::azalea_read(buf)? as u32)
297    }
298}
299
300impl AzaleaReadVar for u32 {
301    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
302        Ok(i32::azalea_read_var(buf)? as u32)
303    }
304}
305
306impl AzaleaRead for u16 {
307    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
308        i16::azalea_read(buf).map(|i| i as u16)
309    }
310}
311
312impl AzaleaRead for i16 {
313    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
314        Ok(buf.read_i16::<BE>()?)
315    }
316}
317
318impl AzaleaReadVar for u16 {
319    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
320        Ok(i32::azalea_read_var(buf)? as u16)
321    }
322}
323
324impl AzaleaRead for i64 {
325    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
326        Ok(buf.read_i64::<BE>()?)
327    }
328}
329
330impl AzaleaRead for u64 {
331    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
332        i64::azalea_read(buf).map(|i| i as u64)
333    }
334}
335
336impl AzaleaRead for bool {
337    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
338        let byte = u8::azalea_read(buf)?;
339        if byte > 1 {
340            warn!("Boolean value was not 0 or 1, but {}", byte);
341        }
342        Ok(byte != 0)
343    }
344}
345
346impl AzaleaRead for u8 {
347    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
348        Ok(buf.read_u8()?)
349    }
350}
351
352impl AzaleaRead for i8 {
353    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
354        u8::azalea_read(buf).map(|i| i as i8)
355    }
356}
357
358impl AzaleaRead for f32 {
359    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
360        Ok(buf.read_f32::<BE>()?)
361    }
362}
363
364impl AzaleaRead for f64 {
365    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
366        Ok(buf.read_f64::<BE>()?)
367    }
368}
369
370impl<T: AzaleaRead> AzaleaRead for Option<T> {
371    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
372        let present = bool::azalea_read(buf)?;
373        Ok(if present {
374            Some(T::azalea_read(buf)?)
375        } else {
376            None
377        })
378    }
379}
380
381impl<T: AzaleaReadVar> AzaleaReadVar for Option<T> {
382    fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
383        let present = bool::azalea_read(buf)?;
384        Ok(if present {
385            Some(T::azalea_read_var(buf)?)
386        } else {
387            None
388        })
389    }
390}
391impl<T: AzaleaReadLimited> AzaleaReadLimited for Option<T> {
392    fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: usize) -> Result<Self, BufReadError> {
393        let present = bool::azalea_read(buf)?;
394        Ok(if present {
395            Some(T::azalea_read_limited(buf, limit)?)
396        } else {
397            None
398        })
399    }
400}
401
402// [String; 4]
403impl<T: AzaleaRead, const N: usize> AzaleaRead for [T; N] {
404    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
405        let mut contents = Vec::with_capacity(N);
406        for _ in 0..N {
407            contents.push(T::azalea_read(buf)?);
408        }
409        contents.try_into().map_err(|_| {
410            unreachable!("Panic is not possible since the Vec is the same size as the array")
411        })
412    }
413}
414
415impl AzaleaRead for simdnbt::owned::NbtTag {
416    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
417        Ok(simdnbt::owned::read_tag(buf).map_err(simdnbt::Error::from)?)
418    }
419}
420
421impl AzaleaRead for simdnbt::owned::NbtCompound {
422    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
423        match simdnbt::owned::read_tag(buf).map_err(simdnbt::Error::from)? {
424            simdnbt::owned::NbtTag::Compound(compound) => Ok(compound),
425            _ => Err(BufReadError::Custom("Expected compound tag".to_string())),
426        }
427    }
428}
429
430impl AzaleaRead for simdnbt::owned::Nbt {
431    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
432        Ok(simdnbt::owned::read_unnamed(buf)?)
433    }
434}
435
436impl<T> AzaleaRead for Box<T>
437where
438    T: AzaleaRead,
439{
440    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
441        Ok(Box::new(T::azalea_read(buf)?))
442    }
443}
444
445impl<A: AzaleaRead, B: AzaleaRead> AzaleaRead for (A, B) {
446    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
447        Ok((A::azalea_read(buf)?, B::azalea_read(buf)?))
448    }
449}
450
451impl<T: AzaleaRead> AzaleaRead for Arc<T> {
452    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
453        Ok(Arc::new(T::azalea_read(buf)?))
454    }
455}