msg_tool\scripts\artemis\ast/
mod.rs

1//! Artemis Engine AST file (.ast)
2mod dump;
3mod parser;
4mod text;
5mod types;
6
7use crate::scripts::base::*;
8use crate::types::*;
9use crate::utils::encoding::*;
10use anyhow::Result;
11use std::io::Write;
12
13pub use dump::Dumper;
14pub use parser::Parser;
15pub use types::*;
16
17#[derive(Debug)]
18/// The builder for Artemis AST scripts.
19pub struct AstScriptBuilder {}
20
21impl AstScriptBuilder {
22    /// Creates a new instance of `AstScriptBuilder`.
23    pub fn new() -> Self {
24        AstScriptBuilder {}
25    }
26}
27
28impl ScriptBuilder for AstScriptBuilder {
29    fn default_encoding(&self) -> Encoding {
30        Encoding::Utf8
31    }
32
33    fn build_script(
34        &self,
35        buf: Vec<u8>,
36        _filename: &str,
37        encoding: Encoding,
38        _archive_encoding: Encoding,
39        config: &ExtraConfig,
40        _archive: Option<&Box<dyn Script>>,
41    ) -> Result<Box<dyn Script>> {
42        Ok(Box::new(AstScript::new(buf, encoding, config)?))
43    }
44
45    fn extensions(&self) -> &'static [&'static str] {
46        &["ast"]
47    }
48
49    fn script_type(&self) -> &'static ScriptType {
50        &ScriptType::Artemis
51    }
52
53    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
54        let parser = parser::Parser::new(&buf[..buf_len], Encoding::Utf8);
55        if parser.try_parse_header().is_ok() {
56            Some(15)
57        } else {
58            None
59        }
60    }
61}
62
63#[derive(Debug)]
64/// The Artemis AST script.
65pub struct AstScript {
66    ast: AstFile,
67    indent: Option<usize>,
68    max_line_width: usize,
69    no_indent: bool,
70    lang: Option<String>,
71}
72
73impl AstScript {
74    /// Creates a new Artemis AST script from the given buffer.
75    ///
76    /// * `buf` - The buffer containing the AST data.
77    /// * `encoding` - The encoding used for the AST data.
78    /// * `config` - Extra configuration options.
79    pub fn new(buf: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
80        let parser = parser::Parser::new(&buf, encoding);
81        let ast = parser.parse()?;
82        Ok(AstScript {
83            ast,
84            indent: config.artemis_indent,
85            max_line_width: config.artemis_max_line_width,
86            no_indent: config.artemis_no_indent,
87            lang: config.artemis_ast_lang.clone(),
88        })
89    }
90}
91
92impl Script for AstScript {
93    fn default_output_script_type(&self) -> OutputScriptType {
94        OutputScriptType::Json
95    }
96
97    fn default_format_type(&self) -> FormatOptions {
98        FormatOptions::None
99    }
100
101    fn extract_messages(&self) -> Result<Vec<Message>> {
102        let mut messages = Vec::new();
103        let ast = &self.ast.ast;
104        let mut lang: Option<&str> = self.lang.as_ref().map(|s| s.as_str());
105        // old version
106        if ast["label"]["top"]["block"].is_null() && ast["text"].is_array() {
107            let text = &ast["text"];
108            let mut text_index = 1i64;
109            for block in ast.members() {
110                if block.is_array() {
111                    let savetitle = &block[Key("savetitle")];
112                    if savetitle.is_array() {
113                        if let Some(lang) = lang {
114                            if let Some(title) = savetitle[lang].as_str() {
115                                messages.push(Message {
116                                    name: None,
117                                    message: title.to_string(),
118                                });
119                            } else if let Some(title) = savetitle["text"].as_str() {
120                                messages.push(Message {
121                                    name: None,
122                                    message: title.to_string(),
123                                });
124                            }
125                        } else if let Some(title) = savetitle["text"].as_str() {
126                            messages.push(Message {
127                                name: None,
128                                message: title.to_string(),
129                            });
130                        }
131                    }
132                    if !block[Key("text")].is_null() {
133                        let tex = &text[NumKey(text_index)];
134                        text_index += 1;
135                        if tex.is_array() {
136                            let lan = match lang {
137                                Some(l) => l,
138                                None => {
139                                    for l in tex.kv_keys() {
140                                        if l.is_str() && l != "vo" && l != "name" {
141                                            lang = l.as_str();
142                                            break;
143                                        }
144                                    }
145                                    match lang {
146                                        Some(l) => l,
147                                        // No text found, continue to next block
148                                        None => continue,
149                                    }
150                                }
151                            };
152                            let mut te = &tex[lan];
153                            if te.is_null() {
154                                for l in tex.kv_keys() {
155                                    if l != "vo" && l != "name" {
156                                        te = &tex[l];
157                                        break;
158                                    }
159                                }
160                            }
161                            let name = &tex["name"];
162                            let nam = if name.is_array() {
163                                if let Some(lang) = lang {
164                                    if let Some(n) = name[lang].as_string() {
165                                        Some(n)
166                                    } else if let Some(n) = name["name"].as_string() {
167                                        Some(n)
168                                    } else {
169                                        None
170                                    }
171                                } else if let Some(n) = name["name"].as_string() {
172                                    Some(n)
173                                } else {
174                                    None
175                                }
176                            } else {
177                                None
178                            };
179                            for item in te.members() {
180                                let message = text::TextGenerator::new().generate(item)?;
181                                messages.push(Message {
182                                    name: nam.clone(),
183                                    message: message.replace("<rt2>", "\n").replace("<ret2>", "\n"),
184                                });
185                            }
186                        }
187                    } else if !block[Key("select")].is_null() {
188                        let tex = &text[NumKey(text_index)]["select"];
189                        text_index += 1;
190                        if tex.is_array() {
191                            let lan = match lang {
192                                Some(l) => l,
193                                None => {
194                                    for l in tex.kv_keys() {
195                                        if l.is_str() && l != "vo" && l != "name" {
196                                            lang = l.as_str();
197                                            break;
198                                        }
199                                    }
200                                    match lang {
201                                        Some(l) => l,
202                                        // No text found, continue to next block
203                                        None => continue,
204                                    }
205                                }
206                            };
207                            let mut te = &tex[lan];
208                            if te.is_null() {
209                                for l in tex.kv_keys() {
210                                    if l != "vo" && l != "name" {
211                                        te = &tex[l];
212                                        break;
213                                    }
214                                }
215                            }
216                            for item in te.members() {
217                                if let Some(select) = item.as_str() {
218                                    messages.push(Message {
219                                        name: None,
220                                        message: select.to_string(),
221                                    });
222                                }
223                            }
224                        }
225                    }
226                }
227            }
228            return Ok(messages);
229        }
230        let mut block_name = ast["label"]["top"]["block"]
231            .as_str()
232            .ok_or(anyhow::anyhow!("Missing top block name"))?;
233        let mut block = &ast[block_name];
234        loop {
235            let savetitle = &block[Key("savetitle")];
236            if savetitle.is_array() {
237                if let Some(lang) = lang {
238                    if let Some(title) = savetitle[lang].as_str() {
239                        messages.push(Message {
240                            name: None,
241                            message: title.to_string(),
242                        });
243                    } else if let Some(title) = savetitle["text"].as_str() {
244                        messages.push(Message {
245                            name: None,
246                            message: title.to_string(),
247                        });
248                    }
249                } else if let Some(title) = savetitle["text"].as_str() {
250                    messages.push(Message {
251                        name: None,
252                        message: title.to_string(),
253                    });
254                }
255            }
256            let text = &block["text"];
257            if text.is_array() {
258                let lan = match lang {
259                    Some(l) => l,
260                    None => {
261                        for l in text.kv_keys() {
262                            if l.is_str() && l != "vo" {
263                                lang = l.as_str();
264                                break;
265                            }
266                        }
267                        match lang {
268                            Some(l) => l,
269                            // No text found, continue to next block
270                            None => {
271                                block_name = match block["linknext"].as_str() {
272                                    Some(name) => name,
273                                    None => break,
274                                };
275                                block = &ast[block_name];
276                                continue;
277                            }
278                        }
279                    }
280                };
281                let mut tex = &text[lan];
282                if tex.is_null() {
283                    for l in text.kv_keys() {
284                        if l != "vo" {
285                            tex = &text[l];
286                            break;
287                        }
288                    }
289                }
290                for item in tex.members() {
291                    let name = item["name"].last_member().as_string();
292                    let message = text::TextGenerator::new().generate(item)?;
293                    messages.push(Message {
294                        name: name,
295                        message: message
296                            .replace("<rt2>", "\n")
297                            .replace("<ret2>", "\n")
298                            .trim_end_matches("\n")
299                            .to_string(),
300                    });
301                }
302            }
303            let select = &block["select"];
304            if select.is_array() {
305                let lan = match lang {
306                    Some(l) => l,
307                    None => {
308                        for l in select.kv_keys() {
309                            if l.is_str() && l != "vo" {
310                                lang = l.as_str();
311                                break;
312                            }
313                        }
314                        match lang {
315                            Some(l) => l,
316                            // No select text found, continue to next block
317                            None => {
318                                block_name = match block["linknext"].as_str() {
319                                    Some(name) => name,
320                                    None => break,
321                                };
322                                block = &ast[block_name];
323                                continue;
324                            }
325                        }
326                    }
327                };
328                let mut select_text = &select[lan];
329                if select_text.is_null() {
330                    for l in select.kv_keys() {
331                        if l != "vo" {
332                            select_text = &select[l];
333                            break;
334                        }
335                    }
336                }
337                for item in select_text.members() {
338                    if let Some(select) = item.as_str() {
339                        messages.push(Message {
340                            name: None,
341                            message: select.to_string(),
342                        });
343                    }
344                }
345            }
346            block_name = match block["linknext"].as_str() {
347                Some(name) => name,
348                None => break,
349            };
350            block = &ast[block_name];
351        }
352        Ok(messages)
353    }
354
355    fn import_messages<'a>(
356        &'a self,
357        messages: Vec<Message>,
358        mut file: Box<dyn WriteSeek + 'a>,
359        _filename: &str,
360        encoding: Encoding,
361        replacement: Option<&'a ReplacementTable>,
362    ) -> Result<()> {
363        let mut ast = self.ast.clone();
364        let root = &mut ast.ast;
365        let mut lang = self.lang.as_ref().map(|s| s.to_string());
366        let mut mess = messages.iter();
367        let mut mes = mess.next();
368        if root["label"]["top"]["block"].is_null() && root["text"].is_array() {
369            let mut text_index = 1i64;
370            let len = root.len();
371            for i in 0..len {
372                if root[i].is_array() {
373                    if root[i][Key("savetitle")].is_array() {
374                        let lan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("text");
375                        let m = match mes {
376                            Some(m) => m,
377                            None => return Err(anyhow::anyhow!("Not enough messages.")),
378                        };
379                        let mut title = m.message.clone();
380                        if let Some(repl) = replacement {
381                            for (k, v) in &repl.map {
382                                title = title.replace(k, v);
383                            }
384                        }
385                        root[i][Key("savetitle")][lan].set_string(title);
386                        mes = mess.next();
387                    }
388                }
389                if !root[i][Key("text")].is_null() {
390                    let lan = match &lang {
391                        Some(l) => l.as_str(),
392                        None => {
393                            for l in root["text"][NumKey(text_index)].kv_keys() {
394                                if l.is_str() && l != "vo" && l != "name" {
395                                    lang = l.as_string();
396                                    break;
397                                }
398                            }
399                            match lang {
400                                Some(ref l) => l.as_str(),
401                                // No text found, continue to next block
402                                None => continue,
403                            }
404                        }
405                    };
406                    if root["text"][NumKey(text_index)]["name"].is_array() {
407                        let name = match mes {
408                            Some(m) => m.name.clone(),
409                            None => return Err(anyhow::anyhow!("Message name is missing.")),
410                        };
411                        let mut name = match name {
412                            Some(n) => n,
413                            None => return Err(anyhow::anyhow!("Message name is missing.")),
414                        };
415                        if let Some(repl) = replacement {
416                            for (k, v) in &repl.map {
417                                name = name.replace(k, v);
418                            }
419                        }
420                        let nlan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("name");
421                        root["text"][NumKey(text_index)]["name"][nlan].set_string(name);
422                    }
423                    let origin_count = {
424                        let text = &root["text"][NumKey(text_index)];
425                        let mut tex = &text[lan];
426                        if tex.is_null() {
427                            for l in text.kv_keys() {
428                                if l != "vo" && l != "name" {
429                                    tex = &text[l];
430                                    break;
431                                }
432                            }
433                        }
434                        tex.len()
435                    };
436                    let mut arr = Value::new_array();
437                    for _ in 0..origin_count {
438                        let m = match mes {
439                            Some(m) => m,
440                            None => return Err(anyhow::anyhow!("Not enough messages.")),
441                        };
442                        let mut text = m.message.clone();
443                        if let Some(repl) = replacement {
444                            for (k, v) in &repl.map {
445                                text = text.replace(k, v);
446                            }
447                        }
448                        let v = text::TextParser::new(&text.replace("\n", "<rt2>")).parse()?;
449                        arr.push_member(v);
450                        mes = mess.next();
451                    }
452                    root["text"][NumKey(text_index)][lan] = arr;
453                    text_index += 1;
454                } else if !root[i][Key("select")].is_null() {
455                    let lan = match &lang {
456                        Some(l) => l.as_str(),
457                        None => {
458                            for l in root["text"][NumKey(text_index)]["select"].kv_keys() {
459                                if l.is_str() && l != "vo" && l != "name" {
460                                    lang = l.as_string();
461                                    break;
462                                }
463                            }
464                            match lang {
465                                Some(ref l) => l.as_str(),
466                                // No text found, continue to next block
467                                None => continue,
468                            }
469                        }
470                    };
471                    let count = {
472                        let text = &root["text"][NumKey(text_index)]["select"];
473                        let mut tex = &text[lan];
474                        if tex.is_null() {
475                            for l in text.kv_keys() {
476                                if l != "vo" && l != "name" {
477                                    tex = &text[l];
478                                    break;
479                                }
480                            }
481                        }
482                        tex.len()
483                    };
484                    let mut new_select = Value::new_array();
485                    for _ in 0..count {
486                        let m = match mes {
487                            Some(m) => m,
488                            None => return Err(anyhow::anyhow!("Not enough messages.")),
489                        };
490                        let mut select_text = m.message.clone();
491                        if let Some(repl) = replacement {
492                            for (k, v) in &repl.map {
493                                select_text = select_text.replace(k, v);
494                            }
495                        }
496                        new_select.push_member(Value::Str(select_text));
497                        mes = mess.next();
498                    }
499                    root["text"][NumKey(text_index)]["select"][lan] = new_select;
500                    text_index += 1;
501                }
502            }
503            if mes.is_some() || mess.next().is_some() {
504                return Err(anyhow::anyhow!("Not all messages were used."));
505            }
506            let mut writer = Vec::new();
507            let mut dumper = dump::Dumper::new(&mut writer);
508            if self.no_indent {
509                dumper.set_no_indent();
510            } else if let Some(indent) = self.indent {
511                dumper.set_indent(indent);
512            }
513            dumper.set_max_line_width(self.max_line_width);
514            dumper.dump(&ast)?;
515            let data = String::from_utf8(writer)?;
516            let encoded = encode_string(encoding, &data, false)?;
517            file.write_all(&encoded)?;
518            file.flush()?;
519            return Ok(());
520        }
521        let mut block_name = root["label"]["top"]["block"]
522            .as_string()
523            .ok_or(anyhow::anyhow!("Missing top block name"))?;
524        let mut block = &mut root[block_name];
525        loop {
526            if block[Key("savetitle")].is_array() {
527                let lan = self.lang.as_ref().map(|s| s.as_str()).unwrap_or("text");
528                let m = match mes {
529                    Some(m) => m,
530                    None => return Err(anyhow::anyhow!("Not enough messages.")),
531                };
532                let mut title = m.message.clone();
533                if let Some(repl) = replacement {
534                    for (k, v) in &repl.map {
535                        title = title.replace(k, v);
536                    }
537                }
538                block[Key("savetitle")][lan].set_string(title);
539                mes = mess.next();
540            }
541            if block["text"].is_array() {
542                let lan = match &lang {
543                    Some(l) => l.as_str(),
544                    None => {
545                        for l in block["text"].kv_keys() {
546                            if l.is_str() && l != "vo" {
547                                lang = l.as_string();
548                                break;
549                            }
550                        }
551                        match lang {
552                            Some(ref l) => l.as_str(),
553                            // No text found, continue to next block
554                            None => {
555                                block_name = match block["linknext"].as_string() {
556                                    Some(name) => name,
557                                    None => break,
558                                };
559                                block = &mut root[block_name];
560                                continue;
561                            }
562                        }
563                    }
564                };
565                let origin_names: Vec<_> = {
566                    let mut tex = &block["text"][lan];
567                    if tex.is_null() {
568                        for l in block["text"].kv_keys() {
569                            if l != "vo" {
570                                tex = &block["text"][l];
571                                break;
572                            }
573                        }
574                    }
575                    tex.members().map(|m| m["name"].clone()).collect()
576                };
577                let mut arr = Value::new_array();
578                for name in origin_names {
579                    let m = match mes {
580                        Some(m) => m,
581                        None => return Err(anyhow::anyhow!("Not enough messages.")),
582                    };
583                    let mut text = m.message.clone();
584                    if let Some(repl) = replacement {
585                        for (k, v) in &repl.map {
586                            text = text.replace(k, v);
587                        }
588                    }
589                    if !text.ends_with("\n") {
590                        text.push('\n');
591                    }
592                    let mut v = text::TextParser::new(&text.replace("\n", "<rt2>")).parse()?;
593                    if name.is_array() {
594                        let mut n = match &m.name {
595                            Some(n) => n.to_string(),
596                            None => return Err(anyhow::anyhow!("Message name is missing.")),
597                        };
598                        if let Some(repl) = replacement {
599                            for (k, v) in &repl.map {
600                                n = n.replace(k, v);
601                            }
602                        }
603                        v.insert_member(0, Value::new_kv("name", name));
604                        if v["name"].len() <= 1 {
605                            if v["name"][0] != n {
606                                v["name"].push_member(Value::Str(n));
607                            }
608                        } else {
609                            v["name"].last_member_mut().set_string(n);
610                        }
611                    }
612                    arr.push_member(v);
613                    mes = mess.next();
614                }
615                block["text"][lan] = arr;
616            }
617            if block["select"].is_array() {
618                let lan = match &lang {
619                    Some(l) => l.as_str(),
620                    None => {
621                        for l in block["select"].kv_keys() {
622                            if l.is_str() && l != "vo" {
623                                lang = l.as_string();
624                                break;
625                            }
626                        }
627                        match lang {
628                            Some(ref l) => l.as_str(),
629                            // No text found, continue to next block
630                            None => {
631                                block_name = match block["linknext"].as_string() {
632                                    Some(name) => name,
633                                    None => break,
634                                };
635                                block = &mut root[block_name];
636                                continue;
637                            }
638                        }
639                    }
640                };
641                let select_count = {
642                    let mut select = &block["select"][lan];
643                    if select.is_null() {
644                        for l in block["select"].kv_keys() {
645                            if l != "vo" {
646                                select = &block["select"][l];
647                                break;
648                            }
649                        }
650                    }
651                    select.len()
652                };
653                let mut new_select = Value::new_array();
654                for _ in 0..select_count {
655                    let m = match mes {
656                        Some(m) => m,
657                        None => return Err(anyhow::anyhow!("Not enough messages.")),
658                    };
659                    let mut select_text = m.message.clone();
660                    if let Some(repl) = replacement {
661                        for (k, v) in &repl.map {
662                            select_text = select_text.replace(k, v);
663                        }
664                    }
665                    new_select.push_member(Value::Str(select_text));
666                    mes = mess.next();
667                }
668                block["select"][lan] = new_select;
669            }
670            block_name = match block["linknext"].as_string() {
671                Some(name) => name,
672                None => break,
673            };
674            block = &mut root[block_name];
675        }
676        if mes.is_some() || mess.next().is_some() {
677            return Err(anyhow::anyhow!("Not all messages were used."));
678        }
679        let mut writer = Vec::new();
680        let mut dumper = dump::Dumper::new(&mut writer);
681        if self.no_indent {
682            dumper.set_no_indent();
683        } else if let Some(indent) = self.indent {
684            dumper.set_indent(indent);
685        }
686        dumper.set_max_line_width(self.max_line_width);
687        dumper.dump(&ast)?;
688        let data = String::from_utf8(writer)?;
689        let encoded = encode_string(encoding, &data, false)?;
690        file.write_all(&encoded)?;
691        file.flush()?;
692        Ok(())
693    }
694}
695
696/// Checks if the given buffer is in the Artemis AST format.
697///
698/// * `filename` - The name of the file.
699/// * `buf` - The buffer containing the data.
700/// * `buf_len` - The length of the buffer.
701pub fn is_this_format(_filename: &str, buf: &[u8], buf_len: usize) -> bool {
702    let parser = parser::Parser::new(&buf[..buf_len], Encoding::Utf8);
703    parser.try_parse_header().is_ok()
704}