amebazii/types/
section.rs

1use std::vec;
2
3use super::{
4    from_stream,
5    header::{EntryHeader, SectionHeader},
6    BinarySize, FromStream, ToStream,
7};
8use crate::{error::Error, util::skip_aligned, util::write_fill, write_aligned};
9
10/// Represents a section in a sub-image.
11///
12/// This struct encapsulates a section within the image, consisting of the following components:
13///
14/// - `header`: The metadata and configuration for the section (represented by `SectionHeader`).
15/// - `entry_header`: The header that defines the entry point and loading address of the section (represented by `EntryHeader`).
16/// - `data`: A `Vec<u8>` containing the raw data for the section, which can be processed or manipulated as needed.
17///
18/// # Default Values:
19/// - The `header` and `entry_header` are initialized with their default values.
20/// - The `data` is an empty vector by default.
21#[derive(Debug)]
22pub struct Section {
23    /// The metadata and configuration for the section.
24    pub header: SectionHeader,
25
26    /// The header that defines the entry point and loading address of the section.
27    pub entry_header: EntryHeader,
28
29    /// The raw data of the section.
30    data: Vec<u8>,
31}
32
33impl Default for Section {
34    /// Returns a default `Section` with default headers and an empty data vector.
35    fn default() -> Section {
36        Section {
37            header: SectionHeader::default(),
38            entry_header: EntryHeader::default(),
39            data: Vec::new(),
40        }
41    }
42}
43
44impl Section {
45    // ------------------------------------------------------------------------------------
46    // Static Methods
47    // ------------------------------------------------------------------------------------
48
49    /// Creates a new `Section` with a specified data capacity.
50    ///
51    /// This static method allows you to create a new `Section` with a predefined data capacity.
52    /// The `data` field will be initialized as a vector of zeroed bytes with the given size.
53    ///
54    /// # Parameters:
55    /// - `capacity`: The size (in bytes) to which the `data` vector should be initialized.
56    ///
57    /// # Returns:
58    /// A new `Section` instance with the specified `capacity` for its `data` field.
59    ///
60    /// # Example:
61    /// ```rust
62    /// let section = Section::new_with_size(1024);
63    /// ```
64    pub fn new_with_size(capacity: usize) -> Section {
65        Section {
66            header: SectionHeader::default(),
67            entry_header: EntryHeader::default(),
68            data: vec![0; capacity],
69        }
70    }
71
72    // ------------------------------------------------------------------------------------
73    // Instance Methods
74    // ------------------------------------------------------------------------------------
75
76    /// Returns a reference to the section's data.
77    ///
78    /// # Returns:
79    /// A slice of the section's data (`&[u8]`).
80    pub fn get_data(&self) -> &[u8] {
81        return &self.data;
82    }
83
84    /// Computes the aligned length of the section data, ensuring it is padded to a 0x20-byte boundary.
85    ///
86    /// This function calculates the total length of the section (including the `EntryHeader` and the
87    /// section's data) and ensures that the result is aligned to a 0x20-byte boundary.
88    ///
89    /// # Returns:
90    /// - `u32`: The aligned length of the section, including the `EntryHeader` and section data.
91    pub fn build_aligned_length(&self) -> u32 {
92        let length = EntryHeader::binary_size() + self.data.len();
93        let alignment = length % 0x20;
94        if alignment == 0 {
95            length as u32
96        } else {
97            (length + (0x20 - alignment)) as u32
98        }
99    }
100
101    /// Computes the aligned size of the section, including the `SectionHeader`, `EntryHeader`, and section data.
102    ///
103    /// # Returns:
104    /// - `u32`: The aligned size of the section, including headers and data.
105    pub fn build_aligned_size(&self) -> u32 {
106        SectionHeader::binary_size() as u32 + self.build_aligned_length()
107    }
108
109    /// Replaces the current content of the `data` field with a new byte vector.
110    ///
111    /// # Arguments
112    ///
113    /// * `data` - The new byte data (`Vec<u8>`) to be assigned to the section.
114    pub fn set_data(&mut self, data: Vec<u8>) {
115        self.data = data;
116    }
117}
118
119impl FromStream for Section {
120    /// Reads a `Section` from a stream.
121    ///
122    /// # Parameters:
123    /// - `reader`: The stream (`Read + Seek`) from which the `Section` will be read.
124    ///
125    /// # Returns:
126    /// A result containing `Ok(())` if the section was successfully read, or an `Error` if something
127    /// went wrong during the process.
128    fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
129    where
130        R: std::io::Read + std::io::Seek,
131    {
132        self.header = from_stream(reader)?;
133        self.entry_header = from_stream(reader)?;
134        // length includes entry header size
135        self.data.resize(self.header.length as usize - 0x20, 0x00);
136        // Read the actual data for the section into the data buffer
137        reader.read_exact(&mut self.data)?;
138        skip_aligned(reader, 0x20)?;
139        Ok(())
140    }
141}
142
143impl ToStream for Section {
144    /// Writes a `Section` to a stream.
145    ///
146    /// # Parameters:
147    /// - `writer`: The stream (`Write + Seek`) to which the `Section` will be written.
148    ///
149    /// # Returns:
150    /// A result containing `Ok(())` if the section was successfully written, or an `Error` if something
151    /// went wrong during the process.
152    fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
153    where
154        W: std::io::Write + std::io::Seek,
155    {
156        self.header.write_to(writer)?;
157        self.entry_header.write_to(writer)?;
158        writer.write_all(&self.data)?;
159
160        // align the stream
161        write_aligned!(writer, 0x20, optional);
162        Ok(())
163    }
164}