Skip to main content

egdata_manifests_parser/parser/
reader.rs

1//! Tiny helpers for LE primitives and UE-style FStrings.
2
3use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
4use std::io::{self, Read, Seek, SeekFrom};
5use uuid::Uuid;
6
7/// Extension methods, implemented for every `Read`.
8pub trait ReadExt: Read + Seek {
9  fn i32(&mut self) -> io::Result<i32> {
10    self.read_i32::<LittleEndian>()
11  }
12  fn u8(&mut self) -> io::Result<u8> {
13    self.read_u8()
14  }
15  fn u32(&mut self) -> io::Result<u32> {
16    self.read_u32::<LittleEndian>()
17  }
18  fn i64(&mut self) -> io::Result<i64> {
19    self.read_i64::<LittleEndian>()
20  }
21  fn u64(&mut self) -> io::Result<u64> {
22    self.read_u64::<LittleEndian>()
23  }
24
25  // Additional primitive type readers
26  fn i8(&mut self) -> io::Result<i8> {
27    self.read_i8()
28  }
29  fn i16(&mut self) -> io::Result<i16> {
30    self.read_i16::<LittleEndian>()
31  }
32  fn u16(&mut self) -> io::Result<u16> {
33    self.read_u16::<LittleEndian>()
34  }
35  fn bool(&mut self) -> io::Result<bool> {
36    self.read_u8().map(|b| b != 0)
37  }
38  fn f32(&mut self) -> io::Result<f32> {
39    self.read_f32::<LittleEndian>()
40  }
41  fn f64(&mut self) -> io::Result<f64> {
42    self.read_f64::<LittleEndian>()
43  }
44
45  /// Read exactly n bytes
46  fn read_bytes(&mut self, count: usize) -> io::Result<Vec<u8>> {
47    if count == 0 {
48      return Ok(Vec::new());
49    }
50    let mut buf = vec![0u8; count];
51    self.read_exact(&mut buf)?;
52    Ok(buf)
53  }
54
55  /// Read a GUID (UUID) stored as 4 uint32 segments in Big Endian
56  fn guid(&mut self) -> io::Result<Uuid> {
57    let mut data = [0u32; 4];
58    for i in 0..4 {
59      data[i] = self.read_u32::<byteorder::BigEndian>()?;
60    }
61    let mut guid_bytes = [0u8; 16];
62    for i in 0..4 {
63      LittleEndian::write_u32(&mut guid_bytes[i * 4..(i + 1) * 4], data[i]);
64    }
65    Ok(Uuid::from_bytes(guid_bytes))
66  }
67
68  /// Peek n bytes without advancing the reader
69  fn peek(&mut self, n: usize) -> io::Result<Vec<u8>> {
70    let pos = self.stream_position()?;
71    let bytes = self.read_bytes(n)?;
72    self.seek(SeekFrom::Start(pos))?;
73    Ok(bytes)
74  }
75
76  /// Unreal's FString (32-bit length, optionally null-terminated)
77  fn fstring(&mut self) -> io::Result<String> {
78    let len = self.u32()?;
79    if len == 0 {
80      return Ok(String::new());
81    }
82
83    // Add reasonable size limit
84    const MAX_REASONABLE_STRING_LENGTH: u32 = 1024 * 1024 * 1024; // 1GB max string length
85    if len > MAX_REASONABLE_STRING_LENGTH {
86      return Err(io::Error::new(
87        io::ErrorKind::InvalidData,
88        format!(
89          "String length ({}) exceeds maximum allowed size of {} bytes",
90          len, MAX_REASONABLE_STRING_LENGTH
91        ),
92      ));
93    }
94
95    let mut buf = vec![0u8; len as usize];
96    self.read_exact(&mut buf)?;
97
98    // Use the length field directly to determine string length
99    // This handles both null-terminated and non-null-terminated strings
100    Ok(String::from_utf8_lossy(&buf).to_string())
101  }
102
103  fn fstring_array(&mut self) -> io::Result<Vec<String>> {
104    let len = self.u32()? as usize;
105    let mut strings = Vec::with_capacity(len);
106    for _ in 0..len {
107      strings.push(self.fstring()?);
108    }
109    Ok(strings)
110  }
111
112  fn skip(&mut self, bytes: u64) -> io::Result<()> {
113    self.seek(SeekFrom::Current(bytes as i64))?;
114    Ok(())
115  }
116}
117
118impl<T: Read + Seek + ?Sized> ReadExt for T {}