1use crate::protocol::{JdwpError, JdwpResult};
23use crate::types::ValueData;
24use bytes::Buf;
25
26pub mod value_tags {
29 pub const BYTE: u8 = 66; pub const CHAR: u8 = 67; pub const OBJECT: u8 = 76; pub const FLOAT: u8 = 70; pub const DOUBLE: u8 = 68; pub const INT: u8 = 73; pub const LONG: u8 = 74; pub const SHORT: u8 = 83; pub const VOID: u8 = 86; pub const BOOLEAN: u8 = 90; pub const STRING: u8 = 115; pub const THREAD: u8 = 116; pub const THREAD_GROUP: u8 = 103; pub const CLASS_LOADER: u8 = 108; pub const CLASS_OBJECT: u8 = 99; pub const ARRAY: u8 = 91; }
46
47fn ensure(buf: &[u8], n: usize, what: &str) -> JdwpResult<()> {
50 if buf.remaining() < n {
51 return Err(JdwpError::Protocol(format!(
52 "Not enough data for {what}: need {n} byte(s), have {}",
53 buf.remaining()
54 )));
55 }
56 Ok(())
57}
58
59fn value_width(tag: u8) -> JdwpResult<usize> {
64 use value_tags as t;
65 Ok(match tag {
66 t::VOID => 0,
67 t::BYTE | t::BOOLEAN => 1,
68 t::CHAR | t::SHORT => 2,
69 t::FLOAT | t::INT => 4,
70 t::DOUBLE
72 | t::LONG
73 | t::OBJECT
74 | t::STRING
75 | t::THREAD
76 | t::THREAD_GROUP
77 | t::CLASS_LOADER
78 | t::CLASS_OBJECT
79 | t::ARRAY => 8,
80 _ => return Err(JdwpError::Protocol(format!("Unknown value tag: {tag}"))),
81 })
82}
83
84pub fn read_value_by_tag(tag: u8, buf: &mut &[u8]) -> JdwpResult<ValueData> {
92 use value_tags as t;
93 let width = value_width(tag)?;
94 ensure(buf, width, "value")?;
95 Ok(match tag {
97 t::BYTE => ValueData::Byte(buf.get_i8()),
98 t::CHAR => ValueData::Char(buf.get_u16()),
99 t::DOUBLE => ValueData::Double(buf.get_f64()),
100 t::FLOAT => ValueData::Float(buf.get_f32()),
101 t::INT => ValueData::Int(buf.get_i32()),
102 t::LONG => ValueData::Long(buf.get_i64()),
103 t::SHORT => ValueData::Short(buf.get_i16()),
104 t::BOOLEAN => ValueData::Boolean(buf.get_u8() != 0),
105 t::VOID => ValueData::Void,
106 _ => ValueData::Object(buf.get_u64()),
107 })
108}
109
110pub fn read_string(buf: &mut &[u8]) -> JdwpResult<String> {
115 ensure(buf, 4, "string length")?;
116 let len = buf.get_u32() as usize;
117 ensure(buf, len, "string body")?;
121 let bytes = buf
122 .get(..len)
123 .ok_or_else(|| JdwpError::Protocol("String shorter than its length prefix".to_string()))?
124 .to_vec();
125 buf.advance(len);
126
127 String::from_utf8(bytes).map_err(|e| JdwpError::Protocol(format!("Invalid UTF-8 in string: {e}")))
128}
129
130pub fn read_u32(buf: &mut &[u8]) -> JdwpResult<u32> {
135 ensure(buf, 4, "u32")?;
136 Ok(buf.get_u32())
137}
138
139pub fn read_i32(buf: &mut &[u8]) -> JdwpResult<i32> {
144 ensure(buf, 4, "i32")?;
145 Ok(buf.get_i32())
146}
147
148pub fn read_u8(buf: &mut &[u8]) -> JdwpResult<u8> {
153 ensure(buf, 1, "u8")?;
154 Ok(buf.get_u8())
155}
156
157pub fn read_u64(buf: &mut &[u8]) -> JdwpResult<u64> {
162 ensure(buf, 8, "u64")?;
163 Ok(buf.get_u64())
164}
165
166pub fn read_i64(buf: &mut &[u8]) -> JdwpResult<i64> {
171 ensure(buf, 8, "i64")?;
172 Ok(buf.get_i64())
173}
174
175#[must_use]
182pub fn some_if_present(s: String) -> Option<String> {
183 (!s.is_empty()).then_some(s)
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::eval::write_untagged_value;
190 use crate::types::Value;
191
192 fn sample_values() -> Vec<(u8, ValueData)> {
195 use value_tags as t;
196 vec![
197 (t::BYTE, ValueData::Byte(-7)),
198 (t::CHAR, ValueData::Char(u16::from(b'Q'))),
199 (t::SHORT, ValueData::Short(-300)),
200 (t::INT, ValueData::Int(i32::MIN)),
201 (t::LONG, ValueData::Long(i64::MAX)),
202 (t::FLOAT, ValueData::Float(1.5)),
203 (t::DOUBLE, ValueData::Double(-2.25)),
204 (t::BOOLEAN, ValueData::Boolean(true)),
205 (t::OBJECT, ValueData::Object(0xdead_beef)),
206 ]
207 }
208
209 #[test]
213 fn every_value_variant_round_trips_through_write_then_read() {
214 let mut bytes = Vec::new();
215 for (tag, data) in sample_values() {
216 bytes.clear();
217 write_untagged_value(&mut bytes, &Value { tag, data: data.clone() });
218 assert_eq!(
219 bytes.len(),
220 value_width(tag).expect("sample tags are all known"),
221 "tag {tag} wrote {} bytes, width table says otherwise",
222 bytes.len()
223 );
224
225 let mut buf = bytes.as_slice();
226 let read = read_value_by_tag(tag, &mut buf).expect("round trip");
227 assert_eq!(format!("{read:?}"), format!("{data:?}"), "tag {tag} changed on the way back");
228 assert!(buf.is_empty(), "tag {tag} left {} unread byte(s)", buf.len());
229 }
230 }
231
232 #[test]
235 fn a_truncated_buffer_errors_for_every_value_tag() {
236 let mut full = Vec::new();
237 for (tag, data) in sample_values() {
238 full.clear();
239 write_untagged_value(&mut full, &Value { tag, data });
240 for keep in 0..full.len() {
242 let mut buf = &full[..keep];
243 let err = read_value_by_tag(tag, &mut buf);
244 assert!(
245 err.is_err(),
246 "tag {tag} accepted {keep} of {} byte(s) instead of erroring",
247 full.len()
248 );
249 }
250 }
251 }
252
253 #[test]
254 fn void_reads_from_an_empty_buffer_and_consumes_nothing() {
255 let mut buf: &[u8] = &[];
256 assert!(matches!(read_value_by_tag(value_tags::VOID, &mut buf), Ok(ValueData::Void)));
257 assert!(buf.is_empty());
258 }
259
260 #[test]
263 fn an_unknown_value_tag_errors_without_consuming_input() {
264 let mut buf: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
265 let err = read_value_by_tag(b'?', &mut buf).expect_err("'?' is not a value tag");
266 assert!(format!("{err}").contains("Unknown value tag"), "unhelpful error: {err}");
267 assert_eq!(buf.len(), 8, "a rejected tag must not advance the buffer");
268 }
269
270 #[test]
271 fn each_fixed_width_reader_errors_on_a_short_buffer() {
272 assert!(read_u8(&mut &[][..]).is_err());
273 assert!(read_u32(&mut &[0u8; 3][..]).is_err());
274 assert!(read_i32(&mut &[0u8; 3][..]).is_err());
275 assert!(read_u64(&mut &[0u8; 7][..]).is_err());
276 assert_eq!(read_u8(&mut &[9u8][..]).expect("u8"), 9);
278 assert_eq!(read_u32(&mut &[0, 0, 1, 0][..]).expect("u32"), 256);
279 assert_eq!(read_i32(&mut &[0xff, 0xff, 0xff, 0xff][..]).expect("i32"), -1);
280 assert_eq!(read_u64(&mut &[0, 0, 0, 0, 0, 0, 0, 5][..]).expect("u64"), 5);
281 }
282
283 #[test]
284 fn read_string_handles_empty_truncated_and_lying_lengths() {
285 let mut wire = 5u32.to_be_bytes().to_vec();
287 wire.extend_from_slice(b"hello");
288 wire.extend_from_slice(b"tail");
289 let mut buf = wire.as_slice();
290 assert_eq!(read_string(&mut buf).expect("string"), "hello");
291 assert_eq!(buf, b"tail", "read_string must consume exactly the string");
292
293 assert_eq!(read_string(&mut &0u32.to_be_bytes()[..]).expect("empty"), "");
295
296 assert!(read_string(&mut &[0u8, 0, 5][..]).is_err());
298 let mut lying = 99u32.to_be_bytes().to_vec();
299 lying.extend_from_slice(b"short");
300 assert!(read_string(&mut lying.as_slice()).is_err(), "a length past the end must error");
301
302 let mut bad = 2u32.to_be_bytes().to_vec();
305 bad.extend_from_slice(&[0xff, 0xfe]);
306 assert!(read_string(&mut bad.as_slice()).is_err());
307 }
308}