1use super::yscm::YSCMData;
3use super::yslb::{Label, YSLBData};
4use crate::ext::io::*;
5use crate::scripts::base::*;
6use crate::types::*;
7use crate::utils::encoding::*;
8use crate::utils::serde_base64bytes::*;
9use crate::utils::struct_pack::*;
10use crate::utils::xored_stream::*;
11use anyhow::Result;
12use msg_tool_macro::*;
13use serde::{Deserialize, Serialize};
14use std::any::Any;
15use std::collections::{BTreeMap, BTreeSet};
16use std::io::{Read, Seek, SeekFrom, Write};
17use std::ops::{Deref, DerefMut};
18
19#[derive(Clone, Debug, StructUnpack, StructPack, Deserialize, Serialize)]
20struct YSTBHeader {
21 version: u32,
22 #[serde(skip)]
23 inst_entry_count: u32,
24 #[serde(skip)]
25 inst_index_size: u32,
26 #[serde(skip)]
27 args_index_size: u32,
28 #[serde(skip)]
29 args_data_size: u32,
30 #[serde(skip)]
31 line_numbers_size: u32,
32 reserve0: u32,
33}
34
35#[derive(Clone, Debug, StructUnpack, StructPack)]
36struct YSTBHeaderV2 {
37 version: u32,
38 code_seg_size: u32,
39 args_seg_size: u32,
40 args_seg_offset: u32,
41 reserved0: u32,
42 reserved1: u32,
43 reserved2: u32,
44}
45
46#[derive(Deserialize, Serialize)]
47struct YSTBData {
48 #[serde(flatten)]
49 header: YSTBHeader,
50 insts: Vec<YSTBInst>,
51 line_numbers: Base64Bytes,
52}
53
54impl std::fmt::Debug for YSTBData {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 f.debug_struct("YSTBData")
57 .field("header", &self.header)
58 .field("insts", &self.insts)
59 .field("line_numbers", &hex::encode(&self.line_numbers.bytes))
60 .finish()
61 }
62}
63
64impl StructUnpack for YSTBData {
65 fn unpack<R: Read + Seek>(
66 reader: &mut R,
67 big: bool,
68 encoding: Encoding,
69 info: &Option<Box<dyn Any>>,
70 ) -> Result<Self> {
71 let header = YSTBHeader::unpack(reader, big, encoding, info)?;
72 let insts = reader.read_struct_vec::<YSTBInstBase>(
73 header.inst_entry_count as usize,
74 big,
75 encoding,
76 info,
77 )?;
78 let info = Box::new(header.clone()) as Box<dyn Any>;
79 let args = reader.read_struct_vec::<YSTBArg>(
80 (header.args_index_size / 0xC) as usize,
81 big,
82 encoding,
83 &Some(info),
84 )?;
85 let mut args = args.into_iter();
86 let insts = insts
87 .into_iter()
88 .map(|base| {
89 let args = args.by_ref().take(base.arg_count as usize).collect();
90 YSTBInst { base, args }
91 })
92 .collect();
93 let line_numbers = reader.peek_exact_at_vec(
94 0x20 + header.inst_index_size as u64
95 + header.args_index_size as u64
96 + header.args_data_size as u64,
97 header.line_numbers_size as usize,
98 )?;
99 Ok(Self {
100 header,
101 insts,
102 line_numbers: line_numbers.into(),
103 })
104 }
105}
106
107#[derive(Clone, Debug, StructUnpack, StructPack, Deserialize, Serialize)]
108struct YSTBInstBase {
109 opcode: u8,
110 #[serde(skip)]
111 arg_count: u8,
112 unk: u16,
113}
114
115#[derive(Deserialize, Serialize)]
116struct YSTBInst {
117 #[serde(flatten)]
118 base: YSTBInstBase,
119 args: Vec<YSTBArg>,
120}
121
122impl Deref for YSTBInst {
123 type Target = YSTBInstBase;
124 fn deref(&self) -> &Self::Target {
125 &self.base
126 }
127}
128
129impl DerefMut for YSTBInst {
130 fn deref_mut(&mut self) -> &mut Self::Target {
131 &mut self.base
132 }
133}
134
135impl std::fmt::Debug for YSTBInst {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 f.debug_struct("YSTBInst")
138 .field("opcode", &self.opcode)
139 .field("arg_count", &self.arg_count)
140 .field("unk", &self.unk)
141 .field("args", &self.args)
142 .finish()
143 }
144}
145
146#[derive(Clone, Debug, StructUnpack, StructPack, Deserialize, Serialize)]
147struct YSTBArgBase {
148 id: u16,
149 typ: u16,
150 #[serde(skip)]
151 size: u32,
152}
153
154struct YSTBArg {
155 base: YSTBArgBase,
156 data: Vec<u8>,
157 encoding: Encoding,
158}
159
160#[derive(Deserialize, Serialize)]
161#[serde(tag = "t")]
162enum YSTBArgDat {
163 Raw { data: Base64Bytes },
164 NotEqual,
165 Mod,
166 LogAnd,
167 PerformVarIndexAtion,
168 Mul,
169 Add,
170 Nop,
171 Sub,
172 Div,
173 Equal,
174 Less,
175 Greater,
176 BinAnd,
177 PushInt8 { value: i8 },
178 PushDouble { value: f64 },
179 PushScalarVarVar { index: u16 },
180 PushScalarVarStr { index: u16 },
181 PushInt32 { value: i32 },
182 PushInt64 { value: i64 },
183 MString { s: String },
184 BinOr,
185 ChangeSign,
186 Le,
187 PrepareVarIndexationVar { index: u16 },
188 PrepareVarIndexationStr { index: u16 },
189 PushInt16 { value: i16 },
190 Ge,
191 BinXor,
192 ToNumber,
193 ToString,
194 PushArrayVarVar { index: u16 },
195 PushArrayVarStr { index: u16 },
196 LogOr,
197 Array { data: Vec<YSTBArgDat> },
198 String { s: String },
199}
200
201impl YSTBArgDat {
202 fn to_data(self, encoding: Encoding) -> Result<Vec<u8>> {
203 Ok(match self {
204 YSTBArgDat::Raw { data } => data.bytes,
205 YSTBArgDat::NotEqual => NOTEQUAL_TYPE.into(),
206 YSTBArgDat::Mod => MOD_TYPE.into(),
207 YSTBArgDat::LogAnd => LOGAND_TYPE.into(),
208 YSTBArgDat::PerformVarIndexAtion => PERFORMVARINDEXATION_TYPE.into(),
209 YSTBArgDat::Mul => MUL_TYPE.into(),
210 YSTBArgDat::Add => ADD_TYPE.into(),
211 YSTBArgDat::Nop => NOP_TYPE.into(),
212 YSTBArgDat::Sub => SUB_TYPE.into(),
213 YSTBArgDat::Div => DIV_TYPE.into(),
214 YSTBArgDat::Equal => EQUAL_TYPE.into(),
215 YSTBArgDat::Less => LESS_TYPE.into(),
216 YSTBArgDat::Greater => GREATER_TYPE.into(),
217 YSTBArgDat::BinAnd => BINAND_TYPE.into(),
218 YSTBArgDat::PushInt8 { value } => {
219 let mut m = MemWriter::new();
220 m.write_u8(b'B')?;
221 m.write_u16(1)?;
222 m.write_i8(value)?;
223 m.into_inner()
224 }
225 YSTBArgDat::PushDouble { value } => {
226 let mut m = MemWriter::new();
227 m.write_u8(b'F')?;
228 m.write_u16(8)?;
229 m.write_f64(value)?;
230 m.into_inner()
231 }
232 YSTBArgDat::PushScalarVarVar { index } => {
233 let mut m = MemWriter::new();
234 m.write_u8(b'H')?;
235 m.write_u16(3)?;
236 m.write_u8(b'$')?;
237 m.write_u16(index)?;
238 m.into_inner()
239 }
240 YSTBArgDat::PushScalarVarStr { index } => {
241 let mut m = MemWriter::new();
242 m.write_u8(b'H')?;
243 m.write_u16(3)?;
244 m.write_u8(b'@')?;
245 m.write_u16(index)?;
246 m.into_inner()
247 }
248 YSTBArgDat::PushInt32 { value } => {
249 let mut m = MemWriter::new();
250 m.write_u8(b'I')?;
251 m.write_u16(4)?;
252 m.write_i32(value)?;
253 m.into_inner()
254 }
255 YSTBArgDat::PushInt64 { value } => {
256 let mut m = MemWriter::new();
257 m.write_u8(b'L')?;
258 m.write_u16(8)?;
259 m.write_i64(value)?;
260 m.into_inner()
261 }
262 YSTBArgDat::MString { s } => {
263 let mut m = MemWriter::new();
264 m.write_u8(b'M')?;
265 let d = encode_string(encoding, &s, true)?;
266 m.write_u16(d.len() as u16)?;
267 m.write_all(&d)?;
268 m.into_inner()
269 }
270 YSTBArgDat::BinOr => BINOR_TYPE.into(),
271 YSTBArgDat::ChangeSign => CHANGESIGN_TYPE.into(),
272 YSTBArgDat::Le => LE_TYPE.into(),
273 YSTBArgDat::PrepareVarIndexationVar { index } => {
274 let mut m = MemWriter::new();
275 m.write_u8(b'V')?;
276 m.write_u16(3)?;
277 m.write_u8(b'$')?;
278 m.write_u16(index)?;
279 m.into_inner()
280 }
281 YSTBArgDat::PrepareVarIndexationStr { index } => {
282 let mut m = MemWriter::new();
283 m.write_u8(b'V')?;
284 m.write_u16(3)?;
285 m.write_u8(b'@')?;
286 m.write_u16(index)?;
287 m.into_inner()
288 }
289 YSTBArgDat::PushInt16 { value } => {
290 let mut m = MemWriter::new();
291 m.write_u8(b'W')?;
292 m.write_u16(2)?;
293 m.write_i16(value)?;
294 m.into_inner()
295 }
296 YSTBArgDat::Ge => GE_TYPE.into(),
297 YSTBArgDat::BinXor => BINXOR_TYPE.into(),
298 YSTBArgDat::ToNumber => TONUMBER_TYPE.into(),
299 YSTBArgDat::ToString => TOSTRING_TYPE.into(),
300 YSTBArgDat::PushArrayVarVar { index } => {
301 let mut m = MemWriter::new();
302 m.write_u8(b'v')?;
303 m.write_u16(3)?;
304 m.write_u8(b'$')?;
305 m.write_u16(index)?;
306 m.into_inner()
307 }
308 YSTBArgDat::PushArrayVarStr { index } => {
309 let mut m = MemWriter::new();
310 m.write_u8(b'v')?;
311 m.write_u16(3)?;
312 m.write_u8(b'@')?;
313 m.write_u16(index)?;
314 m.into_inner()
315 }
316 YSTBArgDat::LogOr => LOGOR_TYPE.into(),
317 YSTBArgDat::Array { data } => {
318 let mut m = MemWriter::new();
319 for d in data {
320 m.write_all(&d.to_data(encoding)?)?;
321 }
322 m.into_inner()
323 }
324 YSTBArgDat::String { s } => encode_string(encoding, &s, true)?,
325 })
326 }
327}
328
329impl TryFrom<YSTBArgTmp> for YSTBArg {
330 type Error = anyhow::Error;
331 fn try_from(value: YSTBArgTmp) -> Result<Self> {
332 let data = value.data.to_data(value.encoding)?;
333 Ok(Self {
334 base: value.base,
335 data,
336 encoding: value.encoding,
337 })
338 }
339}
340
341impl<'a> TryFrom<&'a YSTBArg> for YSTBArgTmp {
342 type Error = anyhow::Error;
343 fn try_from(value: &'a YSTBArg) -> Result<Self> {
344 let mut list = Vec::new();
345 let mut data = value.data.as_slice();
346 loop {
347 if data.is_empty() {
348 break;
349 }
350 if data.starts_with(NOTEQUAL_TYPE) {
351 list.push(YSTBArgDat::NotEqual);
352 data = &data[3..];
353 } else if data.starts_with(MOD_TYPE) {
354 list.push(YSTBArgDat::Mod);
355 data = &data[3..];
356 } else if data.starts_with(LOGAND_TYPE) {
357 list.push(YSTBArgDat::LogAnd);
358 data = &data[3..];
359 } else if data.starts_with(PERFORMVARINDEXATION_TYPE) {
360 list.push(YSTBArgDat::PerformVarIndexAtion);
361 data = &data[4..];
362 } else if data.starts_with(MUL_TYPE) {
363 list.push(YSTBArgDat::Mul);
364 data = &data[3..];
365 } else if data.starts_with(ADD_TYPE) {
366 list.push(YSTBArgDat::Add);
367 data = &data[3..];
368 } else if data.starts_with(NOP_TYPE) {
369 list.push(YSTBArgDat::Nop);
370 data = &data[3..];
371 } else if data.starts_with(SUB_TYPE) {
372 list.push(YSTBArgDat::Sub);
373 data = &data[3..];
374 } else if data.starts_with(DIV_TYPE) {
375 list.push(YSTBArgDat::Div);
376 data = &data[3..];
377 } else if data.starts_with(EQUAL_TYPE) {
378 list.push(YSTBArgDat::Equal);
379 data = &data[3..];
380 } else if data.starts_with(LESS_TYPE) {
381 list.push(YSTBArgDat::Less);
382 data = &data[3..];
383 } else if data.starts_with(GREATER_TYPE) {
384 list.push(YSTBArgDat::Greater);
385 data = &data[3..];
386 } else if data.starts_with(BINAND_TYPE) {
387 list.push(YSTBArgDat::BinAnd);
388 data = &data[3..];
389 } else if data.starts_with(PUSHINT8_TYPE) {
390 if data.len() < 4 {
391 list.push(YSTBArgDat::Raw {
392 data: data.to_vec().into(),
393 });
394 break;
395 }
396 list.push(YSTBArgDat::PushInt8 {
397 value: i8::from_le_bytes([data[3]]),
398 });
399 data = &data[4..];
400 } else if data.starts_with(PUSHDOUBLE_TYPE) {
401 if data.len() < 11 {
402 list.push(YSTBArgDat::Raw {
403 data: data.to_vec().into(),
404 });
405 break;
406 }
407 list.push(YSTBArgDat::PushDouble {
408 value: f64::from_le_bytes([
409 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
410 ]),
411 });
412 data = &data[11..];
413 } else if data.starts_with(PUSHSCALARVAR_VAR_TYPE) {
414 if data.len() < 6 {
415 list.push(YSTBArgDat::Raw {
416 data: data.to_vec().into(),
417 });
418 break;
419 }
420 list.push(YSTBArgDat::PushScalarVarVar {
421 index: u16::from_le_bytes([data[4], data[5]]),
422 });
423 data = &data[6..];
424 } else if data.starts_with(PUSHSCALARVAR_STR_TYPE) {
425 if data.len() < 6 {
426 list.push(YSTBArgDat::Raw {
427 data: data.to_vec().into(),
428 });
429 break;
430 }
431 list.push(YSTBArgDat::PushScalarVarStr {
432 index: u16::from_le_bytes([data[4], data[5]]),
433 });
434 data = &data[6..];
435 } else if data.starts_with(PUSHINT32_TYPE) {
436 if data.len() < 7 {
437 list.push(YSTBArgDat::Raw {
438 data: data.to_vec().into(),
439 });
440 break;
441 }
442 list.push(YSTBArgDat::PushInt32 {
443 value: i32::from_le_bytes([data[3], data[4], data[5], data[6]]),
444 });
445 data = &data[7..];
446 } else if data.starts_with(PUSHINT64_TYPE) {
447 if data.len() < 11 {
448 list.push(YSTBArgDat::Raw {
449 data: data.to_vec().into(),
450 });
451 break;
452 }
453 list.push(YSTBArgDat::PushInt64 {
454 value: i64::from_le_bytes([
455 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
456 ]),
457 });
458 data = &data[11..];
459 } else if data.starts_with(PUSHSTRING_TYPE) {
460 if data.len() < 3 {
461 list.push(YSTBArgDat::Raw {
462 data: data.to_vec().into(),
463 });
464 break;
465 }
466 let len = u16::from_le_bytes([data[1], data[2]]) as usize;
467 if data.len() < 3 + len {
468 list.push(YSTBArgDat::Raw {
469 data: data.to_vec().into(),
470 });
471 break;
472 }
473 if let Ok(s) = decode_to_string(value.encoding, &data[3..3 + len], true) {
474 list.push(YSTBArgDat::MString { s });
475 } else {
476 list.push(YSTBArgDat::Raw {
477 data: data[..3 + len].to_vec().into(),
478 });
479 }
480 data = &data[3 + len..];
481 } else if data.starts_with(BINOR_TYPE) {
482 list.push(YSTBArgDat::BinOr);
483 data = &data[3..];
484 } else if data.starts_with(CHANGESIGN_TYPE) {
485 list.push(YSTBArgDat::ChangeSign);
486 data = &data[3..];
487 } else if data.starts_with(LE_TYPE) {
488 list.push(YSTBArgDat::Le);
489 data = &data[3..];
490 } else if data.starts_with(PREPAREVARINDEXATION_VAR_TYPE) {
491 if data.len() < 6 {
492 list.push(YSTBArgDat::Raw {
493 data: data.to_vec().into(),
494 });
495 break;
496 }
497 list.push(YSTBArgDat::PrepareVarIndexationVar {
498 index: u16::from_le_bytes([data[4], data[5]]),
499 });
500 data = &data[6..];
501 } else if data.starts_with(PREPAREVARINDEXATION_STR_TYPE) {
502 if data.len() < 6 {
503 list.push(YSTBArgDat::Raw {
504 data: data.to_vec().into(),
505 });
506 break;
507 }
508 list.push(YSTBArgDat::PrepareVarIndexationStr {
509 index: u16::from_le_bytes([data[4], data[5]]),
510 });
511 data = &data[6..];
512 } else if data.starts_with(PUSHINT16_TYPE) {
513 if data.len() < 5 {
514 list.push(YSTBArgDat::Raw {
515 data: data.to_vec().into(),
516 });
517 break;
518 }
519 list.push(YSTBArgDat::PushInt16 {
520 value: i16::from_le_bytes([data[3], data[4]]),
521 });
522 data = &data[5..];
523 } else if data.starts_with(GE_TYPE) {
524 list.push(YSTBArgDat::Ge);
525 data = &data[3..];
526 } else if data.starts_with(BINXOR_TYPE) {
527 list.push(YSTBArgDat::BinXor);
528 data = &data[3..];
529 } else if data.starts_with(TONUMBER_TYPE) {
530 list.push(YSTBArgDat::ToNumber);
531 data = &data[3..];
532 } else if data.starts_with(TOSTRING_TYPE) {
533 list.push(YSTBArgDat::ToString);
534 data = &data[3..];
535 } else if data.starts_with(PUSHARRAYVAR_VAR_TYPE) {
536 if data.len() < 6 {
537 list.push(YSTBArgDat::Raw {
538 data: data.to_vec().into(),
539 });
540 break;
541 }
542 list.push(YSTBArgDat::PushArrayVarVar {
543 index: u16::from_le_bytes([data[4], data[5]]),
544 });
545 data = &data[6..];
546 } else if data.starts_with(PUSHARRAYVAR_STR_TYPE) {
547 if data.len() < 6 {
548 list.push(YSTBArgDat::Raw {
549 data: data.to_vec().into(),
550 });
551 break;
552 }
553 list.push(YSTBArgDat::PushArrayVarStr {
554 index: u16::from_le_bytes([data[4], data[5]]),
555 });
556 data = &data[6..];
557 } else if data.starts_with(LOGOR_TYPE) {
558 list.push(YSTBArgDat::LogOr);
559 data = &data[3..];
560 } else {
561 if list.is_empty() {
562 if !data.contains(&0)
563 && let Ok(s) = decode_to_string(value.encoding, data, true)
564 {
565 list.push(YSTBArgDat::String { s });
566 break;
567 }
568 }
569 list.push(YSTBArgDat::Raw {
570 data: data.to_vec().into(),
571 });
572 break;
573 }
574 }
575 if list.len() > 1 {
576 return Ok(Self {
577 base: value.base.clone(),
578 data: YSTBArgDat::Array { data: list },
579 encoding: value.encoding,
580 });
581 }
582 if let Some(data) = list.pop() {
583 return Ok(Self {
584 base: value.base.clone(),
585 data,
586 encoding: value.encoding,
587 });
588 }
589 Ok(Self {
590 base: value.base.clone(),
591 data: YSTBArgDat::Raw {
592 data: value.data.clone().into(),
593 },
594 encoding: value.encoding,
595 })
596 }
597}
598
599#[derive(Deserialize, Serialize)]
600struct YSTBArgTmp {
601 #[serde(flatten)]
602 base: YSTBArgBase,
603 data: YSTBArgDat,
604 encoding: Encoding,
605}
606
607impl<'de> Deserialize<'de> for YSTBArg {
608 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
609 where
610 D: serde::Deserializer<'de>,
611 {
612 let tmp = YSTBArgTmp::deserialize(deserializer)?;
613 tmp.try_into().map_err(serde::de::Error::custom)
614 }
615}
616
617impl Serialize for YSTBArg {
618 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
619 where
620 S: serde::Serializer,
621 {
622 let tmp: YSTBArgTmp = self.try_into().map_err(serde::ser::Error::custom)?;
623 tmp.serialize(serializer)
624 }
625}
626
627struct YSTBArgData<'a>(&'a [u8], Encoding);
628
629const NOTEQUAL_TYPE: &[u8] = b"!\0\0";
631const MOD_TYPE: &[u8] = b"%\0\0";
632const LOGAND_TYPE: &[u8] = b"&\0\0";
633const PERFORMVARINDEXATION_TYPE: &[u8] = b")\x01\0\0";
634const MUL_TYPE: &[u8] = b"*\0\0";
635const ADD_TYPE: &[u8] = b"+\0\0";
636const NOP_TYPE: &[u8] = b",\0\0";
637const SUB_TYPE: &[u8] = b"-\0\0";
638const DIV_TYPE: &[u8] = b"/\0\0";
639const EQUAL_TYPE: &[u8] = b"=\0\0";
640const LESS_TYPE: &[u8] = b"<\0\0";
641const GREATER_TYPE: &[u8] = b">\0\0";
642const BINAND_TYPE: &[u8] = b"A\0\0";
643const PUSHINT8_TYPE: &[u8] = b"B\x01\0";
645const PUSHDOUBLE_TYPE: &[u8] = b"F\x08\0";
647const PUSHSCALARVAR_VAR_TYPE: &[u8] = b"H\x03\0$";
648const PUSHSCALARVAR_STR_TYPE: &[u8] = b"H\x03\0@";
649const PUSHINT32_TYPE: &[u8] = b"I\x04\0";
650const PUSHINT64_TYPE: &[u8] = b"L\x08\0";
651const PUSHSTRING_TYPE: &[u8] = b"M";
652const BINOR_TYPE: &[u8] = b"O\0\0";
653const CHANGESIGN_TYPE: &[u8] = b"R\0\0";
654const LE_TYPE: &[u8] = b"S\0\0";
655const PREPAREVARINDEXATION_VAR_TYPE: &[u8] = b"V\x03\0$";
656const PREPAREVARINDEXATION_STR_TYPE: &[u8] = b"V\x03\0@";
657const PUSHINT16_TYPE: &[u8] = b"W\x02\0";
658const GE_TYPE: &[u8] = b"Z\0\0";
659const BINXOR_TYPE: &[u8] = b"^\0\0";
660const TONUMBER_TYPE: &[u8] = b"i\0\0";
661const TOSTRING_TYPE: &[u8] = b"s\0\0";
662const PUSHARRAYVAR_VAR_TYPE: &[u8] = b"v\x03\0$";
663const PUSHARRAYVAR_STR_TYPE: &[u8] = b"v\x03\0@";
664const LOGOR_TYPE: &[u8] = b"|\0\0";
665
666impl<'a> std::fmt::Debug for YSTBArgData<'a> {
667 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
668 let mut data = self.0;
669 let mut first = true;
670 loop {
671 if data.is_empty() {
672 break;
673 }
674 let is_first = first;
675 if first {
676 first = false;
677 } else {
678 f.write_str(" ")?;
679 }
680 if data.starts_with(NOTEQUAL_TYPE) {
681 f.write_str("notequal")?;
682 data = &data[3..];
683 } else if data.starts_with(MOD_TYPE) {
684 f.write_str("mod")?;
685 data = &data[3..];
686 } else if data.starts_with(LOGAND_TYPE) {
687 f.write_str("logand")?;
688 data = &data[3..];
689 } else if data.starts_with(PERFORMVARINDEXATION_TYPE) {
690 f.write_str("performvarindexation")?;
691 data = &data[4..];
692 } else if data.starts_with(MUL_TYPE) {
693 f.write_str("mul")?;
694 data = &data[3..];
695 } else if data.starts_with(ADD_TYPE) {
696 f.write_str("add")?;
697 data = &data[3..];
698 } else if data.starts_with(NOP_TYPE) {
699 f.write_str("nop")?;
700 data = &data[3..];
701 } else if data.starts_with(SUB_TYPE) {
702 f.write_str("sub")?;
703 data = &data[3..];
704 } else if data.starts_with(DIV_TYPE) {
705 f.write_str("div")?;
706 data = &data[3..];
707 } else if data.starts_with(EQUAL_TYPE) {
708 f.write_str("equal")?;
709 data = &data[3..];
710 } else if data.starts_with(LESS_TYPE) {
711 f.write_str("less")?;
712 data = &data[3..];
713 } else if data.starts_with(GREATER_TYPE) {
714 f.write_str("greater")?;
715 data = &data[3..];
716 } else if data.starts_with(BINAND_TYPE) {
717 f.write_str("binand")?;
718 data = &data[3..];
719 } else if data.starts_with(PUSHINT8_TYPE) {
720 if data.len() < 4 {
721 f.write_str(&hex::encode(data))?;
722 break;
723 }
724 f.write_fmt(format_args!("pushint8({})", i8::from_le_bytes([data[3]])))?;
725 data = &data[4..];
726 } else if data.starts_with(PUSHDOUBLE_TYPE) {
727 if data.len() < 11 {
728 f.write_str(&hex::encode(data))?;
729 break;
730 }
731 f.write_fmt(format_args!(
732 "pushdouble({})",
733 f64::from_le_bytes([
734 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10]
735 ])
736 ))?;
737 data = &data[11..];
738 } else if data.starts_with(PUSHSCALARVAR_VAR_TYPE) {
739 if data.len() < 6 {
740 f.write_str(&hex::encode(data))?;
741 break;
742 }
743 f.write_fmt(format_args!(
744 "pushscalarvar(var[{}])",
745 u16::from_le_bytes([data[4], data[5]])
746 ))?;
747 data = &data[6..];
748 } else if data.starts_with(PUSHSCALARVAR_STR_TYPE) {
749 if data.len() < 6 {
750 f.write_str(&hex::encode(data))?;
751 break;
752 }
753 f.write_fmt(format_args!(
754 "pushscalarvar(str[{}])",
755 u16::from_le_bytes([data[4], data[5]])
756 ))?;
757 data = &data[6..];
758 } else if data.starts_with(PUSHINT32_TYPE) {
759 if data.len() < 7 {
760 f.write_str(&hex::encode(data))?;
761 break;
762 }
763 f.write_fmt(format_args!(
764 "pushint32({})",
765 i32::from_le_bytes([data[3], data[4], data[5], data[6]])
766 ))?;
767 data = &data[7..];
768 } else if data.starts_with(PUSHINT64_TYPE) {
769 if data.len() < 11 {
770 f.write_str(&hex::encode(data))?;
771 break;
772 }
773 f.write_fmt(format_args!(
774 "pushint64({})",
775 i64::from_le_bytes([
776 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10]
777 ])
778 ))?;
779 data = &data[11..];
780 } else if data.starts_with(PUSHSTRING_TYPE) {
781 if data.len() < 3 {
782 f.write_str(&hex::encode(data))?;
783 break;
784 }
785 let len = u16::from_le_bytes([data[1], data[2]]) as usize;
786 if data.len() < 3 + len {
787 f.write_str(&hex::encode(data))?;
788 break;
789 }
790 if let Ok(s) = decode_to_string(self.1, &data[3..3 + len], true) {
791 f.write_str(&s)?;
792 } else {
793 f.write_str(&hex::encode(&data[..3 + len]))?;
794 }
795 data = &data[3 + len..];
796 } else if data.starts_with(BINOR_TYPE) {
797 f.write_str("binor")?;
798 data = &data[3..];
799 } else if data.starts_with(CHANGESIGN_TYPE) {
800 f.write_str("changesign")?;
801 data = &data[3..];
802 } else if data.starts_with(LE_TYPE) {
803 f.write_str("le")?;
804 data = &data[3..];
805 } else if data.starts_with(PREPAREVARINDEXATION_VAR_TYPE) {
806 if data.len() < 6 {
807 f.write_str(&hex::encode(data))?;
808 break;
809 }
810 f.write_fmt(format_args!(
811 "preparevarindexation(var[{}])",
812 u16::from_le_bytes([data[4], data[5]])
813 ))?;
814 data = &data[6..];
815 } else if data.starts_with(PREPAREVARINDEXATION_STR_TYPE) {
816 if data.len() < 6 {
817 f.write_str(&hex::encode(data))?;
818 break;
819 }
820 f.write_fmt(format_args!(
821 "preparevarindexation(str[{}])",
822 u16::from_le_bytes([data[4], data[5]])
823 ))?;
824 data = &data[6..];
825 } else if data.starts_with(PUSHINT16_TYPE) {
826 if data.len() < 5 {
827 f.write_str(&hex::encode(data))?;
828 break;
829 }
830 f.write_fmt(format_args!(
831 "pushint16({})",
832 i16::from_le_bytes([data[3], data[4]])
833 ))?;
834 data = &data[5..];
835 } else if data.starts_with(GE_TYPE) {
836 f.write_str("ge")?;
837 data = &data[3..];
838 } else if data.starts_with(BINXOR_TYPE) {
839 f.write_str("binxor")?;
840 data = &data[3..];
841 } else if data.starts_with(TONUMBER_TYPE) {
842 f.write_str("tonumber")?;
843 data = &data[3..];
844 } else if data.starts_with(TOSTRING_TYPE) {
845 f.write_str("tostring")?;
846 data = &data[3..];
847 } else if data.starts_with(PUSHARRAYVAR_VAR_TYPE) {
848 if data.len() < 6 {
849 f.write_str(&hex::encode(data))?;
850 break;
851 }
852 f.write_fmt(format_args!(
853 "pusharrayvar(var[{}])",
854 u16::from_le_bytes([data[4], data[5]])
855 ))?;
856 data = &data[6..];
857 } else if data.starts_with(PUSHARRAYVAR_STR_TYPE) {
858 if data.len() < 6 {
859 f.write_str(&hex::encode(data))?;
860 break;
861 }
862 f.write_fmt(format_args!(
863 "pusharrayvar(str[{}])",
864 u16::from_le_bytes([data[4], data[5]])
865 ))?;
866 data = &data[6..];
867 } else if data.starts_with(LOGOR_TYPE) {
868 f.write_str("logor")?;
869 data = &data[3..];
870 } else {
871 if is_first {
872 if !data.contains(&0)
873 && let Ok(s) = decode_to_string(self.1, &data, true)
874 {
875 f.write_str(&s)?;
876 break;
877 }
878 }
879 f.write_str(&hex::encode(data))?;
880 break;
881 }
882 }
883 Ok(())
884 }
885}
886
887impl std::fmt::Debug for YSTBArg {
888 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
889 f.debug_struct("YSTBArg")
890 .field("id", &self.id)
891 .field("type", &self.typ)
892 .field("size", &self.size)
893 .field("data", &YSTBArgData(&self.data, self.encoding))
894 .finish()
895 }
896}
897
898impl Deref for YSTBArg {
899 type Target = YSTBArgBase;
900 fn deref(&self) -> &Self::Target {
901 &self.base
902 }
903}
904
905impl DerefMut for YSTBArg {
906 fn deref_mut(&mut self) -> &mut Self::Target {
907 &mut self.base
908 }
909}
910
911fn get_info_as_header(info: &Option<Box<dyn Any>>) -> Result<&YSTBHeader> {
912 Ok(info
913 .as_ref()
914 .ok_or_else(|| anyhow::anyhow!("info not found"))?
915 .downcast_ref()
916 .ok_or_else(|| anyhow::anyhow!("not YSTBHeader"))?)
917}
918
919impl StructUnpack for YSTBArg {
920 fn unpack<R: Read + Seek>(
921 reader: &mut R,
922 big: bool,
923 encoding: Encoding,
924 info: &Option<Box<dyn Any>>,
925 ) -> Result<Self> {
926 let base = YSTBArgBase::unpack(reader, big, encoding, info)?;
927 let offset = u32::unpack(reader, big, encoding, info)?;
928 let header = get_info_as_header(info)?;
929 let target =
930 0x20 + header.inst_index_size as u64 + header.args_index_size as u64 + offset as u64;
931 let data = reader.peek_exact_at_vec(target, base.size as usize)?;
932 Ok(Self {
933 base,
934 data,
935 encoding,
936 })
937 }
938}
939
940#[derive(Debug)]
941pub struct YSTBBuilder {}
942
943impl YSTBBuilder {
944 pub const fn new() -> Self {
946 YSTBBuilder {}
947 }
948}
949
950impl ScriptBuilder for YSTBBuilder {
951 fn default_encoding(&self) -> Encoding {
952 Encoding::Cp932
953 }
954
955 fn build_script(
956 &self,
957 buf: Vec<u8>,
958 filename: &str,
959 encoding: Encoding,
960 _archive_encoding: Encoding,
961 config: &ExtraConfig,
962 archive: Option<&Box<dyn Script>>,
963 ) -> Result<Box<dyn Script + Send + Sync>> {
964 Ok(Box::new(YSTB::new(
965 MemReader::new(buf),
966 filename,
967 encoding,
968 config,
969 archive,
970 )?))
971 }
972
973 fn extensions(&self) -> &'static [&'static str] {
974 &["ybn"]
975 }
976
977 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
978 if buf_len >= 4 && buf.starts_with(b"YSTB") {
979 return Some(20);
980 }
981 None
982 }
983
984 fn script_type(&self) -> &'static ScriptType {
985 &ScriptType::YurisYSTB
986 }
987}
988
989#[derive(Debug)]
990pub struct YSTB {
991 data: YSTBData,
992 com: YSCMData,
993 xor_key: Option<u32>,
994 disasm: bool,
995 custom_yaml: bool,
996 labels: BTreeMap<u32, Label>,
997}
998
999impl YSTB {
1000 pub fn new<T: Read + Seek>(
1001 mut reader: T,
1002 filename: &str,
1003 encoding: Encoding,
1004 config: &ExtraConfig,
1005 archive: Option<&Box<dyn Script>>,
1006 ) -> Result<Self> {
1007 let mut sig = [0; 4];
1008 reader.read_exact(&mut sig)?;
1009 if &sig != b"YSTB" {
1010 anyhow::bail!("Unsupported YSTB file.");
1011 }
1012 let mut xor_key = None;
1013 let data = match YSTBData::unpack(&mut reader, false, encoding, &None) {
1014 Ok(data) => data,
1015 Err(err) => {
1016 let key = Self::get_xor_key(&mut reader)?;
1017 if key == 0 {
1018 return Err(err);
1019 }
1020 xor_key = Some(key);
1021 let mut writer = MemWriter::with_capacity(reader.stream_length()? as usize);
1022 Self::xor(&mut reader, &mut writer, key)?;
1023 let mut reader = writer.to_ref();
1024 reader.pos = 4;
1025 YSTBData::unpack(&mut reader, false, encoding, &None)?
1026 }
1027 };
1028 let yscm = if let Some(path) = config.yuris_ysc_path.as_ref() {
1030 crate::utils::files::read_file(path)?
1031 } else {
1032 let path = std::path::Path::new(filename);
1033 let pdir = path.parent().unwrap_or_else(|| std::path::Path::new(""));
1034 let fp = pdir.join("ysc.ybn");
1035 if let Some(archive) = &archive {
1036 let mut file = archive.open_file_by_name(&fp.to_string_lossy(), true)?;
1037 file.data()?
1038 } else {
1039 let p = crate::utils::files::get_ignorecase_path(&fp)?;
1040 crate::utils::files::read_file(&p)?
1041 }
1042 };
1043 if !yscm.starts_with(b"YSCM") {
1044 anyhow::bail!("Unsupported YSCM file. (ysc.ybn)");
1045 }
1046 let mut reader = MemReader::new(yscm);
1047 reader.pos = 4;
1048 let com = YSCMData::unpack(&mut reader, false, encoding, &None)?;
1049 let labels = match Self::try_load_yslb(filename, &archive, config, encoding) {
1050 Ok(labels) => labels,
1051 Err(e) => {
1052 eprintln!("WARNING: Failed to load ysl.bin file: {}", e);
1053 crate::COUNTER.inc_warning();
1054 BTreeMap::new()
1055 }
1056 };
1057 Ok(Self {
1058 data,
1059 com,
1060 xor_key,
1061 disasm: config.yuris_ystb_disasm,
1062 custom_yaml: config.custom_yaml,
1063 labels,
1064 })
1065 }
1066
1067 fn try_load_yslb(
1068 filename: &str,
1069 archive: &Option<&Box<dyn Script>>,
1070 config: &ExtraConfig,
1071 encoding: Encoding,
1072 ) -> Result<BTreeMap<u32, Label>> {
1073 let yslb = if let Some(path) = config.yuris_ysl_path.as_ref() {
1074 crate::utils::files::read_file(path)?
1075 } else {
1076 let path = std::path::Path::new(filename);
1077 let pdir = path.parent().unwrap_or_else(|| std::path::Path::new(""));
1078 let fp = pdir.join("ysl.ybn");
1079 if let Some(archive) = &archive {
1080 let mut file = archive.open_file_by_name(&fp.to_string_lossy(), true)?;
1081 file.data()?
1082 } else {
1083 let p = crate::utils::files::get_ignorecase_path(&fp)?;
1084 crate::utils::files::read_file(&p)?
1085 }
1086 };
1087 if !yslb.starts_with(b"YSLB") {
1088 anyhow::bail!("Unsupported YSLB file. (ysl.ybn)");
1089 }
1090 let mut reader = MemReader::new(yslb);
1091 reader.pos = 4;
1092 let labels = YSLBData::unpack(&mut reader, false, encoding, &None)?;
1093 let path = std::path::Path::new(filename);
1094 let filename = path
1095 .file_stem()
1096 .ok_or_else(|| anyhow::anyhow!("No filename"))?
1097 .to_string_lossy()
1098 .into_owned();
1099 let script_idx_name = String::from_iter(
1100 filename
1101 .chars()
1102 .rev()
1103 .take(5)
1104 .collect::<Vec<_>>()
1105 .iter()
1106 .rev(),
1107 );
1108 let script_idx: u16 = script_idx_name.parse()?;
1109 let mut map = BTreeMap::new();
1110 for label in labels.labels {
1111 if label.script_index == script_idx {
1112 map.insert(label.offset, label);
1113 }
1114 }
1115 Ok(map)
1116 }
1117
1118 fn get_xor_key<T: Read + Seek>(reader: &mut T) -> Result<u32> {
1119 let version = reader.peek_u32_at(4)?;
1120 reader.seek(SeekFrom::Start(4))?;
1121 Ok(if matches!(version, 201..300) {
1122 let header: YSTBHeaderV2 = reader.read_struct(false, Encoding::Cp932, &None)?;
1123 if (header.code_seg_size as u64) + (header.args_seg_size as u64) < 0x10 {
1124 0
1125 } else {
1126 reader.peek_u32_at(0x2C)?
1127 }
1128 } else {
1129 let header: YSTBHeader = reader.read_struct(false, Encoding::Cp932, &None)?;
1130 if header.args_data_size == 0 {
1131 0
1132 } else {
1133 reader.peek_u32_at(header.inst_index_size as u64 + 0x28)?
1134 }
1135 })
1136 }
1137
1138 fn xor<R: Read + Seek, W: Write>(
1139 mut reader: &mut R,
1140 writer: &mut W,
1141 xor_key: u32,
1142 ) -> Result<()> {
1143 let key = xor_key.to_le_bytes();
1144 reader.seek(SeekFrom::Start(4))?;
1145 writer.write_all(b"YSTB")?;
1146 let version = reader.peek_u32()?;
1147 if matches!(version, 201..300) {
1148 let header: YSTBHeaderV2 = reader.read_struct(false, Encoding::Cp932, &None)?;
1149 writer.write_struct(&header, false, Encoding::Cp932, &None)?;
1150 let mut stream = XoredKeyStream::new(
1151 StreamRegion::with_size(&mut reader, header.code_seg_size as u64)?,
1152 key.to_vec(),
1153 0,
1154 );
1155 std::io::copy(&mut stream, writer)?;
1156 stream = XoredKeyStream::new(
1157 StreamRegion::with_size(&mut reader, header.args_seg_size as u64)?,
1158 key.to_vec(),
1159 0,
1160 );
1161 std::io::copy(&mut stream, writer)?;
1162 std::io::copy(reader, writer)?;
1163 } else {
1164 let header: YSTBHeader = reader.read_struct(false, Encoding::Cp932, &None)?;
1165 writer.write_struct(&header, false, Encoding::Cp932, &None)?;
1166 let mut stream = XoredKeyStream::new(
1167 StreamRegion::with_size(&mut reader, header.inst_index_size as u64)?,
1168 key.to_vec(),
1169 0,
1170 );
1171 std::io::copy(&mut stream, writer)?;
1172 stream = XoredKeyStream::new(
1173 StreamRegion::with_size(&mut reader, header.args_index_size as u64)?,
1174 key.to_vec(),
1175 0,
1176 );
1177 std::io::copy(&mut stream, writer)?;
1178 stream = XoredKeyStream::new(
1179 StreamRegion::with_size(&mut reader, header.args_data_size as u64)?,
1180 key.to_vec(),
1181 0,
1182 );
1183 std::io::copy(&mut stream, writer)?;
1184 stream = XoredKeyStream::new(
1185 StreamRegion::with_size(&mut reader, header.line_numbers_size as u64)?,
1186 key.to_vec(),
1187 0,
1188 );
1189 std::io::copy(&mut stream, writer)?;
1190 std::io::copy(reader, writer)?;
1191 }
1192 Ok(())
1193 }
1194}
1195
1196struct YSTBDataSer<'a> {
1197 data: &'a YSTBData,
1198 com: &'a YSCMData,
1199 labels: &'a BTreeMap<u32, Label>,
1200}
1201
1202impl<'a> serde::Serialize for YSTBDataSer<'a> {
1203 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1204 where
1205 S: serde::Serializer,
1206 {
1207 use serde::ser::SerializeStruct;
1208 let h = &self.data.header;
1209 let mut s = serializer.serialize_struct("YSTBData", 4)?;
1210 s.serialize_field("version", &h.version)?;
1211 s.serialize_field("reserve0", &h.reserve0)?;
1212 s.serialize_field(
1213 "insts",
1214 &YSTBInstSliceSer {
1215 insts: &self.data.insts,
1216 com: self.com,
1217 labels: self.labels,
1218 },
1219 )?;
1220 s.serialize_field("line_numbers", &self.data.line_numbers)?;
1221 s.end()
1222 }
1223}
1224
1225struct YSTBInstSliceSer<'a> {
1226 insts: &'a [YSTBInst],
1227 com: &'a YSCMData,
1228 labels: &'a BTreeMap<u32, Label>,
1229}
1230
1231impl<'a> serde::Serialize for YSTBInstSliceSer<'a> {
1232 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1233 where
1234 S: serde::Serializer,
1235 {
1236 use serde::ser::SerializeSeq;
1237 let mut seq = serializer.serialize_seq(Some(self.insts.len()))?;
1238 for (i, inst) in self.insts.iter().enumerate() {
1239 let offset = i as u32;
1240 let opcode_name = self
1241 .com
1242 .opcodes
1243 .get(inst.opcode as usize)
1244 .map(|m| m.name.as_str());
1245 let label = self.labels.get(&offset);
1246 seq.serialize_element(&YSTBInstSer {
1247 inst,
1248 opcode_name,
1249 label,
1250 })?;
1251 }
1252 seq.end()
1253 }
1254}
1255
1256struct YSTBInstSer<'a> {
1257 inst: &'a YSTBInst,
1258 opcode_name: Option<&'a str>,
1259 label: Option<&'a Label>,
1260}
1261
1262impl<'a> serde::Serialize for YSTBInstSer<'a> {
1263 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1264 where
1265 S: serde::Serializer,
1266 {
1267 use serde::ser::SerializeStruct;
1268 let nfields = 3 + self.opcode_name.is_some() as usize + self.label.is_some() as usize;
1269 let mut s = serializer.serialize_struct("YSTBInst", nfields)?;
1270 s.serialize_field("opcode", &self.inst.opcode)?;
1271 if let Some(name) = self.opcode_name {
1272 s.serialize_field("opcode_name", name)?;
1273 }
1274 s.serialize_field("unk", &self.inst.unk)?;
1275 s.serialize_field("args", &self.inst.args)?;
1276 if let Some(label) = self.label {
1277 s.serialize_field("label", &label.name)?;
1278 }
1279 s.end()
1280 }
1281}
1282
1283fn make_pushstring_data(content: &[u8]) -> Vec<u8> {
1285 let mut new_data = Vec::with_capacity(5 + content.len());
1286 new_data.push(b'M');
1287 new_data.extend_from_slice(&((content.len() + 2) as u16).to_le_bytes());
1288 new_data.push(b'"');
1289 new_data.extend_from_slice(content);
1290 new_data.push(b'"');
1291 new_data
1292}
1293
1294impl Script for YSTB {
1295 fn default_output_script_type(&self) -> OutputScriptType {
1296 OutputScriptType::Json
1297 }
1298
1299 fn is_output_supported(&self, _output: OutputScriptType) -> bool {
1300 true
1301 }
1302
1303 fn default_format_type(&self) -> FormatOptions {
1304 FormatOptions::None
1305 }
1306
1307 fn custom_output_extension(&self) -> &'static str {
1308 if self.disasm {
1309 "txt"
1310 } else if self.custom_yaml {
1311 "yaml"
1312 } else {
1313 "json"
1314 }
1315 }
1316
1317 fn extract_messages(&self) -> Result<Vec<Message>> {
1318 let mut mes = Vec::new();
1319 for code in self.data.insts.iter() {
1320 let meta =
1321 self.com.opcodes.get(code.opcode as usize).ok_or_else(|| {
1322 anyhow::anyhow!("Failed to find op {:x}'s metadata", code.opcode)
1323 })?;
1324 if meta.name == "WORD" {
1325 if code.arg_count != 1 {
1326 anyhow::bail!("Bad argument count for WORD.");
1327 }
1328 let arg = &code.args[0];
1329 if arg.typ == 0 && arg.size > 0 {
1330 let mut data = decode_to_string(arg.encoding, &arg.data, true)?;
1331 let name = if data.starts_with("【")
1332 && let Some(end_pos) = data.find("】")
1333 {
1334 let n = data[3..end_pos].to_owned();
1335 data = data[end_pos + 3..].to_owned();
1336 Some(n)
1337 } else {
1338 None
1339 };
1340 mes.push(Message::new(data, name));
1341 }
1342 } else if meta.name == "_"
1343 && meta.arguments.len() > 0
1344 && code.arg_count == 1
1345 && meta.arguments[0].data == 3
1346 {
1347 let arg = &code.args[0];
1348 if arg.data.starts_with(PUSHSTRING_TYPE) {
1349 let len = u16::from_le_bytes([arg.data[1], arg.data[2]]);
1350 if len as u32 + 3 == arg.size {
1351 let data = decode_to_string(
1352 arg.encoding,
1353 &arg.data[4..arg.size as usize - 1],
1354 true,
1355 )?;
1356 mes.push(Message::new(data, None));
1357 }
1358 }
1359 } else if meta.name == "GOSUB" && code.arg_count >= 2 {
1360 let arg0 = &code.args[0];
1361 let name = format!("{:?}", &YSTBArgData(&arg0.data, arg0.encoding))
1362 .trim_matches('"')
1363 .to_lowercase();
1364 if name == "es.sel.set" {
1365 for arg in &code.args[1..] {
1366 if arg.data.starts_with(PUSHSTRING_TYPE) {
1367 let len = u16::from_le_bytes([arg.data[1], arg.data[2]]);
1368 if len as u32 + 3 == arg.size {
1369 let data = decode_to_string(
1370 arg.encoding,
1371 &arg.data[4..arg.size as usize - 1],
1372 true,
1373 )?;
1374 if !data.is_empty() {
1375 mes.push(Message::new(data, None));
1376 }
1377 }
1378 }
1379 }
1380 } else if name == "es.char.name" && code.arg_count >= 3 {
1381 let arg = &code.args[2];
1382 if arg.data.starts_with(PUSHSTRING_TYPE) {
1383 let len = u16::from_le_bytes([arg.data[1], arg.data[2]]);
1384 if len as u32 + 3 == arg.size {
1385 let data = decode_to_string(
1386 arg.encoding,
1387 &arg.data[4..arg.size as usize - 1],
1388 true,
1389 )?;
1390 mes.push(Message::new(data, None));
1391 }
1392 }
1393 }
1394 }
1395 }
1396 Ok(mes)
1397 }
1398
1399 fn import_messages<'a>(
1400 &'a self,
1401 messages: Vec<Message>,
1402 mut file: Box<dyn WriteSeek + 'a>,
1403 _filename: &str,
1404 encoding: Encoding,
1405 replacement: Option<&'a ReplacementTable>,
1406 ) -> Result<()> {
1407 let mut messages_iter = messages.into_iter();
1408
1409 let mut inst_data: Vec<(YSTBInstBase, Vec<(YSTBArgBase, Vec<u8>)>)> = Vec::new();
1411
1412 for code in self.data.insts.iter() {
1413 let meta =
1414 self.com.opcodes.get(code.opcode as usize).ok_or_else(|| {
1415 anyhow::anyhow!("Failed to find op {:x}'s metadata", code.opcode)
1416 })?;
1417
1418 let mut new_args: Vec<(YSTBArgBase, Vec<u8>)> = code
1420 .args
1421 .iter()
1422 .map(|arg| (arg.base.clone(), arg.data.clone()))
1423 .collect();
1424
1425 if meta.name == "WORD" {
1426 if code.arg_count == 1 {
1427 let arg = &code.args[0];
1428 if arg.typ == 0 && arg.size > 0 {
1429 let mut msg = messages_iter
1430 .next()
1431 .ok_or_else(|| anyhow::anyhow!("No more messages to import"))?;
1432 if let Some(table) = replacement {
1433 for (from, to) in &table.map {
1434 msg.message = msg.message.replace(from, to);
1435 }
1436 if let Some(ref name) = msg.name {
1437 let mut new_name = name.clone();
1438 for (from, to) in &table.map {
1439 new_name = new_name.replace(from, to);
1440 }
1441 msg.name = Some(new_name);
1442 }
1443 }
1444 let mut text = msg.message;
1445 if let Some(name) = msg.name {
1446 text = format!("【{}】{}", name, text);
1447 }
1448 let encoded = encode_string(encoding, &text, true)?;
1449 new_args[0].1 = encoded;
1450 new_args[0].0.size = new_args[0].1.len() as u32;
1451 }
1452 }
1453 } else if meta.name == "_"
1454 && !meta.arguments.is_empty()
1455 && code.arg_count == 1
1456 && meta.arguments[0].data == 3
1457 {
1458 let arg = &code.args[0];
1459 if arg.data.starts_with(PUSHSTRING_TYPE) {
1460 let len = u16::from_le_bytes([arg.data[1], arg.data[2]]);
1461 if len as u32 + 3 == arg.size {
1462 let mut msg = messages_iter
1463 .next()
1464 .ok_or_else(|| anyhow::anyhow!("No more messages to import"))?;
1465 if let Some(table) = replacement {
1466 for (from, to) in &table.map {
1467 msg.message = msg.message.replace(from, to);
1468 }
1469 }
1470 let d = encode_string(encoding, &msg.message, true)?;
1471 new_args[0].1 = make_pushstring_data(&d);
1472 new_args[0].0.size = new_args[0].1.len() as u32;
1473 }
1474 }
1475 } else if meta.name == "GOSUB" && code.arg_count >= 2 {
1476 let arg0 = &code.args[0];
1477 let name = format!("{:?}", &YSTBArgData(&arg0.data, arg0.encoding))
1478 .trim_matches('"')
1479 .to_lowercase();
1480 if name == "es.sel.set" {
1481 for arg_pair in new_args.iter_mut().skip(1) {
1482 let data = &arg_pair.1;
1483 if data.starts_with(PUSHSTRING_TYPE) {
1484 let slen = u16::from_le_bytes([data[1], data[2]]);
1485 if slen as u32 + 3 == arg_pair.0.size {
1486 let mut msg = messages_iter
1487 .next()
1488 .ok_or_else(|| anyhow::anyhow!("No more messages to import"))?;
1489 if let Some(table) = replacement {
1490 for (from, to) in &table.map {
1491 msg.message = msg.message.replace(from, to);
1492 }
1493 }
1494 if !msg.message.is_empty() {
1495 let d = encode_string(encoding, &msg.message, true)?;
1496 arg_pair.1 = make_pushstring_data(&d);
1497 arg_pair.0.size = arg_pair.1.len() as u32;
1498 }
1499 }
1500 }
1501 }
1502 } else if name == "es.char.name" && code.arg_count >= 3 {
1503 let arg1 = &code.args[1];
1505 if arg1.data.starts_with(PUSHSTRING_TYPE) {
1506 let slen = u16::from_le_bytes([arg1.data[1], arg1.data[2]]);
1507 if slen as u32 + 3 == arg1.size {
1508 let mut decoded = decode_to_string(
1509 arg1.encoding,
1510 &arg1.data[4..arg1.size as usize - 1],
1511 true,
1512 )?;
1513 if let Some(table) = replacement {
1514 for (from, to) in &table.map {
1515 decoded = decoded.replace(from, to);
1516 }
1517 }
1518 let d = encode_string(encoding, &decoded, true)?;
1519 new_args[1].1 = make_pushstring_data(&d);
1520 new_args[1].0.size = new_args[1].1.len() as u32;
1521 }
1522 }
1523 let arg2 = &code.args[2];
1525 if arg2.data.starts_with(PUSHSTRING_TYPE) {
1526 let slen = u16::from_le_bytes([arg2.data[1], arg2.data[2]]);
1527 if slen as u32 + 3 == arg2.size {
1528 let mut msg = messages_iter
1529 .next()
1530 .ok_or_else(|| anyhow::anyhow!("No more messages to import"))?;
1531 if let Some(table) = replacement {
1532 for (from, to) in &table.map {
1533 msg.message = msg.message.replace(from, to);
1534 }
1535 }
1536 let d = encode_string(encoding, &msg.message, true)?;
1537 new_args[2].1 = make_pushstring_data(&d);
1538 new_args[2].0.size = new_args[2].1.len() as u32;
1539 }
1540 }
1541 } else if name == "es.char.name.mark.set" && code.arg_count >= 2 {
1542 let arg1 = &code.args[1];
1544 if arg1.data.starts_with(PUSHSTRING_TYPE) {
1545 let slen = u16::from_le_bytes([arg1.data[1], arg1.data[2]]);
1546 if slen as u32 + 3 == arg1.size {
1547 let mut decoded = decode_to_string(
1548 arg1.encoding,
1549 &arg1.data[4..arg1.size as usize - 1],
1550 true,
1551 )?;
1552 if let Some(table) = replacement {
1553 for (from, to) in &table.map {
1554 decoded = decoded.replace(from, to);
1555 }
1556 }
1557 let d = encode_string(encoding, &decoded, true)?;
1558 new_args[1].1 = make_pushstring_data(&d);
1559 new_args[1].0.size = new_args[1].1.len() as u32;
1560 }
1561 }
1562 }
1563 }
1564
1565 inst_data.push((code.base.clone(), new_args));
1566 }
1567
1568 let mut f = MemWriter::new();
1570 f.write_all(b"YSTB")?;
1571
1572 let inst_entry_count = inst_data.len() as u32;
1573 let inst_index_size = inst_entry_count * 4;
1574 let arg_count: usize = inst_data.iter().map(|(_, args)| args.len()).sum();
1575 let args_index_size = arg_count as u32 * 0xC;
1576
1577 let mut header = self.data.header.clone();
1578 header.inst_entry_count = inst_entry_count;
1579 header.inst_index_size = inst_index_size;
1580 header.args_index_size = args_index_size;
1581 header.line_numbers_size = self.data.line_numbers.len() as u32;
1582
1583 header.pack(&mut f, false, encoding, &None)?;
1585
1586 for (base, args) in inst_data.iter() {
1588 let mut b = base.clone();
1589 b.arg_count = args.len() as u8;
1590 b.pack(&mut f, false, encoding, &None)?;
1591 }
1592
1593 let mut cpos = f.pos as u64;
1595 f.pos += args_index_size as usize;
1596 let bpos = f.pos as u32;
1597
1598 for (base, args) in inst_data.iter_mut() {
1599 let meta =
1600 self.com.opcodes.get(base.opcode as usize).ok_or_else(|| {
1601 anyhow::anyhow!("Failed to find op {:x}'s metadata", base.opcode)
1602 })?;
1603
1604 for arg in args.iter_mut() {
1605 arg.0.size = arg.1.len() as u32;
1606 f.write_struct_at(cpos, &arg.0, false, encoding, &None)?;
1607 cpos += 8;
1608
1609 if arg.0.size == 0
1610 || (meta.name == "RETURNCODE" && arg.0.size == 1 && arg.1[0] == b'M')
1611 {
1612 f.write_u32_at(cpos, 0)?;
1613 cpos += 4;
1614 continue;
1615 }
1616
1617 let offset = f.pos as u32 - bpos;
1618 f.write_u32_at(cpos, offset)?;
1619 cpos += 4;
1620 f.write_all(&arg.1)?;
1621 }
1622 }
1623
1624 header.args_data_size = f.pos as u32 - bpos;
1626 f.write_all(&self.data.line_numbers)?;
1627
1628 f.pos = 4;
1630 header.pack(&mut f, false, encoding, &None)?;
1631
1632 if let Some(xor) = self.xor_key {
1634 let mut r = MemReader::new(f.into_inner());
1635 f = MemWriter::new();
1636 Self::xor(&mut r, &mut f, xor)?;
1637 }
1638
1639 file.write_all(&f.data)?;
1640 Ok(())
1641 }
1642
1643 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
1644 if !self.disasm {
1645 let wrapper = YSTBDataSer {
1646 data: &self.data,
1647 com: &self.com,
1648 labels: &self.labels,
1649 };
1650 let s = if self.custom_yaml {
1651 serde_yaml_ng::to_string(&wrapper)?
1652 } else {
1653 serde_json::to_string_pretty(&wrapper)?
1654 };
1655 let mut f = std::fs::File::create(filename)?;
1656 let encoded = encode_string(encoding, &s, true)?;
1657 f.write_all(&encoded)?;
1658 return Ok(());
1659 }
1660 let mut file = MemWriter::new();
1661 let mut indent = String::new();
1662 let mut unused_labels = BTreeSet::from_iter(self.labels.keys().cloned());
1663 for (i, code) in self.data.insts.iter().enumerate() {
1664 let offset = i as u32;
1665 let meta =
1666 self.com.opcodes.get(code.opcode as usize).ok_or_else(|| {
1667 anyhow::anyhow!("Failed to find op {:x}'s metadata", code.opcode)
1668 })?;
1669 if let Some(lab) = self.labels.get(&offset) {
1670 writeln!(file, "#{}", lab.name)?;
1671 unused_labels.remove(&offset);
1672 }
1673 if meta.name == "IFEND" || meta.name == "IFBLEND" || meta.name == "LOOPEND" {
1674 indent.pop();
1675 indent.pop();
1676 }
1677 write!(file, "{}", indent)?;
1678 if meta.name == "GOSUB" {
1679 if code.arg_count < 1 {
1680 anyhow::bail!("GOSUB at least need one argument.");
1681 }
1682 let arg0 = &code.args[0];
1683 let name = format!("{:?}", &YSTBArgData(&arg0.data, arg0.encoding));
1684 write!(file, "\\{}(", name.trim_matches('"'))?;
1685 let mut first = true;
1686 for arg in &code.args[1..] {
1687 write!(
1688 file,
1689 "{}{:?}",
1690 if first {
1691 first = false;
1692 ""
1693 } else {
1694 ", "
1695 },
1696 &YSTBArgData(&arg.data, arg.encoding)
1697 )?;
1698 }
1699 writeln!(file, ")")?;
1700 } else {
1701 write!(file, "{}[", meta.name)?;
1702 let mut first = true;
1703 for arg in &code.args {
1704 if first {
1705 first = false;
1706 } else {
1707 write!(file, ", ")?;
1708 }
1709 if meta.arguments.len() > arg.id as usize {
1710 write!(file, "{}=", meta.arguments[arg.id as usize].name)?;
1711 }
1712 write!(file, "{:?}", &YSTBArgData(&arg.data, arg.encoding))?;
1713 }
1714 writeln!(file, "]")?;
1715 }
1716 if meta.name == "IF" || meta.name == "ELSE" || meta.name == "LOOP" {
1717 indent += " ";
1718 }
1719 }
1720 let mut f = std::fs::File::create(filename)?;
1721 if encoding.is_utf8() {
1722 f.write_all(&file.data)?;
1723 } else {
1724 let s = decode_to_string(Encoding::Utf8, &file.data, true)?;
1725 let encoded = encode_string(encoding, &s, true)?;
1726 f.write_all(&encoded)?;
1727 }
1728 if !unused_labels.is_empty() {
1729 eprintln!("WARNING: Some labels not used: {:?}", unused_labels);
1730 crate::COUNTER.inc_warning();
1731 }
1732 Ok(())
1733 }
1734
1735 fn custom_import<'a>(
1736 &'a self,
1737 custom_filename: &'a str,
1738 mut file: Box<dyn WriteSeek + 'a>,
1739 encoding: Encoding,
1740 output_encoding: Encoding,
1741 ) -> Result<()> {
1742 if self.disasm {
1743 anyhow::bail!("Import is not supported for disasm mode.");
1744 }
1745 let mut f = MemWriter::new();
1746 let data = crate::utils::files::read_file(custom_filename)?;
1747 let data = decode_to_string(output_encoding, &data, true)?;
1748 let mut data: YSTBData = if self.custom_yaml {
1749 serde_yaml_ng::from_str(&data)?
1750 } else {
1751 serde_json::from_str(&data)?
1752 };
1753 f.write_all(b"YSTB")?;
1754 data.header.line_numbers_size = data.line_numbers.len() as u32;
1755 data.header.inst_entry_count = data.insts.len() as u32;
1756 data.header.inst_index_size = data.header.inst_entry_count * 4;
1757 data.header.pack(&mut f, false, encoding, &None)?;
1758 for i in data.insts.iter_mut() {
1759 i.base.arg_count = i.args.len() as u8;
1760 i.base.pack(&mut f, false, encoding, &None)?;
1761 }
1762 let arg_count = data.insts.iter().fold(0, |c, i| c + i.args.len());
1763 data.header.args_index_size = arg_count as u32 * 0xC;
1764 let mut cpos = f.pos as u64;
1765 f.pos += data.header.args_index_size as usize;
1766 let bpos = f.pos as u32;
1767 for i in data.insts.iter_mut() {
1768 let meta =
1769 self.com.opcodes.get(i.opcode as usize).ok_or_else(|| {
1770 anyhow::anyhow!("Failed to find op {:x}'s metadata", i.opcode)
1771 })?;
1772 for arg in i.args.iter_mut() {
1773 arg.base.size = arg.data.len() as u32;
1774 f.write_struct_at(cpos, &arg.base, false, encoding, &None)?;
1775 cpos += 8;
1776 if arg.base.size == 0
1777 || (meta.name == "RETURNCODE" && arg.base.size == 1 && arg.data[0] == b'M')
1778 {
1779 f.write_u32_at(cpos, 0)?;
1780 cpos += 4;
1781 continue;
1782 }
1783 let offset = f.pos as u32 - bpos;
1784 f.write_u32_at(cpos, offset)?;
1785 cpos += 4;
1786 f.write_all(&arg.data)?;
1787 }
1788 }
1789 data.header.args_data_size = f.pos as u32 - bpos;
1790 f.write_all(&data.line_numbers)?;
1791 f.pos = 4;
1792 data.header.pack(&mut f, false, encoding, &None)?;
1793 if let Some(xor) = self.xor_key {
1794 let mut r = MemReader::new(f.into_inner());
1795 f = MemWriter::new();
1796 Self::xor(&mut r, &mut f, xor)?;
1797 }
1798 file.write_all(&f.data)?;
1799 Ok(())
1800 }
1801}