steamkit/util/
stream_helpers.rs1use async_trait::async_trait;
5use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
6
7use crate::error::SteamError;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum StreamEncoding {
12 Utf8,
14 Ascii,
16 Latin1,
18}
19
20impl StreamEncoding {
21 fn character_size(self) -> usize {
24 1
25 }
26
27 fn encode(self, value: &str) -> Vec<u8> {
29 match self {
30 StreamEncoding::Utf8 => value.as_bytes().to_vec(),
31 StreamEncoding::Ascii => value
32 .chars()
33 .map(|character| {
34 if (character as u32) < 0x80 {
35 character as u8
36 } else {
37 b'?'
38 }
39 })
40 .collect(),
41 StreamEncoding::Latin1 => value
42 .chars()
43 .map(|character| {
44 if (character as u32) < 0x100 {
45 character as u8
46 } else {
47 b'?'
48 }
49 })
50 .collect(),
51 }
52 }
53
54 fn decode(self, bytes: &[u8]) -> String {
56 match self {
57 StreamEncoding::Utf8 => String::from_utf8_lossy(bytes).into_owned(),
58 StreamEncoding::Ascii => bytes
59 .iter()
60 .map(|byte| {
61 if *byte < 0x80 {
62 *byte as char
63 } else {
64 '?'
65 }
66 })
67 .collect(),
68 StreamEncoding::Latin1 => bytes.iter().map(|byte| *byte as char).collect(),
69 }
70 }
71}
72
73#[async_trait]
75pub trait StreamReadHelpers: AsyncRead + Send + Unpin {
76 async fn read_int16(&mut self) -> Result<i16, SteamError> {
78 let mut data = [0u8; 2];
79 self.read_exact(&mut data).await?;
80 Ok(i16::from_le_bytes(data))
81 }
82
83 async fn read_uint16(&mut self) -> Result<u16, SteamError> {
85 let mut data = [0u8; 2];
86 self.read_exact(&mut data).await?;
87 Ok(u16::from_le_bytes(data))
88 }
89
90 async fn read_int32(&mut self) -> Result<i32, SteamError> {
92 let mut data = [0u8; 4];
93 self.read_exact(&mut data).await?;
94 Ok(i32::from_le_bytes(data))
95 }
96
97 async fn read_int64(&mut self) -> Result<i64, SteamError> {
99 let mut data = [0u8; 8];
100 self.read_exact(&mut data).await?;
101 Ok(i64::from_le_bytes(data))
102 }
103
104 async fn read_uint32(&mut self) -> Result<u32, SteamError> {
106 let mut data = [0u8; 4];
107 self.read_exact(&mut data).await?;
108 Ok(u32::from_le_bytes(data))
109 }
110
111 async fn read_uint64(&mut self) -> Result<u64, SteamError> {
113 let mut data = [0u8; 8];
114 self.read_exact(&mut data).await?;
115 Ok(u64::from_le_bytes(data))
116 }
117
118 async fn read_float(&mut self) -> Result<f32, SteamError> {
120 let mut data = [0u8; 4];
121 self.read_exact(&mut data).await?;
122 Ok(f32::from_le_bytes(data))
123 }
124
125 async fn read_null_term_string(
128 &mut self,
129 encoding: StreamEncoding,
130 ) -> Result<String, SteamError> {
131 let mut result: Vec<u8> = Vec::new();
132
133 if encoding == StreamEncoding::Utf8 {
134 loop {
137 let mut byte = [0u8; 1];
138
139 let read = self.read(&mut byte).await?;
140
141 if read == 0 || byte[0] == 0 {
142 break;
143 }
144
145 result.push(byte[0]);
146 }
147 } else {
148 let character_size = encoding.character_size();
149 let mut chunk = vec![0u8; character_size];
150
151 loop {
152 chunk.fill(0);
153
154 let mut read = 0;
156
157 while read < chunk.len() {
158 let count = self.read(&mut chunk[read..]).await?;
159
160 if count == 0 {
161 break;
162 }
163
164 read += count;
165 }
166
167 if read == 0 {
168 break;
169 }
170
171 if encoding.decode(&chunk) == "\0" {
172 break;
173 }
174
175 result.extend_from_slice(&chunk);
176 }
177 }
178
179 Ok(encoding.decode(&result))
180 }
181
182 async fn read_all(&mut self, buffer: &mut [u8]) -> Result<usize, SteamError> {
185 let mut read = 0;
186
187 while read < buffer.len() {
188 let count = self.read(&mut buffer[read..]).await?;
189
190 if count == 0 {
191 break;
192 }
193
194 read += count;
195 }
196
197 Ok(read)
198 }
199}
200
201#[async_trait]
203pub trait StreamWriteHelpers: AsyncWrite + Send + Unpin {
204 async fn write_null_term_string(
206 &mut self,
207 value: &str,
208 encoding: StreamEncoding,
209 ) -> Result<(), SteamError> {
210 let mut bytes = encoding.encode(value);
211 bytes.push(0);
212
213 self.write_all(&bytes).await?;
214 self.flush().await?;
215
216 Ok(())
217 }
218}
219
220impl<R> StreamReadHelpers for R where R: AsyncRead + Send + Unpin {}
221
222impl<W> StreamWriteHelpers for W where W: AsyncWrite + Send + Unpin {}