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