diff --git a/src/main.rs b/src/main.rs index fcc0a76..b4fb8fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,15 +99,59 @@ pub fn parse_script( } _ => {} } + let mut exts_builder = Vec::new(); for builder in scripts::BUILDER.iter() { let exts = builder.extensions(); for ext in exts { if filename.to_lowercase().ends_with(ext) { - let encoding = get_encoding(arg, builder); - return Ok((builder.build_script(filename, encoding, config)?, builder)); + exts_builder.push(builder); } } } + let exts_builder = if exts_builder.is_empty() { + scripts::BUILDER.iter().collect::>() + } else { + exts_builder + }; + if exts_builder.len() == 1 { + let builder = exts_builder.first().unwrap(); + let encoding = get_encoding(arg, builder); + return Ok((builder.build_script(filename, encoding, config)?, builder)); + } + let mut buf = [0u8; 1024]; + let mut size = 0; + if filename != "-" { + let mut f = std::fs::File::open(filename)?; + size = std::io::Read::read(&mut f, &mut buf)?; + } + let mut scores = Vec::new(); + for builder in exts_builder.iter() { + if let Some(score) = builder.is_this_format(filename, &buf, size) { + scores.push((score, builder)); + } + } + if scores.is_empty() { + return Err(anyhow::anyhow!("Unsupported script type")); + } + let max_score = scores.iter().map(|s| s.0).max().unwrap(); + let mut best_builders = Vec::new(); + for (score, builder) in scores.iter() { + if *score == max_score { + best_builders.push(builder); + } + } + if best_builders.len() == 1 { + let builder = best_builders.first().unwrap(); + let encoding = get_encoding(arg, builder); + return Ok((builder.build_script(filename, encoding, config)?, builder)); + } + if best_builders.len() > 1 { + eprintln!( + "Multiple script types found for {}: {:?}", + filename, best_builders + ); + return Err(anyhow::anyhow!("Multiple script types found")); + } Err(anyhow::anyhow!("Unsupported script type")) } diff --git a/src/scripts/base.rs b/src/scripts/base.rs index 0ae2696..2182081 100644 --- a/src/scripts/base.rs +++ b/src/scripts/base.rs @@ -1,7 +1,7 @@ use crate::types::*; use anyhow::Result; -pub trait ScriptBuilder { +pub trait ScriptBuilder: std::fmt::Debug { fn default_encoding(&self) -> Encoding; fn default_patched_encoding(&self) -> Encoding { @@ -17,6 +17,10 @@ pub trait ScriptBuilder { fn extensions(&self) -> &'static [&'static str]; + fn is_this_format(&self, _filename: &str, _buf: &[u8], _buf_len: usize) -> Option { + None + } + fn script_type(&self) -> &'static ScriptType; } diff --git a/src/scripts/bgi/script.rs b/src/scripts/bgi/script.rs index 954982b..10ae4cb 100644 --- a/src/scripts/bgi/script.rs +++ b/src/scripts/bgi/script.rs @@ -4,6 +4,7 @@ use crate::types::*; use crate::utils::encoding::{decode_to_string, encode_string}; use anyhow::Result; +#[derive(Debug)] pub struct BGIScriptBuilder {} impl BGIScriptBuilder { @@ -37,6 +38,13 @@ impl ScriptBuilder for BGIScriptBuilder { fn script_type(&self) -> &'static ScriptType { &ScriptType::BGI } + + fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option { + if buf_len > 28 && buf.starts_with(b"BurikoCompiledScriptVer1.00\0") { + return Some(255); + } + None + } } pub struct BGIScript { diff --git a/src/scripts/circus/script.rs b/src/scripts/circus/script.rs index efb4dda..6b21062 100644 --- a/src/scripts/circus/script.rs +++ b/src/scripts/circus/script.rs @@ -4,6 +4,7 @@ use crate::types::*; use crate::utils::encoding::{decode_to_string, encode_string}; use anyhow::Result; +#[derive(Debug)] pub struct CircusMesScriptBuilder {} impl CircusMesScriptBuilder { diff --git a/src/scripts/escude/mod.rs b/src/scripts/escude/mod.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/scripts/escude/mod.rs @@ -0,0 +1 @@ + diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index a08a780..eaf5f8e 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -1,6 +1,7 @@ pub mod base; pub mod bgi; pub mod circus; +pub mod escude; pub use base::{Script, ScriptBuilder};