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}