Skip to main content

firmion_output_buffer/
output_buffer.rs

1// Output buffer abstraction for creating the raw binary image.
2//
3// OutputBuffer accumulates the binary image in a Vec<u8> during the exec
4// phase.  Sequential append operations build the image in pass 1; random-
5// access patch writes let extensions overwrite their pre-reserved zero-filled
6// slots in pass 2.  The completed image is written to disk in a single call.
7//
8
9// Don't clutter upstream docs.rs for an otherwise private library.
10#![doc(hidden)]
11
12use std::fs::File;
13use std::io::{self, Read, Write};
14
15pub struct OutputBuffer {
16    data: Vec<u8>,
17}
18
19impl Default for OutputBuffer {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25impl OutputBuffer {
26    pub fn new() -> Self {
27        Self { data: Vec::new() }
28    }
29
30    /// Appends bytes to the buffer.  Infallible.
31    pub fn append(&mut self, bytes: &[u8]) {
32        self.data.extend_from_slice(bytes);
33    }
34
35    /// Appends count zero bytes.  Infallible.
36    /// Reserves space for extension output slots before pass 2 patches them.
37    pub fn append_zeros(&mut self, count: usize) {
38        self.data.resize(self.data.len() + count, 0);
39    }
40
41    /// Reads exactly byte_count bytes from source and appends them.
42    /// Caller seeks source to the correct file position before calling.
43    pub fn append_from_file(&mut self, source: &mut File, byte_count: u64) -> io::Result<()> {
44        let start = self.data.len();
45        self.data.resize(start + byte_count as usize, 0);
46        source.read_exact(&mut self.data[start..])?;
47        Ok(())
48    }
49
50    /// Returns a slice of the buffer at [start..end].
51    /// Used to build ParamArg::Slice values for extension Slice params.
52    pub fn slice(&self, start: usize, end: usize) -> &[u8] {
53        &self.data[start..end]
54    }
55
56    /// Overwrites the bytes at offset with data.
57    /// Used by execute_extensions to patch extension output into the image.
58    /// Panics if offset + data.len() exceeds len(): the caller guarantees
59    /// the slot was pre-reserved, so out-of-bounds is a compiler bug.
60    pub fn patch(&mut self, offset: usize, data: &[u8]) {
61        self.data[offset..offset + data.len()].copy_from_slice(data);
62    }
63
64    /// Returns the current byte count.
65    pub fn len(&self) -> usize {
66        self.data.len()
67    }
68
69    /// Returns true when the buffer holds no bytes.
70    pub fn is_empty(&self) -> bool {
71        self.data.is_empty()
72    }
73
74    /// Writes the entire buffer to file in one call.
75    pub fn write_to_file(&self, file: &mut File) -> io::Result<()> {
76        file.write_all(&self.data)
77    }
78}