fromsoftware_shared/ext/
write.rs

1use std::io;
2
3/// An extension on top of [io::Write] that writes data with length delimiters
4/// so that it can be read back using
5/// [LengthDelimitedReadExt](super::LengthDelimitedReadExt). This is
6/// particularly useful for adding extra data before or after data structures
7/// written by FSW games.
8///
9/// The specific format used by this trait is a little-endian four-byte header
10/// indicating the length of the data in bytes, followed by the data itself.
11pub trait LengthDelimitedWriteExt {
12    /// Writes `data` to the underlying writer with a length delimiter.
13    ///
14    /// This is the dual of [LengthDelimitedReadExt.read_delimited].
15    fn write_delimited(&mut self, data: &[u8]) -> io::Result<usize>;
16
17    /// Writes `text` to the underlying writer as UTF-8 with a length delimiter.
18    ///
19    /// This is the dual of [LengthDelimitedReadExt.read_str_delimited].
20    fn write_str_delimited(&mut self, text: &str) -> io::Result<usize> {
21        self.write_delimited(text.as_bytes())
22    }
23}
24
25impl<T: ?Sized + io::Write> LengthDelimitedWriteExt for T {
26    fn write_delimited(&mut self, data: &[u8]) -> io::Result<usize> {
27        let delimiter = u32::try_from(data.len())
28            .map_err(io::Error::other)?
29            .to_le_bytes();
30
31        let size = self.write(&delimiter)?;
32        if size < delimiter.len() {
33            Ok(size)
34        } else {
35            Ok(size + self.write(data)?)
36        }
37    }
38}