azalea_buf/
read.rs

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