jdwp_client/
types.rs

1use binrw::{BinRead, BinWrite};
2
3pub type JdwpIdSize = u8;
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct JdwpIdSizes {
6    pub field_id_size: JdwpIdSize,
7    pub method_id_size: JdwpIdSize,
8    pub object_id_size: JdwpIdSize,
9    pub reference_type_id_size: JdwpIdSize,
10    pub frame_id_size: JdwpIdSize,
11}
12
13#[derive(Debug)]
14pub struct JdwpString {
15    pub string: String,
16}
17impl BinRead for JdwpString {
18    type Args<'a> = ();
19
20    fn read_options<R: std::io::Read + std::io::Seek>(
21        reader: &mut R,
22        endian: binrw::Endian,
23        args: Self::Args<'_>,
24    ) -> binrw::BinResult<Self> {
25        let length = u32::read_options(reader, endian, args)?;
26        if length == 0 {
27            return Ok(JdwpString {
28                string: String::from(""),
29            });
30        }
31
32        let mut bytes = vec![0u8; length as usize];
33        reader.read_exact(&mut bytes)?;
34        Ok(JdwpString {
35            string: String::from_utf8(bytes).map_err(|e| binrw::Error::Custom {
36                pos: reader.stream_position().unwrap_or(0),
37                err: Box::new(e),
38            })?,
39        })
40    }
41}
42impl BinWrite for JdwpString {
43    type Args<'a> = ();
44
45    fn write_options<W: std::io::Write + std::io::Seek>(
46        &self,
47        writer: &mut W,
48        endian: binrw::Endian,
49        args: Self::Args<'_>,
50    ) -> binrw::BinResult<()> {
51        let bytes = self.string.as_bytes();
52        let length = bytes.len() as u32;
53        length.write_options(writer, endian, args)?;
54
55        if length > 0 {
56            return bytes.write_options(writer, endian, args);
57        }
58        Ok(())
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use std::io::Cursor;
66
67    #[test]
68    fn test_read_jdwp_string_empty() {
69        let data = [0u8, 0u8, 0u8, 0u8]; // 0 length
70        let mut cursor = Cursor::new(&data);
71        let value = JdwpString::read_be(&mut cursor).unwrap();
72        assert!(value.string.is_empty());
73    }
74
75    #[test]
76    fn test_read_jdwp_string() {
77        let data = [0u8, 0u8, 0u8, 4u8, 74u8, 68u8, 87u8, 80u8]; // 4 length, "JDWP"
78        let mut cursor = Cursor::new(&data);
79        let value = JdwpString::read_be(&mut cursor).unwrap();
80        assert_eq!(value.string, "JDWP");
81    }
82
83    #[test]
84    fn test_write_jdwp_string() {
85        let value = JdwpString {
86            string: String::from("JDWP"),
87        };
88        let mut buffer: Vec<u8> = vec![];
89        let mut cursor = Cursor::new(&mut buffer);
90        value.write_be(&mut cursor).unwrap();
91
92        let expected = [0u8, 0u8, 0u8, 4u8, 74u8, 68u8, 87u8, 80u8]; // 4 length, "JDWP"
93        assert_eq!(buffer, expected);
94    }
95
96    #[test]
97    fn test_write_jdwp_string_empty() {
98        let value = JdwpString {
99            string: String::from(""),
100        };
101        let mut buffer: Vec<u8> = vec![];
102        let mut cursor = Cursor::new(&mut buffer);
103        value.write_be(&mut cursor).unwrap();
104
105        let expected = [0u8, 0u8, 0u8, 0u8]; // 0 length
106        assert_eq!(buffer, expected);
107    }
108}