mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-07-08 01:31:53 +08:00
BgiArchiveV1 add DSC decode support
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
use super::dsc::*;
|
||||||
use crate::ext::io::*;
|
use crate::ext::io::*;
|
||||||
use crate::scripts::base::*;
|
use crate::scripts::base::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
@@ -108,12 +109,17 @@ struct Entry<T: Read + Seek> {
|
|||||||
reader: Arc<Mutex<T>>,
|
reader: Arc<Mutex<T>>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
base_offset: u64,
|
base_offset: u64,
|
||||||
|
script_type: Option<ScriptType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read + Seek> ArchiveContent for Entry<T> {
|
impl<T: Read + Seek> ArchiveContent for Entry<T> {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
&self.header.filename
|
&self.header.filename
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn script_type(&self) -> Option<&ScriptType> {
|
||||||
|
self.script_type.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read + Seek> Read for Entry<T> {
|
impl<T: Read + Seek> Read for Entry<T> {
|
||||||
@@ -197,6 +203,48 @@ impl<T: Read + Seek + std::fmt::Debug + 'static> Script for BgiArchive<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MemEntry {
|
||||||
|
name: String,
|
||||||
|
data: MemReader,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for MemEntry {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
self.data.read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArchiveContent for MemEntry {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_type(&self) -> Option<&ScriptType> {
|
||||||
|
detect_script_type(&self.data.data, self.data.data.len(), &self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data(&mut self) -> Result<Vec<u8>> {
|
||||||
|
Ok(self.data.data.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_data<'a>(&'a mut self) -> Result<Box<dyn ReadSeek + 'a>> {
|
||||||
|
Ok(Box::new(&mut self.data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_script_type(buf: &[u8], buf_len: usize, filename: &str) -> Option<&'static ScriptType> {
|
||||||
|
if buf_len >= 28 && buf.starts_with(b"BurikoCompiledScriptVer1.00\0") {
|
||||||
|
return Some(&ScriptType::BGI);
|
||||||
|
}
|
||||||
|
let filename = filename.to_lowercase();
|
||||||
|
if filename.ends_with("._bp") {
|
||||||
|
return Some(&ScriptType::BGIBp);
|
||||||
|
} else if filename.ends_with("._bsi") {
|
||||||
|
return Some(&ScriptType::BGIBsi);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
struct BgiArchiveIter<'a, T: Iterator<Item = &'a BgiFileHeader>, R: Read + Seek> {
|
struct BgiArchiveIter<'a, T: Iterator<Item = &'a BgiFileHeader>, R: Read + Seek> {
|
||||||
entries: T,
|
entries: T,
|
||||||
reader: Arc<Mutex<R>>,
|
reader: Arc<Mutex<R>>,
|
||||||
@@ -213,12 +261,63 @@ impl<'a, T: Iterator<Item = &'a BgiFileHeader>, R: Read + Seek + 'static> Iterat
|
|||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
let entry = Entry {
|
let mut entry = Entry {
|
||||||
header: entry.clone(),
|
header: entry.clone(),
|
||||||
reader: self.reader.clone(),
|
reader: self.reader.clone(),
|
||||||
pos: 0,
|
pos: 0,
|
||||||
base_offset: self.base_offset,
|
base_offset: self.base_offset,
|
||||||
|
script_type: None,
|
||||||
};
|
};
|
||||||
|
let mut buf = [0u8; 32];
|
||||||
|
match entry.read(&mut buf) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
return Some(Err(anyhow::anyhow!(
|
||||||
|
"Failed to read entry '{}': {}",
|
||||||
|
entry.header.filename,
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.pos = 0;
|
||||||
|
if buf.starts_with(b"DSC FORMAT 1.00") {
|
||||||
|
let data = match entry.data() {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(e) => {
|
||||||
|
return Some(Err(anyhow::anyhow!(
|
||||||
|
"Failed to read DSC data for '{}': {}",
|
||||||
|
entry.header.filename,
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
entry.pos = 0;
|
||||||
|
let dsc = match DscDecoder::new(&data) {
|
||||||
|
Ok(dsc) => dsc,
|
||||||
|
Err(e) => {
|
||||||
|
return Some(Err(anyhow::anyhow!(
|
||||||
|
"Failed to create DSC decoder for '{}': {}",
|
||||||
|
entry.header.filename,
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let decoded = match dsc.unpack() {
|
||||||
|
Ok(decoded) => decoded,
|
||||||
|
Err(e) => {
|
||||||
|
return Some(Err(anyhow::anyhow!(
|
||||||
|
"Failed to unpack DSC data for '{}': {}",
|
||||||
|
entry.header.filename,
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Some(Ok(Box::new(MemEntry {
|
||||||
|
name: entry.header.filename.clone(),
|
||||||
|
data: MemReader::new(decoded),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
entry.script_type = detect_script_type(&buf, buf.len(), &entry.header.filename).cloned();
|
||||||
Some(Ok(Box::new(entry)))
|
Some(Ok(Box::new(entry)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user