1use std::{
2 mem::{align_of, size_of},
3 ops::Range,
4};
5
6use bytemuck::{Pod, PodCastError, Zeroable};
7use snafu::{Backtrace, Snafu};
8
9use super::RawHeaderError;
10
11#[repr(C)]
13#[derive(Clone, Copy, Zeroable, Pod, Default)]
14pub struct FileAlloc {
15 pub start: u32,
17 pub end: u32,
19}
20
21#[derive(Debug, Snafu)]
23pub enum RawFatError {
24 #[snafu(transparent)]
26 RawHeader {
27 source: RawHeaderError,
29 },
30 #[snafu(display("file allocation table must be a multiple of {} bytes", size_of::<FileAlloc>()))]
32 InvalidSize {
33 backtrace: Backtrace,
35 },
36 #[snafu(display("expected {expected}-alignment for autoload infos but got {actual}-alignment:\n{backtrace}"))]
38 Misaligned {
39 expected: usize,
41 actual: usize,
43 backtrace: Backtrace,
45 },
46}
47
48impl FileAlloc {
49 fn check_size(data: &'_ [u8]) -> Result<(), RawFatError> {
50 let size = size_of::<Self>();
51 if !data.len().is_multiple_of(size) {
52 InvalidSizeSnafu {}.fail()
53 } else {
54 Ok(())
55 }
56 }
57
58 fn handle_pod_cast<T>(result: Result<T, PodCastError>, addr: usize) -> Result<T, RawFatError> {
59 match result {
60 Ok(build_info) => Ok(build_info),
61 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
62 MisalignedSnafu { expected: align_of::<Self>(), actual: 1usize << addr.trailing_zeros() }.fail()
63 }
64 Err(PodCastError::AlignmentMismatch) => panic!(),
65 Err(PodCastError::OutputSliceWouldHaveSlop) => panic!(),
66 Err(PodCastError::SizeMismatch) => unreachable!(),
67 }
68 }
69
70 pub fn borrow_from_slice(data: &'_ [u8]) -> Result<&'_ [Self], RawFatError> {
76 Self::check_size(data)?;
77 let addr = data as *const [u8] as *const () as usize;
78 Self::handle_pod_cast(bytemuck::try_cast_slice(data), addr)
79 }
80
81 pub fn into_file(self, rom: &[u8]) -> &[u8] {
83 &rom[self.start as usize..self.end as usize]
84 }
85
86 pub fn range(self) -> Range<usize> {
88 self.start as usize..self.end as usize
89 }
90}