1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::struct_pack::*;
7use anyhow::Result;
8use msg_tool_macro::*;
9use serde::ser::SerializeStruct;
10use serde::{Deserialize, Serialize};
11use std::collections::BTreeMap;
12use std::io::{Read, Seek, Write};
13
14#[derive(Debug)]
15pub struct RldScriptBuilder {}
17
18impl RldScriptBuilder {
19 pub fn new() -> Self {
21 Self {}
22 }
23}
24
25impl ScriptBuilder for RldScriptBuilder {
26 fn default_encoding(&self) -> Encoding {
27 Encoding::Cp932
28 }
29
30 fn build_script(
31 &self,
32 buf: Vec<u8>,
33 filename: &str,
34 encoding: Encoding,
35 _archive_encoding: Encoding,
36 config: &ExtraConfig,
37 _archive: Option<&Box<dyn Script>>,
38 ) -> Result<Box<dyn Script>> {
39 Ok(Box::new(RldScript::new(buf, filename, encoding, config)?))
40 }
41
42 fn extensions(&self) -> &'static [&'static str] {
43 &["rld"]
44 }
45
46 fn script_type(&self) -> &'static ScriptType {
47 &ScriptType::ExHibit
48 }
49
50 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
51 if buf_len >= 4 && buf.starts_with(b"\0DLR") {
52 return Some(10);
53 }
54 None
55 }
56}
57
58#[derive(Debug)]
59struct XorKey {
60 xor_key: u32,
61 keys: [u32; 0x100],
62}
63
64#[derive(Debug, StructPack, StructUnpack)]
65struct Header {
66 ver: u32,
67 offset: u32,
68 count: u32,
69}
70
71#[derive(Clone, Debug, StructPack, StructUnpack)]
72struct Op {
73 op: u16,
74 init_count: u8,
75 unk: u8,
76}
77
78impl PartialEq<u16> for Op {
79 fn eq(&self, other: &u16) -> bool {
80 self.op == *other
81 }
82}
83
84impl Op {
85 pub fn str_count(&self) -> u8 {
86 self.unk & 0xF
87 }
88}
89
90#[derive(Clone, Debug)]
91struct OpExt {
92 op: Op,
93 strs: Vec<String>,
94 ints: Vec<u32>,
95}
96
97impl<'de> Deserialize<'de> for OpExt {
98 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
99 where
100 D: serde::Deserializer<'de>,
101 {
102 #[derive(Deserialize)]
103 struct OpExtHelper {
104 op: u16,
105 unk: u8,
106 strs: Vec<String>,
107 ints: Vec<u32>,
108 }
109
110 let helper = OpExtHelper::deserialize(deserializer)?;
111 let init_count = helper.ints.len() as u8;
112 let str_count = helper.strs.len() as u8;
113 let unk = (helper.unk << 4) | (str_count & 0xF);
114
115 Ok(OpExt {
116 op: Op {
117 op: helper.op,
118 init_count,
119 unk,
120 },
121 strs: helper.strs,
122 ints: helper.ints,
123 })
124 }
125}
126
127impl Serialize for OpExt {
128 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
129 let mut state = serializer.serialize_struct("OpExt", 4)?;
130 state.serialize_field("op", &self.op.op)?;
131 state.serialize_field("unk", &((self.op.unk & 0xF0) >> 4))?;
132 state.serialize_field("strs", &self.strs)?;
133 state.serialize_field("ints", &self.ints)?;
134 state.end()
135 }
136}
137
138impl StructPack for OpExt {
139 fn pack<W: Write>(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> {
140 self.op.op.pack(writer, big, encoding)?;
141 let init_count = self.ints.len() as u8;
142 init_count.pack(writer, big, encoding)?;
143 let unk = (self.op.unk & 0xF0) | (self.strs.len() as u8 & 0xF);
144 unk.pack(writer, big, encoding)?;
145 for i in &self.ints {
146 i.pack(writer, big, encoding)?;
147 }
148 for s in &self.strs {
149 let encoded = encode_string(encoding, s, true)?;
150 writer.write_all(&encoded)?;
151 writer.write_u8(0)?; }
153 Ok(())
154 }
155}
156
157impl StructUnpack for OpExt {
158 fn unpack<R: Read + Seek>(mut reader: R, big: bool, encoding: Encoding) -> Result<Self> {
159 let op = Op::unpack(&mut reader, big, encoding)?;
160 let mut ints = Vec::with_capacity(op.init_count as usize);
161 for _ in 0..op.init_count {
162 let i = u32::unpack(&mut reader, big, encoding)?;
163 ints.push(i);
164 }
165 let mut strs = Vec::with_capacity(op.str_count() as usize);
166 for _ in 0..op.str_count() {
167 let s = reader.read_cstring()?;
168 let s = decode_to_string(encoding, s.as_bytes(), true)?;
169 strs.push(s);
170 }
171 Ok(Self { op, strs, ints })
172 }
173}
174
175#[derive(Debug)]
176pub struct RldScript {
178 data: MemReader,
179 decrypted: bool,
180 xor_key: Option<XorKey>,
181 header: Header,
182 _flag: u32,
183 _tag: Option<String>,
184 ops: Vec<OpExt>,
185 is_def_chara: bool,
186 name_table: Option<BTreeMap<u32, String>>,
187 custom_yaml: bool,
188}
189
190impl RldScript {
191 pub fn new(
198 buf: Vec<u8>,
199 filename: &str,
200 encoding: Encoding,
201 config: &ExtraConfig,
202 ) -> Result<Self> {
203 let mut reader = MemReader::new(buf);
204 let mut magic = [0u8; 4];
205 reader.read_exact(&mut magic)?;
206 if &magic != b"\0DLR" {
207 return Err(anyhow::anyhow!("Invalid RLD script magic: {:?}", magic));
208 }
209 let is_def = std::path::Path::new(filename)
210 .file_stem()
211 .map(|s| s.to_ascii_lowercase() == "def")
212 .unwrap_or(false);
213 let is_def_chara = std::path::Path::new(filename)
214 .file_stem()
215 .map(|s| s.to_ascii_lowercase() == "defchara")
216 .unwrap_or(false);
217 let xor_key = if is_def {
218 if let Some(xor_key) = config.ex_hibit_rld_def_xor_key {
219 let keys = config
220 .ex_hibit_rld_def_keys
221 .as_deref()
222 .cloned()
223 .ok_or(anyhow::anyhow!("No keys provided for def RLD script"))?;
224 Some(XorKey {
225 xor_key,
226 keys: keys,
227 })
228 } else {
229 None
230 }
231 } else {
232 if let Some(xor_key) = config.ex_hibit_rld_xor_key {
233 let keys = config
234 .ex_hibit_rld_keys
235 .as_deref()
236 .cloned()
237 .ok_or(anyhow::anyhow!("No keys provided for RLD script"))?;
238 Some(XorKey {
239 xor_key,
240 keys: keys,
241 })
242 } else {
243 None
244 }
245 };
246 let header = Header::unpack(&mut reader, false, encoding)?;
247 let mut decrypted = false;
248 if let Some(key) = &xor_key {
249 Self::xor(&mut reader.data, key);
250 decrypted = true;
251 }
252 let flag = reader.read_u32()?;
253 let tag = if flag == 1 {
254 let s = reader.read_cstring()?;
255 Some(decode_to_string(encoding, s.as_bytes(), true)?)
256 } else {
257 None
258 };
259 reader.pos = header.offset as usize;
260 let mut ops = Vec::with_capacity(header.count as usize);
261 for _ in 0..header.count {
262 let op = OpExt::unpack(&mut reader, false, encoding)?;
263 ops.push(op);
264 }
265 let name_table = if is_def_chara {
266 None
267 } else {
268 match Self::try_load_name_table(filename, encoding, config) {
269 Ok(table) => Some(table),
270 Err(e) => {
271 eprintln!("WARN: Failed to load name table: {}", e);
272 crate::COUNTER.inc_warning();
273 None
274 }
275 }
276 };
277 Ok(Self {
278 data: reader,
279 decrypted,
280 xor_key,
281 header,
282 _flag: flag,
283 _tag: tag,
284 ops,
285 is_def_chara,
286 name_table,
287 custom_yaml: config.custom_yaml,
288 })
289 }
290
291 fn try_load_name_table(
292 filename: &str,
293 encoding: Encoding,
294 config: &ExtraConfig,
295 ) -> Result<BTreeMap<u32, String>> {
296 let mut pb = std::path::Path::new(filename).to_path_buf();
297 pb.set_file_name("defChara.rld");
298 let f = crate::utils::files::read_file(&pb)?;
299 let f = Self::new(f, &pb.to_string_lossy(), encoding, config)?;
300 Ok(f.name_table()?)
301 }
302
303 fn xor(data: &mut Vec<u8>, key: &XorKey) {
304 let mut end = data.len().min(0xFFCF);
305 end -= end % 4;
306 let mut ri = 0;
307 for i in (0x10..end).step_by(4) {
308 let en_temp = u32::from_le_bytes([data[i], data[i + 1], data[i + 2], data[i + 3]]);
309 let temp_key = key.keys[ri & 0xFF] ^ key.xor_key;
310 let de_temp = (en_temp ^ temp_key).to_le_bytes();
311 data[i] = de_temp[0];
312 data[i + 1] = de_temp[1];
313 data[i + 2] = de_temp[2];
314 data[i + 3] = de_temp[3];
315 ri += 1;
316 }
317 }
318
319 fn name_table(&self) -> Result<BTreeMap<u32, String>> {
320 let mut names = BTreeMap::new();
321 for op in &self.ops {
322 if op.op == 48 {
323 if op.strs.is_empty() {
324 return Err(anyhow::anyhow!("Op 48 has no strings"));
325 }
326 let name = op.strs[0].clone();
327 let data: Vec<_> = name.split(",").collect();
328 if data.len() < 4 {
329 return Err(anyhow::anyhow!("Op 48 has invalid data: {}", name));
330 }
331 let id = data[0].parse::<u32>()?;
332 let name = data[3].to_string();
333 names.insert(id, name);
334 }
335 }
336 Ok(names)
337 }
338
339 fn write_script<W: Write + Seek>(
340 &self,
341 mut writer: W,
342 encoding: Encoding,
343 ops: &[OpExt],
344 ) -> Result<()> {
345 writer.write_all(&self.data.data[..self.header.offset as usize])?;
346 let op_count = ops.len() as u32;
347 if op_count != self.header.count {
348 writer.write_u32_at(12, op_count)?;
349 }
350 for op in ops {
351 op.pack(&mut writer, false, encoding)?;
352 }
353 if self.data.data.len() > self.data.pos {
354 writer.write_all(&self.data.data[self.data.pos..])?;
355 }
356 Ok(())
357 }
358}
359
360impl Script for RldScript {
361 fn default_output_script_type(&self) -> OutputScriptType {
362 if self.is_def_chara {
363 return OutputScriptType::Custom;
364 }
365 OutputScriptType::Json
366 }
367
368 fn is_output_supported(&self, output: OutputScriptType) -> bool {
369 if self.is_def_chara {
370 return matches!(output, OutputScriptType::Custom);
371 }
372 true
373 }
374
375 fn default_format_type(&self) -> FormatOptions {
376 FormatOptions::None
377 }
378
379 fn custom_output_extension<'a>(&'a self) -> &'a str {
380 if self.custom_yaml { "yaml" } else { "json" }
381 }
382
383 fn extract_messages(&self) -> Result<Vec<Message>> {
384 let mut messages = Vec::new();
385 for op in &self.ops {
386 if op.op == 28 {
387 if op.strs.len() < 2 {
388 return Err(anyhow::anyhow!("Op 28 has less than 2 strings"));
389 }
390 let name = if op.strs[0] == "*" {
391 if op.ints.is_empty() {
392 return Err(anyhow::anyhow!("Op 28 has no integers"));
393 }
394 let id = op.ints[0];
395 self.name_table
396 .as_ref()
397 .and_then(|table| table.get(&id).cloned())
398 } else if op.strs[0] == "$noname$" {
399 None
400 } else {
401 Some(op.strs[0].clone())
402 };
403 let text = op.strs[1].clone();
404 messages.push(Message {
405 name,
406 message: text,
407 });
408 } else if op.op == 21 || op.op == 191 {
409 eprintln!("{op:?}");
410 }
411 }
412 Ok(messages)
413 }
414
415 fn import_messages<'a>(
416 &'a self,
417 messages: Vec<Message>,
418 mut file: Box<dyn WriteSeek + 'a>,
419 _filename: &str,
420 encoding: Encoding,
421 replacement: Option<&'a ReplacementTable>,
422 ) -> Result<()> {
423 let mut ops = self.ops.clone();
424 let mut mes = messages.iter();
425 let mut mess = mes.next();
426 for op in ops.iter_mut() {
427 if op.op == 28 {
428 let m = match mess {
429 Some(m) => m,
430 None => return Err(anyhow::anyhow!("Not enough messages.")),
431 };
432 if op.strs.len() < 2 {
433 return Err(anyhow::anyhow!("Op 28 has less than 2 strings"));
434 }
435 if op.strs[0] != "*" && op.strs[0] != "$noname$" {
436 let mut name = match &m.name {
437 Some(name) => name.clone(),
438 None => {
439 return Err(anyhow::anyhow!("Message has no name"));
440 }
441 };
442 if let Some(replacement) = replacement {
443 for (k, v) in &replacement.map {
444 name = name.replace(k, v);
445 }
446 }
447 op.strs[0] = name;
448 }
449 let mut message = m.message.clone();
450 if let Some(replacement) = replacement {
451 for (k, v) in &replacement.map {
452 message = message.replace(k, v);
453 }
454 }
455 op.strs[1] = message;
456 mess = mes.next();
457 }
458 }
459 if mess.is_some() || mes.next().is_some() {
460 return Err(anyhow::anyhow!("Too many messages provided."));
461 }
462 if self.decrypted {
463 let mut writer = MemWriter::new();
464 self.write_script(&mut writer, encoding, &ops)?;
465 if let Some(key) = &self.xor_key {
466 Self::xor(&mut writer.data, key);
467 }
468 file.write_all(&writer.data)?;
469 } else {
470 self.write_script(&mut file, encoding, &ops)?;
471 }
472 Ok(())
473 }
474
475 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
476 let s = if self.is_def_chara {
477 let names = self.name_table()?;
478 if self.custom_yaml {
479 serde_yaml_ng::to_string(&names)
480 .map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
481 } else {
482 serde_json::to_string(&names)
483 .map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
484 }
485 } else {
486 if self.custom_yaml {
487 serde_yaml_ng::to_string(&self.ops)
488 .map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
489 } else {
490 serde_json::to_string(&self.ops)
491 .map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
492 }
493 };
494 let s = encode_string(encoding, &s, false)?;
495 let mut file = std::fs::File::create(filename)?;
496 file.write_all(&s)?;
497 Ok(())
498 }
499
500 fn custom_import<'a>(
501 &'a self,
502 custom_filename: &'a str,
503 mut file: Box<dyn WriteSeek + 'a>,
504 encoding: Encoding,
505 output_encoding: Encoding,
506 ) -> Result<()> {
507 let f = crate::utils::files::read_file(custom_filename)?;
508 let s = decode_to_string(output_encoding, &f, true)?;
509 let ops: Vec<OpExt> = if self.is_def_chara {
510 let mut ops = self.ops.clone();
511 let names: BTreeMap<u32, String> = if self.custom_yaml {
512 serde_yaml_ng::from_str(&s)
513 .map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
514 } else {
515 serde_json::from_str(&s)
516 .map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
517 };
518 for op in ops.iter_mut() {
519 if op.op == 48 {
520 if op.strs.is_empty() {
521 return Err(anyhow::anyhow!("Op 48 has no strings"));
522 }
523 let name = op.strs[0].clone();
524 let data: Vec<_> = name.split(",").collect();
525 if data.len() < 4 {
526 return Err(anyhow::anyhow!("Op 48 has invalid data: {}", name));
527 }
528 let id = data[0].parse::<u32>()?;
529 let name = names
530 .get(&id)
531 .cloned()
532 .unwrap_or_else(|| data[3].to_string());
533 let mut data = data.iter().map(|s| s.to_string()).collect::<Vec<_>>();
534 data[3] = name;
535 op.strs[0] = data.join(",");
536 }
537 }
538 ops
539 } else {
540 if self.custom_yaml {
541 serde_yaml_ng::from_str(&s)
542 .map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
543 } else {
544 serde_json::from_str(&s)
545 .map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
546 }
547 };
548 if self.decrypted {
549 let mut writer = MemWriter::new();
550 self.write_script(&mut writer, encoding, &ops)?;
551 if let Some(key) = &self.xor_key {
552 Self::xor(&mut writer.data, key);
553 }
554 file.write_all(&writer.data)?;
555 } else {
556 self.write_script(&mut file, encoding, &ops)?;
557 }
558 Ok(())
559 }
560}
561
562pub fn load_keys(path: Option<&String>) -> Result<Option<Box<[u32; 0x100]>>> {
564 if let Some(path) = path {
565 let f = crate::utils::files::read_file(path)?;
566 let mut reader = MemReader::new(f);
567 let mut keys = [0u32; 0x100];
568 for i in 0..0x100 {
569 keys[i] = reader.read_u32()?;
570 }
571 Ok(Some(Box::new(keys)))
572 } else {
573 Ok(None)
574 }
575}
576
577#[test]
578fn test_ser() {
579 let op = OpExt {
580 op: Op {
581 op: 28,
582 init_count: 1,
583 unk: 0x10 | 2,
584 },
585 strs: vec!["name".to_string(), "message".to_string()],
586 ints: vec![123],
587 };
588 let json = serde_json::to_string(&op).unwrap();
589 assert_eq!(
590 json,
591 r#"{"op":28,"unk":1,"strs":["name","message"],"ints":[123]}"#
592 );
593}
594
595#[test]
596fn test_de_ser() {
597 let json = r#"{"op":28,"unk":1,"strs":["name","message"],"ints":[123]}"#;
598 let op: OpExt = serde_json::from_str(json).unwrap();
599 assert_eq!(op.op.op, 28);
600 assert_eq!(op.op.init_count, 1);
601 assert_eq!(op.op.unk, 0x10 | 2);
602 assert_eq!(op.strs[0], "name");
603 assert_eq!(op.strs[1], "message");
604 assert_eq!(op.ints[0], 123);
605}