1use binrw::{BinRead, binrw};
2
3use crate::{ClassStatus, JdwpIdSize, JdwpIdSizes, JdwpString, TypeTag, binrw_enum};
4
5binrw_enum! {
6 #[repr(u16)]
7 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
8 pub enum Command {
9 VirtualMachineVersion = (1 << 8) | 1,
10 VirtualMachineAllClasses = (1 << 8) | 3,
11 VirtualMachineIDSizes = (1 << 8) | 7,
12 }
13}
14
15#[binrw]
16#[brw(big)]
17pub struct CommandPacketHeader {
18 pub length: u32,
19 pub id: u32,
20 pub flags: u8,
21 pub command: Command,
22}
23impl CommandPacketHeader {
24 pub fn get_length() -> usize {
25 return 4 + 4 + 1 + 2;
26 }
27}
28
29#[binrw]
30#[brw(big)]
31pub struct ReplyPacketHeader {
32 pub length: u32,
33 pub id: u32,
34 pub flags: u8,
35 pub error_code: u16,
36}
37impl ReplyPacketHeader {
38 pub fn default() -> Self {
39 ReplyPacketHeader {
40 length: 0,
41 id: 0xFFFFFFFF,
42 flags: 0,
43 error_code: 0,
44 }
45 }
46 pub fn get_length() -> usize {
47 return 4 + 4 + 1 + 2;
48 }
49 pub fn is_success(&self) -> bool {
50 return self.error_code == 0;
51 }
52}
53
54#[derive(Debug)]
55pub struct VariableLengthId {
56 pub value: u64,
57}
58impl BinRead for VariableLengthId {
59 type Args<'a> = JdwpIdSize;
60
61 fn read_options<R: std::io::Read + std::io::Seek>(
62 reader: &mut R,
63 endian: binrw::Endian,
64 args: Self::Args<'_>,
65 ) -> binrw::BinResult<Self> {
66 let val: u64 = match args {
68 1 => u8::read_options(reader, endian, ())? as u64,
69 2 => u16::read_options(reader, endian, ())? as u64,
70 4 => u32::read_options(reader, endian, ())? as u64,
71 8 => u64::read_options(reader, endian, ())?,
72 _ => {
73 return binrw::BinResult::Err(binrw::Error::Custom {
74 pos: reader.stream_position().unwrap_or(0),
75 err: Box::new("Unsupported variable size ID"),
76 });
77 }
78 };
79
80 Ok(VariableLengthId { value: val })
81 }
82}
83
84#[binrw]
85#[brw(big)]
86#[derive(Debug)]
87pub struct VersionReply {
88 pub description: JdwpString,
89 pub jdwp_major: i32,
90 pub jdwp_minor: i32,
91 pub vm_version: JdwpString,
92 pub vm_name: JdwpString,
93}
94
95#[binrw]
96#[brw(big)]
97#[derive(Debug)]
98pub struct IdSizesReply {
99 pub field_id_size: i32,
100 pub method_id_size: i32,
101 pub object_id_size: i32,
102 pub reference_type_id_size: i32,
103 pub frame_id_size: i32,
104}
105
106#[derive(Debug)]
107pub struct AllClassesReplyClass {
108 pub ref_type_tag: TypeTag,
109 pub type_id: VariableLengthId,
110 pub signature: JdwpString,
111 pub status: ClassStatus,
112}
113impl BinRead for AllClassesReplyClass {
114 type Args<'a> = JdwpIdSizes;
115
116 fn read_options<R: std::io::Read + std::io::Seek>(
117 reader: &mut R,
118 endian: binrw::Endian,
119 args: Self::Args<'_>,
120 ) -> binrw::BinResult<Self> {
121 Ok(AllClassesReplyClass {
122 ref_type_tag: TypeTag::read_options(reader, endian, ())?,
123 type_id: VariableLengthId::read_options(reader, endian, args.reference_type_id_size)?,
124 signature: JdwpString::read_options(reader, endian, ())?,
125 status: ClassStatus::read_options(reader, endian, ())?,
126 })
127 }
128}
129
130#[derive(Debug)]
131pub struct AllClassesReply {
132 pub classes: Vec<AllClassesReplyClass>,
133}
134impl BinRead for AllClassesReply {
135 type Args<'a> = JdwpIdSizes;
136
137 fn read_options<R: std::io::Read + std::io::Seek>(
138 reader: &mut R,
139 endian: binrw::Endian,
140 args: Self::Args<'_>,
141 ) -> binrw::BinResult<Self> {
142 let classes_length = i32::read_options(reader, endian, ())?;
143 let mut classes = Vec::with_capacity(classes_length as usize);
144 for _ in 0..classes_length {
145 classes.push(AllClassesReplyClass::read_options(reader, endian, args)?);
146 }
147
148 Ok(AllClassesReply { classes })
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use crate::Command;
155 use binrw::BinRead;
156 use std::io::Cursor;
157
158 #[test]
159 fn test_deserialize_vm_version_command() {
160 let data = [1u8, 1u8];
161 let mut cursor = Cursor::new(&data);
162 let value = Command::read_be(&mut cursor).unwrap();
163 assert_eq!(value, Command::VirtualMachineVersion);
164 }
165}