hermes_tdata/
qdatastream.rs1use byteorder::{BigEndian, ReadBytesExt};
7use std::io::{Cursor, Read};
8
9use crate::{Error, Result};
10
11pub const QT_VERSION_5_1: u32 = 14;
13
14const NULL_MARKER: u32 = 0xFFFFFFFF;
16
17const EXTENDED_LENGTH_MARKER: u32 = 0xFFFFFFFE;
19
20pub struct QDataStream<'a> {
22 cursor: Cursor<&'a [u8]>,
23 version: u32,
24}
25
26impl<'a> QDataStream<'a> {
27 pub fn new(data: &'a [u8]) -> Self {
29 Self {
30 cursor: Cursor::new(data),
31 version: QT_VERSION_5_1,
32 }
33 }
34
35 pub fn with_version(data: &'a [u8], version: u32) -> Self {
37 Self {
38 cursor: Cursor::new(data),
39 version,
40 }
41 }
42
43 pub fn version(&self) -> u32 {
45 self.version
46 }
47
48 pub fn position(&self) -> u64 {
50 self.cursor.position()
51 }
52
53 pub fn at_end(&self) -> bool {
55 self.remaining() == 0
56 }
57
58 pub fn remaining(&self) -> usize {
60 let len = self.cursor.get_ref().len();
61 usize::try_from(self.cursor.position()).map_or(0, |pos| len.saturating_sub(pos))
62 }
63
64 pub fn skip(&mut self, n: usize) -> Result<()> {
66 if self.remaining() < n {
67 return Err(Error::UnexpectedEof {
68 offset: self.position(),
69 });
70 }
71
72 let offset = u64::try_from(n).map_err(|_| Error::UnexpectedEof {
73 offset: self.position(),
74 })?;
75 let next = self
76 .position()
77 .checked_add(offset)
78 .ok_or(Error::UnexpectedEof {
79 offset: self.position(),
80 })?;
81 self.cursor.set_position(next);
82 Ok(())
83 }
84
85 pub fn read_u8(&mut self) -> Result<u8> {
87 self.cursor.read_u8().map_err(|_| Error::UnexpectedEof {
88 offset: self.position(),
89 })
90 }
91
92 pub fn read_i8(&mut self) -> Result<i8> {
94 self.cursor.read_i8().map_err(|_| Error::UnexpectedEof {
95 offset: self.position(),
96 })
97 }
98
99 pub fn read_u16(&mut self) -> Result<u16> {
101 self.cursor
102 .read_u16::<BigEndian>()
103 .map_err(|_| Error::UnexpectedEof {
104 offset: self.position(),
105 })
106 }
107
108 pub fn read_i16(&mut self) -> Result<i16> {
110 self.cursor
111 .read_i16::<BigEndian>()
112 .map_err(|_| Error::UnexpectedEof {
113 offset: self.position(),
114 })
115 }
116
117 pub fn read_u32(&mut self) -> Result<u32> {
119 self.cursor
120 .read_u32::<BigEndian>()
121 .map_err(|_| Error::UnexpectedEof {
122 offset: self.position(),
123 })
124 }
125
126 pub fn read_i32(&mut self) -> Result<i32> {
128 self.cursor
129 .read_i32::<BigEndian>()
130 .map_err(|_| Error::UnexpectedEof {
131 offset: self.position(),
132 })
133 }
134
135 pub fn read_u64(&mut self) -> Result<u64> {
137 self.cursor
138 .read_u64::<BigEndian>()
139 .map_err(|_| Error::UnexpectedEof {
140 offset: self.position(),
141 })
142 }
143
144 pub fn read_i64(&mut self) -> Result<i64> {
146 self.cursor
147 .read_i64::<BigEndian>()
148 .map_err(|_| Error::UnexpectedEof {
149 offset: self.position(),
150 })
151 }
152
153 pub fn read_bool(&mut self) -> Result<bool> {
155 Ok(self.read_u8()? != 0)
156 }
157
158 pub fn read_f32(&mut self) -> Result<f32> {
160 self.cursor
161 .read_f32::<BigEndian>()
162 .map_err(|_| Error::UnexpectedEof {
163 offset: self.position(),
164 })
165 }
166
167 pub fn read_f64(&mut self) -> Result<f64> {
169 self.cursor
170 .read_f64::<BigEndian>()
171 .map_err(|_| Error::UnexpectedEof {
172 offset: self.position(),
173 })
174 }
175
176 pub fn read_raw(&mut self, len: usize) -> Result<Vec<u8>> {
178 if self.remaining() < len {
179 return Err(Error::UnexpectedEof {
180 offset: self.position(),
181 });
182 }
183
184 let mut buf = vec![0u8; len];
185 self.cursor
186 .read_exact(&mut buf)
187 .map_err(|_| Error::UnexpectedEof {
188 offset: self.position(),
189 })?;
190 Ok(buf)
191 }
192
193 pub fn read_qbytearray(&mut self) -> Result<Vec<u8>> {
201 let len = self.read_u32()?;
202
203 match len {
204 NULL_MARKER => Ok(Vec::new()),
205 EXTENDED_LENGTH_MARKER => {
206 let real_len = usize::try_from(self.read_u64()?)
208 .map_err(|_| Error::qdatastream("QByteArray length is too large"))?;
209 self.read_raw(real_len)
210 }
211 _ => self.read_raw(
212 usize::try_from(len)
213 .map_err(|_| Error::qdatastream("QByteArray length is too large"))?,
214 ),
215 }
216 }
217
218 pub fn read_qstring(&mut self) -> Result<String> {
225 let byte_len = self.read_u32()?;
226
227 if byte_len == NULL_MARKER {
228 return Ok(String::new());
229 }
230
231 if byte_len % 2 != 0 {
232 return Err(Error::qdatastream("QString byte length is not even"));
233 }
234
235 let char_count = usize::try_from(byte_len / 2)
236 .map_err(|_| Error::qdatastream("QString length is too large"))?;
237 let mut utf16: Vec<u16> = Vec::with_capacity(char_count);
238
239 for _ in 0..char_count {
240 utf16.push(self.read_u16()?);
241 }
242
243 String::from_utf16(&utf16).map_err(|_| Error::InvalidUtf16)
244 }
245
246 pub fn read_cstring(&mut self) -> Result<String> {
252 let data = self.read_qbytearray()?;
253
254 let data = data.strip_suffix(&[0]).unwrap_or(&data);
256
257 String::from_utf8(data.to_vec())
258 .map_err(|_| Error::qdatastream("invalid UTF-8 in C string"))
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 #[test]
267 fn test_read_u32() -> Result<()> {
268 let data = [0x12, 0x34, 0x56, 0x78];
269 let mut stream = QDataStream::new(&data);
270 assert_eq!(stream.read_u32()?, 0x12345678);
271 Ok(())
272 }
273
274 #[test]
275 fn test_read_i32() -> Result<()> {
276 let data = [0xFF, 0xFF, 0xFF, 0xFE]; let mut stream = QDataStream::new(&data);
278 assert_eq!(stream.read_i32()?, -2);
279 Ok(())
280 }
281
282 #[test]
283 fn test_read_qbytearray() -> Result<()> {
284 let data = [0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04];
286 let mut stream = QDataStream::new(&data);
287 assert_eq!(stream.read_qbytearray()?, vec![0x01, 0x02, 0x03, 0x04]);
288 Ok(())
289 }
290
291 #[test]
292 fn test_read_null_qbytearray() -> Result<()> {
293 let data = [0xFF, 0xFF, 0xFF, 0xFF];
294 let mut stream = QDataStream::new(&data);
295 assert!(stream.read_qbytearray()?.is_empty());
296 Ok(())
297 }
298
299 #[test]
300 fn test_read_qstring() -> Result<()> {
301 let data = [0x00, 0x00, 0x00, 0x04, 0x00, 0x48, 0x00, 0x69];
303 let mut stream = QDataStream::new(&data);
304 assert_eq!(stream.read_qstring()?, "Hi");
305 Ok(())
306 }
307
308 #[test]
309 fn test_read_null_qstring() -> Result<()> {
310 let data = [0xFF, 0xFF, 0xFF, 0xFF];
311 let mut stream = QDataStream::new(&data);
312 assert!(stream.read_qstring()?.is_empty());
313 Ok(())
314 }
315
316 #[test]
317 fn test_position_and_remaining() -> Result<()> {
318 let data = [0x01, 0x02, 0x03, 0x04, 0x05];
319 let mut stream = QDataStream::new(&data);
320
321 assert_eq!(stream.position(), 0);
322 assert_eq!(stream.remaining(), 5);
323
324 stream.read_u8()?;
325 assert_eq!(stream.position(), 1);
326 assert_eq!(stream.remaining(), 4);
327
328 stream.skip(2)?;
329 assert_eq!(stream.position(), 3);
330 assert_eq!(stream.remaining(), 2);
331 Ok(())
332 }
333
334 #[test]
335 fn test_at_end() -> Result<()> {
336 let data = [0x01, 0x02];
337 let mut stream = QDataStream::new(&data);
338
339 assert!(!stream.at_end());
340 stream.read_u16()?;
341 assert!(stream.at_end());
342 Ok(())
343 }
344}