pub mod bsi;
pub mod cdrom;
pub mod cht;
pub mod fnt;
pub mod fnt_export;
pub mod fnt_ttf;
pub mod fog_ini;
pub mod glide_splash;
pub mod gxa;
pub mod keys_ini;
pub mod menu_ini;
pub mod menu_movies;
pub mod menu_settings;
pub mod model3d;
pub mod palette;
pub mod palette_export;
pub mod png;
pub mod pvo;
pub mod registry;
pub mod rgm;
pub mod rob;
pub mod rtx;
pub mod sfx;
pub mod smacker;
pub mod soup_def;
pub mod wld;
pub mod world_ini;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, clap::ValueEnum)]
pub enum FileType {
Bsi, Cht, Col, Model3d, Model3dc, Rob, Rgm, Pvo, Wld, Fnt, Gxa, Sfx, Rtx, }
const ALL_FILE_TYPES: [FileType; 13] = [
FileType::Bsi,
FileType::Cht,
FileType::Col,
FileType::Model3d,
FileType::Model3dc,
FileType::Rob,
FileType::Rgm,
FileType::Pvo,
FileType::Wld,
FileType::Fnt,
FileType::Gxa,
FileType::Sfx,
FileType::Rtx,
];
impl FileType {
#[must_use]
pub const fn all() -> &'static [Self] {
&ALL_FILE_TYPES
}
#[must_use]
pub const fn display_name(self) -> &'static str {
match self {
Self::Bsi => "Texture BSI",
Self::Cht => "Cheat States",
Self::Col => "Palette",
Self::Model3d => "Model",
Self::Model3dc => "Animated Model",
Self::Rob => "ROB World",
Self::Rgm => "Map Data",
Self::Pvo => "PVO Data",
Self::Wld => "World Geometry",
Self::Fnt => "Font",
Self::Gxa => "GXA Bitmap",
Self::Sfx => "Sound Effects",
Self::Rtx => "Dialogue Audio",
}
}
#[must_use]
pub const fn extensions(self) -> &'static [&'static str] {
match self {
Self::Bsi => &[".bsi"],
Self::Cht => &[".cht"],
Self::Col => &[".col"],
Self::Model3d => &[".3d"],
Self::Model3dc => &[".3dc"],
Self::Rob => &[".rob"],
Self::Rgm => &[".rgm"],
Self::Pvo => &[".pvo"],
Self::Wld => &[".wld"],
Self::Fnt => &[".fnt"],
Self::Gxa => &[".gxa"],
Self::Sfx => &[".sfx"],
Self::Rtx => &[".rtx"],
}
}
#[must_use]
pub fn from_extension(ext: &str) -> Option<Self> {
let lower = ext.to_ascii_lowercase();
Self::all().iter().copied().find(|ft| {
ft.extensions()
.iter()
.any(|e| e.trim_start_matches('.') == lower)
})
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Option<Self> {
let p = path.as_ref();
if let Some(ext) = p.extension().and_then(|e| e.to_str())
&& let Some(ft) = Self::from_extension(ext)
{
return Some(ft);
}
let stem = p.file_stem()?.to_str()?.to_ascii_uppercase();
if stem == "TEXBSI" {
return Some(Self::Bsi);
}
None
}
}
impl std::str::FromStr for FileType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_extension(s.trim()).ok_or_else(|| {
let supported = Self::all()
.iter()
.flat_map(|ft| {
ft.extensions()
.iter()
.map(|ext| ext.trim_start_matches('.').to_string())
})
.collect::<Vec<_>>()
.join(", ");
format!("Unknown file type: {s}. Supported types: {supported}")
})
}
}