msg_tool\scripts\hexen_haus/
bin.rs1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::str::*;
7use anyhow::Result;
8use std::io::Read;
9
10#[derive(Debug)]
11pub struct BinScriptBuilder {}
13
14impl BinScriptBuilder {
15 pub fn new() -> Self {
17 BinScriptBuilder {}
18 }
19}
20
21impl ScriptBuilder for BinScriptBuilder {
22 fn default_encoding(&self) -> Encoding {
23 Encoding::Cp932
24 }
25
26 fn build_script(
27 &self,
28 buf: Vec<u8>,
29 _filename: &str,
30 encoding: Encoding,
31 _archive_encoding: Encoding,
32 config: &ExtraConfig,
33 _archive: Option<&Box<dyn Script>>,
34 ) -> Result<Box<dyn Script>> {
35 Ok(Box::new(BinScript::new(buf, encoding, config)?))
36 }
37
38 fn extensions(&self) -> &'static [&'static str] {
39 &["bin"]
40 }
41
42 fn script_type(&self) -> &'static ScriptType {
43 &ScriptType::HexenHaus
44 }
45
46 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
47 if buf_len >= 4 && buf.starts_with(b"NORI") {
48 return Some(10);
49 }
50 None
51 }
52}
53
54#[derive(Debug)]
55struct BinString {
56 str: String,
57 pos: usize,
58 len: usize,
59}
60
61#[derive(Debug)]
62pub struct BinScript {
64 data: MemReader,
65 strs: Vec<BinString>,
66}
67
68impl BinScript {
69 pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
75 let mut data = MemReader::new(buf);
76 let mut header = [0; 4];
77 data.read_exact(&mut header)?;
78 if header != *b"NORI" {
79 return Err(anyhow::anyhow!("Invalid HexenHaus bin script header"));
80 }
81 for c in data.data.iter_mut() {
82 *c ^= 0x53;
83 }
84 data.pos = memchr::memmem::find(&data.data, b"_beginrp")
85 .ok_or(anyhow::anyhow!("Failed to find _beginrp"))?;
86 data.pos += 16;
87 let mut p = [0; 2];
88 let mut s = Vec::new();
89 let data_len = data.data.len();
90 let mut start_pos = data.pos;
91 let mut strs = Vec::new();
92 while data.pos < data_len {
93 data.read_exact(&mut p)?;
94 if p[0] == 0x53 {
95 if s.len() > 2 {
96 if let Ok(c) = decode_to_string(encoding, &s[s.len() - 2..], true) {
97 if c != "」" && c != "。" && c != "』" {
98 s.pop();
99 s.pop();
100 }
101 } else {
102 s.pop();
103 s.pop();
104 }
105 }
106 if s.len() > 2 {
107 let d = decode_to_string(encoding, &s, true)?;
108 strs.push(BinString {
109 str: d,
110 pos: start_pos,
111 len: s.len(),
112 });
113 }
114 start_pos = data.pos;
115 s.clear();
116 } else if p[1] == 0x53 {
117 if s.len() > 2 {
118 let d = decode_to_string(encoding, &s, true)?;
119 strs.push(BinString {
120 str: d,
121 pos: start_pos,
122 len: s.len(),
123 });
124 }
125 start_pos = data.pos;
126 s.clear();
127 } else {
128 s.extend_from_slice(&p);
129 }
130 }
131 if s.len() > 2 {
132 s.pop();
133 s.pop();
134 if s.len() > 2 {
135 let d = decode_to_string(encoding, &s, true)?;
136 strs.push(BinString {
137 str: d,
138 pos: start_pos,
139 len: s.len(),
140 });
141 }
142 }
143 Ok(BinScript { data, strs })
144 }
145}
146
147impl Script for BinScript {
148 fn default_output_script_type(&self) -> OutputScriptType {
149 OutputScriptType::Json
150 }
151
152 fn default_format_type(&self) -> FormatOptions {
153 FormatOptions::None
154 }
155
156 fn extract_messages(&self) -> Result<Vec<Message>> {
157 let mut messages: Vec<Message> = Vec::new();
158 for str in &self.strs {
159 let message = if let Some(ind) = str.str.find("「") {
160 let (name, mes) = str.str.split_at(ind);
161 let mut name = name.to_string();
162 if name.is_empty() {
163 if let Some(m) = messages.pop() {
164 name = m.message;
165 }
166 }
167 Message {
168 name: Some(name.to_string()),
169 message: mes.to_string(),
170 }
171 } else {
172 Message {
173 name: None,
174 message: str.str.clone(),
175 }
176 };
177 messages.push(message);
178 }
179 Ok(messages)
180 }
181
182 fn import_messages<'a>(
183 &'a self,
184 mut messages: Vec<Message>,
185 mut file: Box<dyn WriteSeek + 'a>,
186 _filename: &str,
187 encoding: Encoding,
188 replacement: Option<&'a ReplacementTable>,
189 ) -> Result<()> {
190 let mut data = MemWriter::from_vec(self.data.data.clone());
191 let mut i = 0;
192 for str in self.strs.iter() {
193 if i >= messages.len() {
194 return Err(anyhow::anyhow!("Not enough messages."));
195 }
196 if let Some(ind) = str.str.find("「") {
197 let (name, _) = str.str.split_at(ind);
198 let mut target = String::new();
199 if !name.is_empty() {
200 let mut name = match &messages[i].name {
201 Some(n) => n.to_owned(),
202 None => return Err(anyhow::anyhow!("Missing name for message.")),
203 };
204 if let Some(repl) = replacement {
205 for (k, v) in &repl.map {
206 name = name.replace(k, v);
207 }
208 };
209 target.push_str(&name);
210 }
211 let mut mes = messages[i].message.clone();
212 if let Some(repl) = replacement {
213 for (k, v) in &repl.map {
214 mes = mes.replace(k, v);
215 }
216 }
217 target.push_str(&mes);
218 let mut encoded = encode_string(encoding, &target, false)?;
219 if encoded.len() > str.len {
220 eprintln!("Warning: Message '{}' is too long, truncating.", target);
221 crate::COUNTER.inc_warning();
222 encoded = truncate_string(&target, str.len, encoding, false)?;
223 }
224 while encoded.len() < str.len {
225 encoded.push(32); }
227 data.write_all_at(str.pos as u64, &encoded)?;
228 i += 1;
229 } else {
230 let mut target = if let Some(name) = messages[i].name.take() {
231 name
232 } else {
233 let s = messages[i].message.clone();
234 i += 1;
235 s
236 };
237 if let Some(repl) = replacement {
238 for (k, v) in &repl.map {
239 target = target.replace(k, v);
240 }
241 }
242 let mut encoded = encode_string(encoding, &target, false)?;
243 if encoded.len() > str.len {
244 eprintln!("Warning: Message '{}' is too long, truncating.", target);
245 crate::COUNTER.inc_warning();
246 encoded = truncate_string(&target, str.len, encoding, false)?;
247 }
248 while encoded.len() < str.len {
249 encoded.push(32); }
251 data.write_all_at(str.pos as u64, &encoded)?;
252 }
253 }
254 let mut data = data.into_inner();
255 for d in data.iter_mut() {
256 *d ^= 0x53;
257 }
258 file.write_all(&data)?;
259 Ok(())
260 }
261}