1use std::io::{self, Read, Write};
7
8pub const FLUSH: &str = "0000";
10pub const DELIM: &str = "0001";
12pub const RESPONSE_END: &str = "0002";
14
15pub fn write_line(w: &mut impl Write, data: &str) -> io::Result<()> {
18 let len = 4 + data.len() + 1;
19 writeln!(w, "{len:04x}{data}")
20}
21
22pub fn write_line_to_vec(buf: &mut Vec<u8>, data: &str) -> io::Result<()> {
24 let len = 4 + data.len() + 1;
25 let line = format!("{len:04x}{data}\n");
26 buf.extend_from_slice(line.as_bytes());
27 Ok(())
28}
29
30pub fn write_flush(w: &mut impl Write) -> io::Result<()> {
32 write!(w, "0000")
33}
34
35pub fn write_packet_raw(w: &mut impl Write, payload: &[u8]) -> io::Result<()> {
37 let total = payload
38 .len()
39 .checked_add(4)
40 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "pkt-line payload too large"))?;
41 if total > 65520 {
42 return Err(io::Error::new(
43 io::ErrorKind::InvalidInput,
44 "pkt-line exceeds maximum size",
45 ));
46 }
47 write!(w, "{total:04x}")?;
48 w.write_all(payload)?;
49 Ok(())
50}
51
52pub fn write_delim(w: &mut impl Write) -> io::Result<()> {
54 write!(w, "0001")
55}
56
57#[derive(Debug, PartialEq, Eq)]
59pub enum Packet {
60 Data(String),
62 Flush,
64 Delim,
66 ResponseEnd,
68}
69
70pub fn read_packet(r: &mut impl Read) -> io::Result<Option<Packet>> {
72 let mut len_buf = [0u8; 4];
73 match r.read_exact(&mut len_buf) {
74 Ok(()) => {}
75 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),
76 Err(e) => return Err(e),
77 }
78 let len_str =
79 std::str::from_utf8(&len_buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
80 let len = usize::from_str_radix(len_str, 16)
81 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
82
83 match len {
84 0 => Ok(Some(Packet::Flush)),
85 1 => Ok(Some(Packet::Delim)),
86 2 => Ok(Some(Packet::ResponseEnd)),
87 n if n <= 4 => Err(io::Error::new(
88 io::ErrorKind::InvalidData,
89 format!("invalid pkt-line length: {n}"),
90 )),
91 n => {
92 let payload_len = n - 4;
93 let mut buf = vec![0u8; payload_len];
94 r.read_exact(&mut buf)?;
95 let s = String::from_utf8_lossy(&buf).into_owned();
98 Ok(Some(Packet::Data(
99 s.strip_suffix('\n').unwrap_or(&s).to_owned(),
100 )))
101 }
102 }
103}
104
105pub fn read_until_flush_or_delim(r: &mut impl Read) -> io::Result<(Vec<String>, Option<Packet>)> {
109 let mut lines = Vec::new();
110 loop {
111 match read_packet(r)? {
112 None => return Ok((lines, None)),
113 Some(Packet::Flush) => return Ok((lines, Some(Packet::Flush))),
114 Some(Packet::Delim) => return Ok((lines, Some(Packet::Delim))),
115 Some(Packet::ResponseEnd) => return Ok((lines, Some(Packet::ResponseEnd))),
116 Some(Packet::Data(s)) => lines.push(s),
117 }
118 }
119}
120
121pub fn read_data_lines_until_flush(
126 r: &mut impl Read,
127 err_not_flush: &str,
128) -> io::Result<Vec<String>> {
129 let mut lines = Vec::new();
130 loop {
131 match read_packet(r)? {
132 None => {
133 return Err(io::Error::new(
134 io::ErrorKind::UnexpectedEof,
135 err_not_flush.to_string(),
136 ));
137 }
138 Some(Packet::Flush) => return Ok(lines),
139 Some(Packet::Delim) | Some(Packet::ResponseEnd) => {
140 return Err(io::Error::new(
141 io::ErrorKind::InvalidData,
142 err_not_flush.to_string(),
143 ));
144 }
145 Some(Packet::Data(s)) => lines.push(s),
146 }
147 }
148}
149
150pub fn write_sideband_packet(w: &mut impl Write, band: u8, payload: &[u8]) -> io::Result<()> {
152 let len = 4 + 1 + payload.len();
153 write!(w, "{len:04x}")?;
154 w.write_all(&[band])?;
155 w.write_all(payload)?;
156 Ok(())
157}
158
159pub fn write_sideband_channel1_64k(w: &mut impl Write, payload: &[u8]) -> io::Result<()> {
161 const MAX_PAYLOAD: usize = 65515;
162 for chunk in payload.chunks(MAX_PAYLOAD) {
163 let len = 4 + 1 + chunk.len();
164 write!(w, "{len:04x}")?;
165 w.write_all(&[1u8])?;
166 w.write_all(chunk)?;
167 }
168 Ok(())
169}
170
171pub fn parse_hex_len(prefix: &[u8]) -> io::Result<usize> {
173 let s = std::str::from_utf8(prefix)
174 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("{e}")))?;
175 usize::from_str_radix(s, 16)
176 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("invalid length: {e}")))
177}
178
179pub fn decode_sideband_primary(mut input: &[u8]) -> io::Result<Vec<u8>> {
181 let mut out = Vec::new();
182 while !input.is_empty() {
183 if input.len() < 4 {
184 break;
185 }
186 let len = parse_hex_len(&input[..4])?;
187 input = &input[4..];
188 if len == 0 {
189 break;
190 }
191 if len <= 4 || input.len() < len - 4 {
192 return Err(io::Error::new(
193 io::ErrorKind::InvalidData,
194 "truncated sideband packet",
195 ));
196 }
197 let payload_len = len - 4;
198 let payload = &input[..payload_len];
199 input = &input[payload_len..];
200 if payload.is_empty() {
201 continue;
202 }
203 let band = payload[0];
204 let data = &payload[1..];
205 if band == 1 {
206 out.extend_from_slice(data);
207 }
208 }
209 Ok(out)
210}