1mod extra;
2mod primitives;
3
4use std::{
5 backtrace::Backtrace,
6 io::{self, Cursor, Write},
7};
8
9use thiserror::Error;
10
11pub trait AzBuf
13where
14 Self: Sized,
15{
16 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>;
17 fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()>;
18}
19
20pub trait AzBufVar
24where
25 Self: Sized,
26{
27 fn azalea_read_var(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>;
28 fn azalea_write_var(&self, buf: &mut impl Write) -> io::Result<()>;
29}
30
31pub trait AzBufLimited
39where
40 Self: Sized,
41{
42 fn azalea_read_limited(buf: &mut Cursor<&[u8]>, limit: u32) -> Result<Self, BufReadError>;
43}
44
45#[derive(Debug, Error)]
46pub enum BufReadError {
47 #[error("Invalid VarInt")]
48 InvalidVarInt,
49 #[error("Invalid VarLong")]
50 InvalidVarLong,
51 #[error("Error reading bytes")]
52 CouldNotReadBytes,
53 #[error(
54 "The received encoded string buffer length is longer than maximum allowed ({length} > {max_length})"
55 )]
56 StringLengthTooLong { length: u32, max_length: u32 },
57 #[error("The received Vec length is longer than maximum allowed ({length} > {max_length})")]
58 VecLengthTooLong { length: u32, max_length: u32 },
59 #[error("{source}")]
60 Io {
61 #[from]
62 #[backtrace]
63 source: io::Error,
64 },
65 #[error("Invalid UTF-8: {bytes:?} (lossy: {lossy:?})")]
66 InvalidUtf8 {
67 bytes: Vec<u8>,
68 lossy: String,
69 },
71 #[error("Unexpected enum variant {id}")]
72 UnexpectedEnumVariant { id: i32 },
73 #[error("Unexpected enum variant {id}")]
74 UnexpectedStringEnumVariant { id: String },
75 #[error("Tried to read {attempted_read} bytes but there were only {actual_read}")]
76 UnexpectedEof {
77 attempted_read: usize,
78 actual_read: usize,
79 backtrace: Backtrace,
80 },
81 #[error("{0}")]
82 Custom(String),
83 #[cfg(feature = "serde_json")]
84 #[error("{source}")]
85 Deserialization {
86 #[from]
87 #[backtrace]
88 source: serde_json::Error,
89 },
90 #[error("{source}")]
91 Nbt {
92 #[from]
93 #[backtrace]
94 source: simdnbt::Error,
95 },
96 #[error("{source}")]
97 DeserializeNbt {
98 #[from]
99 #[backtrace]
100 source: simdnbt::DeserializeError,
101 },
102}
103
104pub(crate) fn read_bytes<'a>(
105 buf: &'a mut Cursor<&[u8]>,
106 length: usize,
107) -> Result<&'a [u8], BufReadError> {
108 if length > (buf.get_ref().len() - buf.position() as usize) {
109 return Err(BufReadError::UnexpectedEof {
110 attempted_read: length,
111 actual_read: buf.get_ref().len() - buf.position() as usize,
112 backtrace: Backtrace::capture(),
113 });
114 }
115 let initial_position = buf.position() as usize;
116 buf.set_position(buf.position() + length as u64);
117 let data = &buf.get_ref()[initial_position..initial_position + length];
118 Ok(data)
119}
120
121pub(crate) fn read_utf_with_len<'a>(
122 buf: &'a mut Cursor<&[u8]>,
123 max_length: u32,
124) -> Result<&'a str, BufReadError> {
125 let length = u32::azalea_read_var(buf)?;
126 if length > max_length * 4 {
128 return Err(BufReadError::StringLengthTooLong {
129 length,
130 max_length: max_length * 4,
131 });
132 }
133
134 let buffer = read_bytes(buf, length as usize)?;
135 let string = std::str::from_utf8(buffer).map_err(|_| BufReadError::InvalidUtf8 {
136 bytes: buffer.to_vec(),
137 lossy: String::from_utf8_lossy(buffer).to_string(),
138 })?;
140 if string.len() > length as usize {
141 return Err(BufReadError::StringLengthTooLong { length, max_length });
142 }
143
144 Ok(string)
145}
146
147pub(crate) fn write_utf_with_len(
148 buf: &mut impl Write,
149 string: &str,
150 max_len: u32,
151) -> io::Result<()> {
152 let actual_len = string.len();
153 if actual_len > max_len as usize {
154 panic!("String too big (was {actual_len} bytes encoded, max {max_len})");
155 }
156 string.as_bytes().to_vec().azalea_write(buf)?;
157 Ok(())
158}