deepslate_protocol/
codec.rs1use bytes::{Buf, BufMut};
9
10use crate::types::ProtocolError;
11use crate::varint;
12
13const MAX_FRAME_SIZE: usize = 2 * 1024 * 1024;
16
17pub const MAX_UNCOMPRESSED_SIZE: usize = 8 * 1024 * 1024;
19
20#[allow(clippy::cast_sign_loss)]
36pub fn try_read_frame(data: &[u8]) -> Result<Option<(usize, usize)>, ProtocolError> {
37 let Some((frame_len, varint_size)) = varint::peek_var_int(data)? else {
38 return Ok(None);
39 };
40
41 if frame_len < 0 {
42 return Err(ProtocolError::InvalidData(
43 "negative frame length".to_string(),
44 ));
45 }
46
47 let frame_len = frame_len as usize;
48 if frame_len > MAX_FRAME_SIZE {
49 return Err(ProtocolError::FrameTooLarge {
50 size: frame_len,
51 max: MAX_FRAME_SIZE,
52 });
53 }
54
55 let total = varint_size + frame_len;
56 if data.len() < total {
57 return Ok(None);
58 }
59
60 Ok(Some((varint_size, frame_len)))
61}
62
63#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
66pub fn write_frame(dst: &mut impl BufMut, inner: &[u8]) {
67 varint::write_var_int(dst, inner.len() as i32);
68 dst.put_slice(inner);
69}
70
71#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
77pub fn write_compressed_frame(dst: &mut impl BufMut, uncompressed_size: i32, payload: &[u8]) {
78 let size_varint_len = varint::var_int_bytes(uncompressed_size);
79 let frame_len = size_varint_len + payload.len();
80 varint::write_var_int(dst, frame_len as i32);
81 varint::write_var_int(dst, uncompressed_size);
82 dst.put_slice(payload);
83}
84
85#[allow(clippy::cast_sign_loss)]
97pub fn read_compressed_frame(data: &[u8]) -> Result<(usize, &[u8]), ProtocolError> {
98 let mut cursor = data;
99 let uncompressed_size = varint::read_var_int(&mut cursor)?;
100 if uncompressed_size < 0 {
101 return Err(ProtocolError::InvalidData(
102 "negative uncompressed size".to_string(),
103 ));
104 }
105 let uncompressed_size = uncompressed_size as usize;
106 if uncompressed_size > MAX_UNCOMPRESSED_SIZE {
107 return Err(ProtocolError::CompressionError(format!(
108 "uncompressed size {uncompressed_size} exceeds maximum {MAX_UNCOMPRESSED_SIZE}"
109 )));
110 }
111 Ok((uncompressed_size, cursor))
112}
113
114pub fn encode_packet_data(packet_id: i32, encode_fn: impl FnOnce(&mut Vec<u8>)) -> Vec<u8> {
116 let mut buf = Vec::with_capacity(64);
117 varint::write_var_int(&mut buf, packet_id);
118 encode_fn(&mut buf);
119 buf
120}
121
122pub fn read_packet_id(buf: &mut impl Buf) -> Result<i32, ProtocolError> {
128 varint::read_var_int(buf)
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_try_read_frame_complete() {
137 let data = vec![0x03, 0x01, 0x02, 0x03];
139 let (varint_size, frame_len) = try_read_frame(&data).unwrap().unwrap();
140 assert_eq!(varint_size + frame_len, 4);
141 assert_eq!(
142 &data[varint_size..varint_size + frame_len],
143 &[0x01, 0x02, 0x03]
144 );
145 }
146
147 #[test]
148 fn test_try_read_frame_incomplete() {
149 let data = vec![0x03, 0x01]; assert!(try_read_frame(&data).unwrap().is_none());
151 }
152
153 #[test]
154 fn test_try_read_frame_empty() {
155 assert!(try_read_frame(&[]).unwrap().is_none());
156 }
157
158 #[test]
159 fn test_write_frame_roundtrip() {
160 let inner = vec![0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F]; let mut buf = Vec::new();
162 write_frame(&mut buf, &inner);
163 let (varint_size, frame_len) = try_read_frame(&buf).unwrap().unwrap();
164 assert_eq!(varint_size + frame_len, buf.len());
165 assert_eq!(&buf[varint_size..varint_size + frame_len], &inner[..]);
166 }
167
168 #[test]
169 fn test_compressed_frame_uncompressed() {
170 let mut buf = Vec::new();
171 let payload = vec![0x00, 0x48, 0x69];
172 write_compressed_frame(&mut buf, 0, &payload);
173
174 let (varint_size, frame_len) = try_read_frame(&buf).unwrap().unwrap();
175 let frame_data = &buf[varint_size..varint_size + frame_len];
176 let (uncompressed_size, data) = read_compressed_frame(frame_data).unwrap();
177 assert_eq!(uncompressed_size, 0);
178 assert_eq!(data, &payload[..]);
179 }
180}