mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 12:58:45 +08:00
Add support to DSC file in BSE encryped files
This commit is contained in:
@@ -119,6 +119,10 @@ impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> B
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_dsc(&self) -> bool {
|
||||
self.header.starts_with(b"DSC FORMAT 1.00")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> Read
|
||||
@@ -126,8 +130,10 @@ impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> R
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
if self.pos < 0x40 {
|
||||
let bytes_to_read = 0x40 - self.pos;
|
||||
buf[..bytes_to_read as usize].copy_from_slice(&self.header[self.pos as usize..]);
|
||||
let bytes_to_read = (0x40 - self.pos).min(buf.len() as u64);
|
||||
buf[..bytes_to_read as usize].copy_from_slice(
|
||||
&self.header[self.pos as usize..self.pos as usize + bytes_to_read as usize],
|
||||
);
|
||||
self.pos += bytes_to_read;
|
||||
Ok(bytes_to_read as usize)
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use crate::ext::io::*;
|
||||
use crate::ext::vec::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::bit_stream::*;
|
||||
use anyhow::Result;
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HuffmanCode {
|
||||
@@ -204,3 +207,88 @@ impl<'a> DscDecoder<'a> {
|
||||
v1 as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DscBuilder {}
|
||||
|
||||
impl DscBuilder {
|
||||
pub fn new() -> Self {
|
||||
DscBuilder {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptBuilder for DscBuilder {
|
||||
fn default_encoding(&self) -> Encoding {
|
||||
Encoding::Cp932
|
||||
}
|
||||
|
||||
fn default_archive_encoding(&self) -> Option<Encoding> {
|
||||
Some(Encoding::Cp932)
|
||||
}
|
||||
|
||||
fn build_script(
|
||||
&self,
|
||||
buf: Vec<u8>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
_archive_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
) -> Result<Box<dyn Script>> {
|
||||
Ok(Box::new(Dsc::new(buf)?))
|
||||
}
|
||||
|
||||
fn extensions(&self) -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn script_type(&self) -> &'static ScriptType {
|
||||
&ScriptType::BGIDsc
|
||||
}
|
||||
|
||||
fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||
if buf_len >= 16 && buf.starts_with(b"DSC FORMAT 1.00\0") {
|
||||
return Some(255);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dsc {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Dsc {
|
||||
pub fn new(buf: Vec<u8>) -> Result<Self> {
|
||||
if buf.len() < 16 || !buf.starts_with(b"DSC FORMAT 1.00\0") {
|
||||
return Err(anyhow::anyhow!("Invalid DSC format"));
|
||||
}
|
||||
let decoder = DscDecoder::new(&buf)?;
|
||||
let data = decoder.unpack()?;
|
||||
Ok(Dsc { data })
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for Dsc {
|
||||
fn default_output_script_type(&self) -> OutputScriptType {
|
||||
OutputScriptType::Custom
|
||||
}
|
||||
|
||||
fn is_output_supported(&self, output: OutputScriptType) -> bool {
|
||||
matches!(output, OutputScriptType::Custom)
|
||||
}
|
||||
|
||||
fn default_format_type(&self) -> FormatOptions {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn custom_output_extension(&self) -> &'static str {
|
||||
"unk"
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, _encoding: Encoding) -> Result<()> {
|
||||
let mut f = std::fs::File::create(filename)?;
|
||||
f.write_all(&self.data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mod bse;
|
||||
mod dsc;
|
||||
pub mod dsc;
|
||||
pub mod v1;
|
||||
pub mod v2;
|
||||
|
||||
@@ -309,6 +309,10 @@ fn detect_script_type(buf: &[u8], buf_len: usize, filename: &str) -> Option<&'st
|
||||
if buf_len >= 28 && buf.starts_with(b"BurikoCompiledScriptVer1.00\0") {
|
||||
return Some(&ScriptType::BGI);
|
||||
}
|
||||
#[cfg(feature = "bgi-img")]
|
||||
if buf_len >= 16 && buf.starts_with(b"CompressedBG___") {
|
||||
return Some(&ScriptType::BGICbg);
|
||||
}
|
||||
let filename = filename.to_lowercase();
|
||||
if filename.ends_with("._bp") {
|
||||
return Some(&ScriptType::BGIBp);
|
||||
@@ -435,7 +439,45 @@ impl<'a, T: Iterator<Item = &'a BgiFileHeader>, R: Read + Seek + 'static> Iterat
|
||||
#[cfg(not(feature = "bgi-img"))]
|
||||
let detect = detect_script_type;
|
||||
match BseReader::new(entry, detect, &filename) {
|
||||
Ok(bse_reader) => {
|
||||
Ok(mut bse_reader) => {
|
||||
if bse_reader.is_dsc() {
|
||||
let data = match bse_reader.data() {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to read BSE data for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let dsc = match DscDecoder::new(&data) {
|
||||
Ok(dsc) => dsc,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to create DSC decoder for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let decoded = match dsc.unpack() {
|
||||
Ok(decoded) => decoded,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to unpack DSC data for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let reader = MemReader::new(decoded);
|
||||
return Some(Ok(Box::new(MemEntry {
|
||||
name: filename,
|
||||
data: reader,
|
||||
detect,
|
||||
})));
|
||||
}
|
||||
return Some(Ok(Box::new(bse_reader)));
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -311,6 +311,10 @@ fn detect_script_type(buf: &[u8], buf_len: usize, filename: &str) -> Option<&'st
|
||||
if buf_len >= 28 && buf.starts_with(b"BurikoCompiledScriptVer1.00\0") {
|
||||
return Some(&ScriptType::BGI);
|
||||
}
|
||||
#[cfg(feature = "bgi-img")]
|
||||
if buf_len >= 16 && buf.starts_with(b"CompressedBG___") {
|
||||
return Some(&ScriptType::BGICbg);
|
||||
}
|
||||
let filename = filename.to_lowercase();
|
||||
if filename.ends_with("._bp") {
|
||||
return Some(&ScriptType::BGIBp);
|
||||
@@ -437,7 +441,45 @@ impl<'a, T: Iterator<Item = &'a BgiFileHeader>, R: Read + Seek + 'static> Iterat
|
||||
#[cfg(not(feature = "bgi-img"))]
|
||||
let detect = detect_script_type;
|
||||
match BseReader::new(entry, detect, &filename) {
|
||||
Ok(bse_reader) => {
|
||||
Ok(mut bse_reader) => {
|
||||
if bse_reader.is_dsc() {
|
||||
let data = match bse_reader.data() {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to read BSE data for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let dsc = match DscDecoder::new(&data) {
|
||||
Ok(dsc) => dsc,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to create DSC decoder for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let decoded = match dsc.unpack() {
|
||||
Ok(decoded) => decoded,
|
||||
Err(e) => {
|
||||
return Some(Err(anyhow::anyhow!(
|
||||
"Failed to unpack DSC data for '{}': {}",
|
||||
&filename,
|
||||
e
|
||||
)));
|
||||
}
|
||||
};
|
||||
let reader = MemReader::new(decoded);
|
||||
return Some(Ok(Box::new(MemEntry {
|
||||
name: filename,
|
||||
data: reader,
|
||||
detect,
|
||||
})));
|
||||
}
|
||||
return Some(Ok(Box::new(bse_reader)));
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -24,6 +24,8 @@ lazy_static::lazy_static! {
|
||||
Box::new(bgi::archive::v1::BgiArchiveBuilder::new()),
|
||||
#[cfg(feature = "bgi-arc")]
|
||||
Box::new(bgi::archive::v2::BgiArchiveBuilder::new()),
|
||||
#[cfg(feature = "bgi-arc")]
|
||||
Box::new(bgi::archive::dsc::DscBuilder::new()),
|
||||
#[cfg(feature = "bgi-img")]
|
||||
Box::new(bgi::image::img::BgiImageBuilder::new()),
|
||||
#[cfg(feature = "bgi-img")]
|
||||
|
||||
@@ -231,6 +231,10 @@ pub enum ScriptType {
|
||||
#[value(alias = "ethornell-arc-v2", alias = "bgi-arc", alias = "ethornell-arc")]
|
||||
/// Buriko General Interpreter/Ethornell archive v2
|
||||
BGIArcV2,
|
||||
#[cfg(feature = "bgi-arc")]
|
||||
#[value(alias("ethornell-dsc"))]
|
||||
/// Buriko General Interpreter/Ethornell compressed file (DSC)
|
||||
BGIDsc,
|
||||
#[cfg(feature = "bgi-img")]
|
||||
#[value(alias("ethornell-img"))]
|
||||
/// Buriko General Interpreter/Ethornell image (Image files in sysgrp.arc)
|
||||
|
||||
Reference in New Issue
Block a user