Add support to DSC file in BSE encryped files

This commit is contained in:
2025-06-16 17:15:30 +08:00
parent b2b1d14acf
commit b98380fcd3
7 changed files with 189 additions and 5 deletions

View File

@@ -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 {

View File

@@ -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(())
}
}

View File

@@ -1,4 +1,4 @@
mod bse;
mod dsc;
pub mod dsc;
pub mod v1;
pub mod v2;

View File

@@ -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) => {

View File

@@ -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) => {

View File

@@ -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")]

View File

@@ -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)