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
//! Disc image format and filesystem type definitions.
use std::path::Path;
/// Supported disc image container formats.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiscFormat {
/// Plain ISO 9660 image (`.iso`, `.toast`) — 2048-byte cooked sectors.
Iso,
/// Raw binary with CUE sheet (`.bin` + `.cue`) — 2352-byte raw sectors.
BinCue,
/// MAME Compressed Hunks of Data, optical variant (`.chd`).
Chd,
/// Media Descriptor Sidecar (`.mds` + `.mdf`) — not yet implemented.
MdsMdf,
}
impl DiscFormat {
/// Detect format from file extension (case-insensitive).
pub fn from_path(path: impl AsRef<Path>) -> Option<Self> {
let ext = path.as_ref().extension()?.to_str()?.to_lowercase();
match ext.as_str() {
"iso" | "toast" => Some(Self::Iso),
"bin" | "cue" => Some(Self::BinCue),
"chd" => Some(Self::Chd),
"mds" | "mdf" => Some(Self::MdsMdf),
_ => None,
}
}
/// Human-readable name for this format.
pub fn display_name(self) -> &'static str {
match self {
Self::Iso => "ISO image",
Self::BinCue => "BIN/CUE",
Self::Chd => "CHD (Compressed Hunks of Data)",
Self::MdsMdf => "MDS/MDF",
}
}
/// File extensions associated with this format.
pub fn extensions(self) -> &'static [&'static str] {
match self {
Self::Iso => &["iso", "toast"],
Self::BinCue => &["bin", "cue"],
Self::Chd => &["chd"],
Self::MdsMdf => &["mds", "mdf"],
}
}
}
/// All file extensions recognised by the library, for use in file-open dialogs.
pub fn supported_extensions() -> &'static [&'static str] {
&["iso", "toast", "bin", "cue", "chd", "mds", "mdf"]
}
/// Filesystem type found on the data track of a disc.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilesystemType {
/// ISO 9660 standard filesystem (data CDs, DVDs).
Iso9660,
/// Joliet extensions (Unicode long filenames on top of ISO 9660).
Joliet,
/// Universal Disk Format (DVDs, Blu-ray).
Udf,
/// Classic HFS (Macintosh CDs, pre-Mac OS X).
Hfs,
/// HFS+ / Mac OS Extended (Mac OS X CDs and DVDs).
HfsPlus,
/// SGI EFS (Extent File System) — IRIX install/distribution CDs.
Efs,
/// Could not be determined.
Unknown,
}
impl FilesystemType {
/// Human-readable name.
pub fn display_name(self) -> &'static str {
match self {
Self::Iso9660 => "ISO 9660",
Self::Joliet => "Joliet",
Self::Udf => "UDF",
Self::Hfs => "HFS",
Self::HfsPlus => "HFS+",
Self::Efs => "EFS",
Self::Unknown => "Unknown",
}
}
/// Returns true if this filesystem can be browsed by the library.
pub fn is_browsable(self) -> bool {
matches!(self, Self::Iso9660 | Self::Hfs | Self::HfsPlus | Self::Efs)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_from_extension() {
assert_eq!(DiscFormat::from_path("game.iso"), Some(DiscFormat::Iso));
assert_eq!(DiscFormat::from_path("game.ISO"), Some(DiscFormat::Iso));
assert_eq!(DiscFormat::from_path("game.toast"), Some(DiscFormat::Iso));
assert_eq!(DiscFormat::from_path("game.bin"), Some(DiscFormat::BinCue));
assert_eq!(DiscFormat::from_path("game.cue"), Some(DiscFormat::BinCue));
assert_eq!(DiscFormat::from_path("game.chd"), Some(DiscFormat::Chd));
assert_eq!(DiscFormat::from_path("game.txt"), None);
}
}