1use super::list::{EnumScr, EscudeBinList, ListData, NameT, VarT};
3use super::ops::base::CustomOps;
4use crate::ext::io::*;
5use crate::scripts::base::*;
6use crate::types::*;
7use crate::utils::encoding::{decode_to_string, encode_string};
8use crate::utils::struct_pack::StructPack;
9use anyhow::Result;
10use clap::ValueEnum;
11use int_enum::IntEnum;
12use std::collections::{BTreeSet, HashMap};
13use std::ffi::CString;
14use std::io::{Read, Seek, SeekFrom};
15use unicode_segmentation::UnicodeSegmentation;
16
17#[derive(Debug, ValueEnum, Clone, Copy)]
18pub enum EscudeOp {
20 Panicon,
22 Hanaou,
24}
25
26#[derive(Debug)]
27pub struct EscudeBinScriptBuilder {}
29
30impl EscudeBinScriptBuilder {
31 pub const fn new() -> Self {
33 EscudeBinScriptBuilder {}
34 }
35}
36
37impl ScriptBuilder for EscudeBinScriptBuilder {
38 fn default_encoding(&self) -> Encoding {
39 Encoding::Cp932
40 }
41
42 fn build_script(
43 &self,
44 data: Vec<u8>,
45 _filename: &str,
46 encoding: Encoding,
47 _archive_encoding: Encoding,
48 config: &ExtraConfig,
49 _archive: Option<&Box<dyn Script>>,
50 ) -> Result<Box<dyn Script>> {
51 Ok(Box::new(EscudeBinScript::new(data, encoding, config)?))
52 }
53
54 fn extensions(&self) -> &'static [&'static str] {
55 &["bin"]
56 }
57
58 fn script_type(&self) -> &'static ScriptType {
59 &ScriptType::Escude
60 }
61
62 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
63 if buf_len > 8 && buf.starts_with(b"ESCR1_00") {
64 return Some(255);
65 }
66 None
67 }
68}
69
70#[derive(Debug)]
71pub struct EscudeBinScript {
73 vms: Vec<u8>,
74 unk1: u32,
75 strings: Vec<String>,
76 names: Option<HashMap<usize, String>>,
77}
78
79fn load_enum_script(
80 filename: &str,
81 encoding: Encoding,
82 config: &ExtraConfig,
83) -> Result<(Vec<NameT>, Vec<VarT>)> {
84 let buf = crate::utils::files::read_file(filename)?;
85 let scr = EscudeBinList::new(buf, filename, encoding, config)?;
86 let mut names = None;
87 let mut vars = None;
88 for scr in scr.entries {
89 match scr.data {
90 ListData::Scr(scr) => match scr {
91 EnumScr::Names(name) => {
92 names = Some(name);
93 }
94 EnumScr::Vars(var) => {
95 vars = Some(var);
96 }
97 _ => {}
98 },
99 _ => {}
100 }
101 }
102 Ok((
103 names.ok_or_else(|| anyhow::anyhow!("No names data in enum script"))?,
104 vars.ok_or_else(|| anyhow::anyhow!("No vars data in enum script"))?,
105 ))
106}
107
108impl EscudeBinScript {
125 pub fn new(data: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
131 let mut reader = MemReader::new(data);
132 let mut magic = [0u8; 8];
133 reader.read_exact(&mut magic)?;
134 if &magic != b"ESCR1_00" {
135 return Err(anyhow::anyhow!(
136 "Invalid Escude binary script magic: {:?}",
137 magic
138 ));
139 }
140 let string_count = reader.read_u32()?;
141 let mut offsets = Vec::with_capacity(string_count as usize);
142 for _ in 0..string_count {
143 offsets.push(reader.read_u32()?);
144 }
145 let vm_count = reader.read_u32()?;
146 let mut vms = Vec::with_capacity(vm_count as usize);
147 vms.resize(vm_count as usize, 0);
148 reader.read_exact(&mut vms)?;
149 let unk1 = reader.read_u32()?;
150 let mut strings = Vec::with_capacity(string_count as usize);
151 if encoding.is_jis() {
152 let replaces = StrReplacer::new()?;
153 for _ in 0..string_count {
154 let s = reader.read_cstring()?;
155 let s = replaces.replace(s.as_bytes())?;
156 strings.push(decode_to_string(encoding, &s, true)?);
157 }
158 } else {
159 for _ in 0..string_count {
160 let s = reader.read_cstring()?;
161 strings.push(decode_to_string(encoding, s.as_bytes(), true)?);
162 }
163 }
164 let names = match &config.escude_enum_scr {
165 Some(loc) => match load_enum_script(loc, encoding, config) {
166 Ok((list, vars)) => match config.escude_op {
167 Some(EscudeOp::Panicon) => {
168 let mut names = HashMap::new();
169 let mut vm = VM::new(&vms);
170 for var in vars {
171 vm.vars.insert(var.value as i32, var.flag as i32);
172 }
173 let _ = vm.run(Some(Box::new(super::ops::panicon::PaniconOps::new())));
174 for (index, name) in vm.names.iter() {
175 if let Some(name) = list.get(*name as usize) {
176 names.insert(*index as usize, name.text.clone());
177 }
178 }
179 Some(names)
181 }
182 Some(EscudeOp::Hanaou) => {
183 let mut names = HashMap::new();
184 let mut vm = VM::new(&vms);
185 for var in vars {
186 vm.vars.insert(var.value as i32, var.flag as i32);
187 }
188 let _ = vm.run(Some(Box::new(super::ops::hanaou::HanaouOps::new())));
189 for (index, name) in vm.names.iter() {
190 if let Some(name) = list.get(*name as usize) {
191 names.insert(*index as usize, name.text.clone());
192 }
193 }
194 Some(names)
196 }
197 None => {
198 let mut names = HashMap::new();
199 let mut vm = VM::new(&vms);
200 for var in vars {
201 vm.vars.insert(var.value as i32, var.flag as i32);
202 }
203 let _ = vm.run(None);
204 for (index, name) in vm.names.iter() {
205 if let Some(name) = list.get(*name as usize) {
206 names.insert(*index as usize, name.text.clone());
207 }
208 }
209 Some(names)
211 }
212 },
213 Err(e) => {
214 eprintln!(
215 "WARN: Failed to load Escude enum script from {}: {}",
216 loc, e
217 );
218 crate::COUNTER.inc_warning();
219 None
220 }
221 },
222 None => None,
223 };
224 Ok(EscudeBinScript {
225 vms,
226 unk1,
227 strings,
228 names,
229 })
230 }
231}
232
233impl Script for EscudeBinScript {
234 fn default_output_script_type(&self) -> OutputScriptType {
235 OutputScriptType::Json
236 }
237
238 fn default_format_type(&self) -> FormatOptions {
239 FormatOptions::None
240 }
241
242 fn extract_messages(&self) -> Result<Vec<Message>> {
243 Ok(self
244 .strings
245 .iter()
246 .enumerate()
247 .map(|(i, s)| Message {
248 message: s.replace("<r>", "\n"),
249 name: self.names.as_ref().map(|n| n.get(&i).cloned()).flatten(),
250 })
251 .collect())
252 }
253
254 fn import_messages<'a>(
255 &'a self,
256 messages: Vec<Message>,
257 mut writer: Box<dyn WriteSeek + 'a>,
258 _filename: &str,
259 encoding: Encoding,
260 replacement: Option<&'a ReplacementTable>,
261 ) -> Result<()> {
262 writer.write_all(b"ESCR1_00")?;
263 let mut offsets = Vec::with_capacity(messages.len());
264 let mut strs = Vec::with_capacity(messages.len());
265 let mut len = 0;
266 for message in messages {
267 offsets.push(len);
268 let mut s = message.message.replace("\n", "<r>");
269 if let Some(repl) = replacement {
270 for (from, to) in &repl.map {
271 s = s.replace(from, to);
272 }
273 }
274 let encoded = encode_string(encoding, &s, false)?;
275 len += encoded.len() as u32 + 1;
276 strs.push(CString::new(encoded)?);
277 }
278 writer.write_u32(offsets.len() as u32)?;
279 offsets.pack(&mut writer, false, encoding, &None)?;
280 writer.write_u32(self.vms.len() as u32)?;
281 writer.write_all(&self.vms)?;
282 writer.write_u32(self.unk1)?;
283 for s in strs {
284 writer.write_all(s.as_bytes_with_nul())?;
285 }
286 Ok(())
287 }
288
289 fn is_archive(&self) -> bool {
290 false
291 }
292}
293
294struct StrReplacer {
295 pub replacements: HashMap<Vec<u8>, Vec<u8>>,
296}
297
298enum JisStr {
299 Single(u8),
300 Double(u8, u8),
301}
302
303impl StrReplacer {
304 pub fn new() -> Result<Self> {
305 let mut s = StrReplacer {
306 replacements: HashMap::new(),
307 };
308 let half_width_katakana = "!? 。「」、…をぁぃぅぇぉゃゅょっーあいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわん゛゜";
310 let mut bytes: Vec<u8> = (0xa0..=0xde).collect();
311 bytes.insert(0, 0x21);
312 bytes.insert(1, 0x3f);
313 s.add(&bytes, half_width_katakana)?;
314 Ok(s)
315 }
316
317 fn add(&mut self, from: &[u8], to: &str) -> Result<()> {
318 let encoding = Encoding::Cp932; let tos = UnicodeSegmentation::graphemes(to, true);
320 for (from, to) in from.into_iter().zip(tos) {
321 let from_bytes = vec![from.clone()];
322 let to_bytes = encode_string(encoding, to, true)?;
323 self.replacements.insert(from_bytes, to_bytes);
324 }
325 Ok(())
326 }
327
328 pub fn replace(&self, input: &[u8]) -> Result<Vec<u8>> {
329 let mut result = Vec::new();
330 let mut reader = MemReaderRef::new(input);
331 while let Ok(byte) = reader.read_u8() {
332 if byte < 0x80 || (byte >= 0xa0 && byte <= 0xdf) {
333 result.push(JisStr::Single(byte));
334 } else if (byte >= 0x81 && byte <= 0x9f) || (byte >= 0xe0 && byte <= 0xef) {
335 let next_byte = reader.read_u8()?;
336 if next_byte < 0x40 || next_byte > 0xfc {
337 return Err(anyhow::anyhow!("Invalid JIS encoding sequence"));
338 }
339 result.push(JisStr::Double(byte, next_byte));
340 } else {
341 return Err(anyhow::anyhow!("Invalid byte in JIS encoding: {}", byte));
342 }
343 }
344 let mut output = Vec::new();
345 for item in result {
346 match item {
347 JisStr::Single(byte) => {
348 let vec = vec![byte];
349 if let Some(replacement) = self.replacements.get(&vec) {
350 output.extend_from_slice(replacement);
351 } else {
352 output.push(byte);
353 }
354 }
355 JisStr::Double(byte1, byte2) => {
356 let key = vec![byte1, byte2];
357 if let Some(replacement) = self.replacements.get(&key) {
358 output.extend_from_slice(replacement);
359 } else {
360 output.push(byte1);
361 output.push(byte2);
362 }
363 }
364 }
365 }
366 Ok(output)
367 }
368}
369
370#[repr(u8)]
371#[derive(Debug, IntEnum)]
372enum BaseOp {
373 End,
374 Jump,
375 JumpZ,
376 Call,
377 Ret,
378 Push,
379 Pop,
380 Str,
381 SetVar,
382 GetVar,
383 SetFlag,
384 GetFlag,
385 Neg,
386 Add,
387 Sub,
388 Mul,
389 Div,
390 Mod,
391 Not,
392 And,
393 Or,
394 Xor,
395 Shr,
396 Shl,
397 Eq,
398 Ne,
399 Gt,
400 Ge,
401 Lt,
402 Le,
403 LNot,
404 LAnd,
405 LOr,
406 FileLine,
407}
408
409pub(crate) trait ReadParam<T> {
410 fn read_param(&mut self) -> Result<T>;
411}
412
413#[derive(Debug)]
414pub(crate) struct VM<'a, T: std::fmt::Debug> {
415 pub reader: MemReaderRef<'a>,
416 pub data: Vec<T>,
417 pub stack: Vec<u64>,
418 pub strs: Vec<T>,
419 pub vars: HashMap<T, T>,
420 pub flags: HashMap<T, bool>,
421 pub mess: BTreeSet<T>,
422 pub names: HashMap<T, T>,
423}
424
425impl ReadParam<i32> for MemReaderRef<'_> {
426 fn read_param(&mut self) -> Result<i32> {
427 Ok(self.read_i32()?)
428 }
429}
430
431impl<'a, T> VM<'a, T>
432where
433 MemReaderRef<'a>: ReadParam<T>,
434 T: TryInto<u64>
435 + Default
436 + Eq
437 + Ord
438 + Copy
439 + std::fmt::Debug
440 + std::fmt::Display
441 + std::hash::Hash
442 + From<u8>
443 + std::ops::Neg<Output = T>
444 + std::ops::Add<Output = T>
445 + std::ops::Sub<Output = T>
446 + std::ops::Mul<Output = T>
447 + std::ops::Div<Output = T>
448 + std::ops::Rem<Output = T>
449 + std::ops::Not<Output = T>
450 + std::ops::BitAnd<Output = T>
451 + std::ops::BitOr<Output = T>
452 + std::ops::BitXor<Output = T>
453 + std::ops::Shr<Output = T>
454 + std::ops::Shl<Output = T>,
455 anyhow::Error: From<<T as TryInto<u64>>::Error>,
456{
457 pub fn new(data: &'a [u8]) -> Self {
458 VM {
459 reader: MemReaderRef::new(data),
460 data: Vec::new(),
461 stack: Vec::new(),
462 strs: Vec::new(),
463 vars: HashMap::new(),
464 flags: HashMap::new(),
465 mess: BTreeSet::new(),
466 names: HashMap::new(),
467 }
468 }
469
470 pub fn pop_data(&mut self) -> Result<T> {
471 self.data
472 .pop()
473 .ok_or_else(|| anyhow::anyhow!("No data to pop"))
474 }
475
476 fn pop_stack(&mut self) -> Result<u64> {
477 self.stack
478 .pop()
479 .ok_or_else(|| anyhow::anyhow!("No stack to pop"))
480 }
481
482 pub fn run(&mut self, mut custom_ops: Option<Box<dyn CustomOps<T>>>) -> Result<()> {
483 loop {
484 if self.reader.is_eof() {
485 break;
486 }
487 let op = self.reader.read_u8()?;
488 if let Ok(op) = BaseOp::try_from(op) {
489 match op {
491 BaseOp::End => break,
492 BaseOp::Jump => {
493 let offset: T = self.reader.read_param()?;
494 let offset: u64 = offset.try_into()?;
495 self.reader.seek(SeekFrom::Start(offset))?;
496 }
497 BaseOp::JumpZ => {
498 let offset: T = self.reader.read_param()?;
499 let offset: u64 = offset.try_into()?;
500 if self.pop_data()? == Default::default() {
501 self.reader.seek(SeekFrom::Start(offset))?;
502 }
503 }
504 BaseOp::Call => {
505 let offset: T = self.reader.read_param()?;
506 let offset: u64 = offset.try_into()?;
507 let pos = self.reader.stream_position()?;
508 self.stack.push(pos);
509 self.reader.seek(SeekFrom::Start(offset))?;
510 }
511 BaseOp::Ret => {
512 if self.stack.is_empty() {
513 let code = self.reader.read_u8()?;
514 if code == 0 && self.reader.is_eof() {
515 break;
516 }
517 }
518 let stack = self.pop_stack()?;
519 self.reader.seek(SeekFrom::Start(stack))?;
520 }
521 BaseOp::Push => {
522 let d = self.reader.read_param()?;
523 self.data.push(d);
524 }
525 BaseOp::Pop => {
526 self.pop_data()?;
527 }
528 BaseOp::Str => {
529 let param = self.reader.read_param()?;
530 self.strs.push(param);
531 self.data.push(param);
532 }
533 BaseOp::SetVar => {
534 let value = self.pop_data()?;
535 let index = self.pop_data()?;
536 self.vars.insert(index, value);
537 self.data.push(value);
538 }
539 BaseOp::GetVar => {
540 let index = self.pop_data()?;
541 let value = self
542 .vars
543 .get(&index)
544 .ok_or_else(|| anyhow::anyhow!("Variable not found: {}", index))?;
545 self.data.push(*value);
546 }
547 BaseOp::SetFlag => {
548 let value = self.pop_data()?;
549 let index = self.pop_data()?;
550 let flag = value != Default::default();
551 self.flags.insert(index, flag);
552 self.data.push(value);
553 }
554 BaseOp::GetFlag => {
555 let index = self.pop_data()?;
556 let flag = self.flags.get(&index).cloned().unwrap_or(false);
557 self.data
558 .push(if flag { T::from(1u8) } else { T::from(0u8) });
559 }
560 BaseOp::Neg => {
561 let value = -self.pop_data()?;
562 self.data.push(value);
563 }
564 BaseOp::Add => {
565 let b = self.pop_data()?;
566 let a = self.pop_data()?;
567 self.data.push(a + b);
568 }
569 BaseOp::Sub => {
570 let b = self.pop_data()?;
571 let a = self.pop_data()?;
572 self.data.push(a - b);
573 }
574 BaseOp::Mul => {
575 let b = self.pop_data()?;
576 let a = self.pop_data()?;
577 self.data.push(a * b);
578 }
579 BaseOp::Div => {
580 let b = self.pop_data()?;
581 if b == Default::default() {
582 return Err(anyhow::anyhow!("Division by zero"));
583 }
584 let a = self.pop_data()?;
585 self.data.push(a / b);
586 }
587 BaseOp::Mod => {
588 let b = self.pop_data()?;
589 if b == Default::default() {
590 return Err(anyhow::anyhow!("Division by zero"));
591 }
592 let a = self.pop_data()?;
593 self.data.push(a % b);
594 }
595 BaseOp::Not => {
596 let value = self.pop_data()?;
597 self.data.push(!value);
598 }
599 BaseOp::And => {
600 let b = self.pop_data()?;
601 let a = self.pop_data()?;
602 self.data.push(a & b);
603 }
604 BaseOp::Or => {
605 let b = self.pop_data()?;
606 let a = self.pop_data()?;
607 self.data.push(a | b);
608 }
609 BaseOp::Xor => {
610 let b = self.pop_data()?;
611 let a = self.pop_data()?;
612 self.data.push(a ^ b);
613 }
614 BaseOp::Shr => {
615 let b = self.pop_data()?;
616 let a = self.pop_data()?;
617 self.data.push(a >> b);
618 }
619 BaseOp::Shl => {
620 let b = self.pop_data()?;
621 let a = self.pop_data()?;
622 self.data.push(a << b);
623 }
624 BaseOp::Eq => {
625 let b = self.pop_data()?;
626 let a = self.pop_data()?;
627 self.data
628 .push(if a == b { T::from(1u8) } else { T::from(0u8) });
629 }
630 BaseOp::Ne => {
631 let b = self.pop_data()?;
632 let a = self.pop_data()?;
633 self.data
634 .push(if a != b { T::from(1u8) } else { T::from(0u8) });
635 }
636 BaseOp::Gt => {
638 let a = self.pop_data()?;
639 let b = self.pop_data()?;
640 self.data
641 .push(if a > b { T::from(1u8) } else { T::from(0u8) });
642 }
643 BaseOp::Ge => {
644 let a = self.pop_data()?;
645 let b = self.pop_data()?;
646 self.data
647 .push(if a >= b { T::from(1u8) } else { T::from(0u8) });
648 }
649 BaseOp::Lt => {
650 let a = self.pop_data()?;
651 let b = self.pop_data()?;
652 self.data
653 .push(if a < b { T::from(1u8) } else { T::from(0u8) });
654 }
655 BaseOp::Le => {
656 let a = self.pop_data()?;
657 let b = self.pop_data()?;
658 self.data
659 .push(if a <= b { T::from(1u8) } else { T::from(0u8) });
660 }
661 BaseOp::LNot => {
662 let value = self.pop_data()?;
663 self.data.push(if value == Default::default() {
664 T::from(1u8)
665 } else {
666 T::from(0u8)
667 });
668 }
669 BaseOp::LAnd => {
670 let b = self.pop_data()? != Default::default();
671 let a = self.pop_data()? != Default::default();
672 self.data
673 .push(if a && b { T::from(1u8) } else { T::from(0u8) });
674 }
675 BaseOp::LOr => {
676 let b = self.pop_data()? != Default::default();
677 let a = self.pop_data()? != Default::default();
678 self.data
679 .push(if a || b { T::from(1u8) } else { T::from(0u8) });
680 }
681 BaseOp::FileLine => {
682 let _: T = self.reader.read_param()?;
683 }
684 }
685 continue;
686 }
687 if let Some(ops) = &mut custom_ops {
688 let nbreak = ops.run(self, op)?;
689 if nbreak {
690 break;
691 }
692 } else {
693 return Err(anyhow::anyhow!("Unknown operation: {}", op));
694 }
695 }
696 Ok(())
697 }
698
699 pub fn skip_n_params(&mut self, n: u64, nbreak: bool) -> Result<bool> {
700 if (self.data.len() as u64) < n {
701 println!("{:?}", self.data);
702 }
703 for _ in 0..n {
704 self.pop_data()?;
705 }
706 Ok(nbreak)
707 }
708
709 pub fn skip_params(&mut self, nbreak: bool) -> Result<bool> {
710 let count: T = self.reader.read_param()?;
711 let count: u64 = count.try_into()?;
712 self.skip_n_params(count, nbreak)
713 }
714
715 pub fn read_params(&mut self, ncount: Option<u64>) -> Result<Vec<T>> {
716 let count = match ncount {
717 Some(count) => count,
718 None => {
719 let count: T = self.reader.read_param()?;
720 count.try_into()?
721 }
722 };
723 let data_len = self.data.len();
724 if (data_len as u64) < count {
725 return Err(anyhow::anyhow!(
726 "Not enough data to read {} parameters, only {} parameters available",
727 count,
728 data_len
729 ));
730 }
731 let mut params = Vec::with_capacity(count as usize);
732 params.resize(count as usize, Default::default());
733 params.copy_from_slice(&self.data[data_len - count as usize..]);
734 self.data.truncate(data_len - count as usize);
735 Ok(params)
736 }
737}