use super::super::fat_table::FatType;
#[derive(Debug, Clone)]
pub struct FormatOptions {
pub volume_size: u64,
pub volume_label: VolumeLabel,
pub oem_name: OemName,
pub sector_size: SectorSize,
pub sectors_per_cluster: Option<u8>,
pub fat_type: FatTypeSelection,
pub fat_copies: u8,
pub root_entry_count: u16,
pub hidden_sectors: u32,
pub media_type: MediaType,
pub volume_id: Option<u32>,
}
impl Default for FormatOptions {
fn default() -> Self {
Self {
volume_size: 0,
volume_label: VolumeLabel::default(),
oem_name: OemName::default(),
sector_size: SectorSize::default(),
sectors_per_cluster: None,
fat_type: FatTypeSelection::Auto,
fat_copies: 2,
root_entry_count: 512,
hidden_sectors: 0,
media_type: MediaType::FixedDisk,
volume_id: None,
}
}
}
impl FormatOptions {
pub fn new(volume_size: u64) -> Self {
Self {
volume_size,
..Default::default()
}
}
pub fn with_label(mut self, label: &str) -> Self {
self.volume_label = VolumeLabel::new(label);
self
}
pub fn with_sector_size(mut self, size: SectorSize) -> Self {
self.sector_size = size;
self
}
pub fn with_fat_type(mut self, fat_type: FatTypeSelection) -> Self {
self.fat_type = fat_type;
self
}
pub fn with_sectors_per_cluster(mut self, spc: u8) -> Self {
self.sectors_per_cluster = Some(spc);
self
}
pub fn with_fat_copies(mut self, copies: u8) -> Self {
self.fat_copies = copies.clamp(1, 2);
self
}
pub fn with_media_type(mut self, media_type: MediaType) -> Self {
self.media_type = media_type;
self
}
pub fn with_hidden_sectors(mut self, hidden: u32) -> Self {
self.hidden_sectors = hidden;
self
}
pub fn with_volume_id(mut self, id: u32) -> Self {
self.volume_id = Some(id);
self
}
}
#[derive(Debug, Clone)]
pub struct VolumeLabel([u8; 11]);
impl VolumeLabel {
pub fn new(s: &str) -> Self {
let mut bytes = [b' '; 11];
for (i, c) in s.chars().take(11).enumerate() {
let c = c.to_ascii_uppercase();
if c.is_ascii() && Self::is_valid_char(c as u8) {
bytes[i] = c as u8;
} else {
bytes[i] = b'_';
}
}
Self(bytes)
}
pub fn no_name() -> Self {
Self(*b"NO NAME ")
}
fn is_valid_char(c: u8) -> bool {
matches!(c, b'A'..=b'Z' | b'0'..=b'9' | b' ' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'(' | b')' | b'-' | b'@' | b'^' | b'_' | b'`' | b'{' | b'}' | b'~')
}
pub fn as_bytes(&self) -> &[u8; 11] {
&self.0
}
}
impl Default for VolumeLabel {
fn default() -> Self {
Self::no_name()
}
}
#[derive(Debug, Clone)]
pub struct OemName([u8; 8]);
impl OemName {
pub fn new(s: &str) -> Self {
let mut bytes = [b' '; 8];
for (i, c) in s.chars().take(8).enumerate() {
if c.is_ascii() {
bytes[i] = c as u8;
}
}
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; 8] {
&self.0
}
}
impl Default for OemName {
fn default() -> Self {
Self(*b"HADRISFT")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SectorSize {
#[default]
S512 = 512,
S1024 = 1024,
S2048 = 2048,
S4096 = 4096,
}
impl SectorSize {
pub fn bytes(self) -> usize {
self as usize
}
}
impl TryFrom<usize> for SectorSize {
type Error = ();
fn try_from(value: usize) -> Result<Self, Self::Error> {
match value {
512 => Ok(Self::S512),
1024 => Ok(Self::S1024),
2048 => Ok(Self::S2048),
4096 => Ok(Self::S4096),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FatTypeSelection {
#[default]
Auto,
Fat12,
Fat16,
Fat32,
}
impl FatTypeSelection {
pub fn as_fat_type(self) -> Option<FatType> {
match self {
Self::Auto => None,
Self::Fat12 => Some(FatType::Fat12),
Self::Fat16 => Some(FatType::Fat16),
Self::Fat32 => Some(FatType::Fat32),
}
}
}
impl From<FatType> for FatTypeSelection {
fn from(fat_type: FatType) -> Self {
match fat_type {
FatType::Fat12 => Self::Fat12,
FatType::Fat16 => Self::Fat16,
FatType::Fat32 => Self::Fat32,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum MediaType {
#[default]
FixedDisk,
Removable,
Custom(u8),
}
impl MediaType {
pub fn value(self) -> u8 {
match self {
Self::FixedDisk => 0xF8,
Self::Removable => 0xF0,
Self::Custom(v) => v,
}
}
}