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}