msg_tool\scripts\bgi\archive/
bse.rs1use crate::ext::io::*;
2use crate::scripts::base::*;
3use crate::types::*;
4use anyhow::Result;
5use std::io::{Read, Seek};
6
7pub trait BseGenerator {
8 fn next_key(&mut self) -> i32;
9}
10
11pub struct BseGenerator100 {
12 key: i32,
13}
14
15impl BseGenerator100 {
16 pub fn new(key: i32) -> Self {
17 BseGenerator100 { key }
18 }
19}
20
21impl BseGenerator for BseGenerator100 {
22 fn next_key(&mut self) -> i32 {
23 let key = (self
24 .key
25 .overflowing_mul(257)
26 .0
27 .overflowing_shr(8)
28 .0
29 .overflowing_add(self.key.overflowing_mul(97).0)
30 .0
31 .overflowing_add(23)
32 .0) as u32
33 ^ 0xA6CD9B75;
34 self.key = key.rotate_right(16) as i32;
35 self.key
36 }
37}
38
39pub struct BseGenerator101 {
40 key: i32,
41}
42
43impl BseGenerator101 {
44 pub fn new(key: i32) -> Self {
45 BseGenerator101 { key }
46 }
47}
48
49impl BseGenerator for BseGenerator101 {
50 fn next_key(&mut self) -> i32 {
51 let key = (self
52 .key
53 .overflowing_mul(127)
54 .0
55 .overflowing_shr(7)
56 .0
57 .overflowing_add(self.key.overflowing_mul(83).0)
58 .0
59 .overflowing_add(53)
60 .0) as u32
61 ^ 0xB97A7E5C;
62 self.key = key.rotate_right(16) as i32;
63 self.key
64 }
65}
66
67pub struct BseReader<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> {
68 reader: T,
69 header: [u8; 0x40],
70 detect: F,
71 pos: u64,
72 filename: String,
73}
74
75impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> BseReader<T, F> {
76 pub fn new(mut reader: T, detect: F, filename: &str) -> Result<Self> {
77 reader.seek(std::io::SeekFrom::Start(8))?;
78 let version = reader.read_u16()?;
79 if version != 0x0100 && version != 0x0101 {
80 return Err(anyhow::anyhow!("Unsupported BSE version: {}", version));
81 }
82 let _checksum = reader.read_u16()?;
83 let key = reader.read_i32()?;
84 let mut header = [0u8; 0x40];
85 reader.read_exact(&mut header)?;
86 let generator: Box<dyn BseGenerator> = if version == 0x0100 {
87 Box::new(BseGenerator100::new(key))
88 } else {
89 Box::new(BseGenerator101::new(key))
90 };
91 Self::decode_header(&mut header, generator)?;
92 Ok(BseReader {
93 reader,
94 header,
95 detect,
96 pos: 0,
97 filename: filename.to_string(),
98 })
99 }
100
101 fn decode_header(data: &mut [u8; 0x40], mut generator: Box<dyn BseGenerator>) -> Result<()> {
102 let mut decoded = [false; 0x40];
103 for _ in 0..0x40 {
104 let mut dst = (generator.next_key() & 0x3F) as usize;
105 while decoded[dst] {
106 dst = (dst + 1) & 0x3F;
107 }
108 let shift = generator.next_key() & 7;
109 let right_shift = (generator.next_key() & 1) == 0;
110 let key_byte = generator.next_key();
111 let symbol = (data[dst] as i32).wrapping_sub(key_byte);
112 let symbol = symbol as u8;
113 data[dst] = if right_shift {
114 symbol.rotate_right(shift as u32)
115 } else {
116 symbol.rotate_left(shift as u32)
117 };
118 decoded[dst] = true;
119 }
120 Ok(())
121 }
122
123 pub fn is_dsc(&self) -> bool {
124 self.header.starts_with(b"DSC FORMAT 1.00")
125 }
126}
127
128impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> Read
129 for BseReader<T, F>
130{
131 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
132 if self.pos < 0x40 {
133 let bytes_to_read = (0x40 - self.pos).min(buf.len() as u64);
134 buf[..bytes_to_read as usize].copy_from_slice(
135 &self.header[self.pos as usize..self.pos as usize + bytes_to_read as usize],
136 );
137 self.pos += bytes_to_read;
138 Ok(bytes_to_read as usize)
139 } else {
140 let true_pos = self.pos + 0x10;
141 self.reader.seek(std::io::SeekFrom::Start(true_pos))?;
142 let bytes_read = self.reader.read(buf)?;
143 self.pos += bytes_read as u64;
144 Ok(bytes_read)
145 }
146 }
147}
148
149impl<T: Read + Seek, F: Fn(&[u8], usize, &str) -> Option<&'static ScriptType>> ArchiveContent
150 for BseReader<T, F>
151{
152 fn name(&self) -> &str {
153 &self.filename
154 }
155
156 fn script_type(&self) -> Option<&ScriptType> {
157 (self.detect)(&self.header, self.header.len(), &self.filename)
158 }
159}