msg_tool\scripts\kirikiri/
ks.rs

1//! Kirikiri Script File (.ks)
2use crate::ext::fancy_regex::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::escape::*;
7use anyhow::Result;
8use fancy_regex::Regex;
9use std::collections::BTreeSet;
10use std::collections::HashSet;
11use std::io::Write;
12use std::ops::{Deref, DerefMut, Index, IndexMut};
13use std::sync::Arc;
14
15#[derive(Debug)]
16/// Kirikiri Script Builder
17pub struct KsBuilder {}
18
19impl KsBuilder {
20    /// Creates a new instance of `KsBuilder`
21    pub fn new() -> Self {
22        Self {}
23    }
24}
25
26impl ScriptBuilder for KsBuilder {
27    fn default_encoding(&self) -> Encoding {
28        Encoding::Cp932
29    }
30
31    fn build_script(
32        &self,
33        buf: Vec<u8>,
34        _filename: &str,
35        encoding: Encoding,
36        _archive_encoding: Encoding,
37        config: &ExtraConfig,
38        _archive: Option<&Box<dyn Script>>,
39    ) -> Result<Box<dyn Script>> {
40        Ok(Box::new(KsScript::new(buf, encoding, config)?))
41    }
42
43    fn extensions(&self) -> &'static [&'static str] {
44        &["ks", "soc"]
45    }
46
47    fn script_type(&self) -> &'static ScriptType {
48        &ScriptType::Kirikiri
49    }
50}
51
52/// Kirikiri Script Node Trait
53pub trait Node {
54    /// Serializes the node to ks format
55    fn serialize(&self) -> String;
56}
57
58#[derive(Clone, Debug)]
59/// Comment Node
60pub struct CommentNode(pub String);
61
62impl Node for CommentNode {
63    fn serialize(&self) -> String {
64        format!("; {}", self.0)
65    }
66}
67
68#[derive(Clone, Debug)]
69/// Label Node
70pub struct LabelNode {
71    /// The name of the label
72    pub name: String,
73    /// The page of the label
74    pub page: Option<String>,
75}
76
77impl Node for LabelNode {
78    fn serialize(&self) -> String {
79        if let Some(page) = &self.page {
80            format!("*{}|{}", self.name, page)
81        } else {
82            format!("*{}", self.name)
83        }
84    }
85}
86
87#[derive(Clone, Debug)]
88/// Text Node
89pub struct TextNode(pub String);
90
91impl Node for TextNode {
92    fn serialize(&self) -> String {
93        // In KAG, [ is escaped as [[
94        self.0.replace("[", "[[")
95    }
96}
97
98#[derive(Clone, Debug)]
99/// Empty Line Node
100pub struct EmptyLineNode;
101
102impl Node for EmptyLineNode {
103    fn serialize(&self) -> String {
104        String::new()
105    }
106}
107
108#[derive(Clone, Debug)]
109/// Represents a tag attribute's value
110pub enum TagAttr {
111    /// true if no value is specified
112    True,
113    /// String value of the attribute
114    Str(String),
115}
116
117#[derive(Clone, Debug)]
118/// Tag Node
119pub struct TagNode {
120    /// The name of the tag
121    pub name: String,
122    /// The attributes of the tag
123    pub attributes: Vec<(String, TagAttr)>,
124}
125
126impl TagNode {
127    fn serialize_attributes(&self) -> String {
128        let mut parts = Vec::new();
129        for (key, value) in self.attributes.iter() {
130            match value {
131                TagAttr::True => {
132                    parts.push(key.clone());
133                }
134                TagAttr::Str(val) => {
135                    if val.contains(" ") || val.contains("=") {
136                        parts.push(format!("{}=\"{}\"", key, val));
137                    } else {
138                        parts.push(format!("{}={}", key, val));
139                    }
140                }
141            }
142        }
143        parts.join(" ")
144    }
145
146    fn ser_attributes_xml(&self) -> String {
147        let mut parts = Vec::new();
148        for (key, value) in self.attributes.iter() {
149            match value {
150                TagAttr::True => {
151                    parts.push(key.clone());
152                }
153                TagAttr::Str(val) => {
154                    parts.push(format!("{}=\"{}\"", key, escape_xml_attr_value(val)));
155                }
156            }
157        }
158        parts.join(" ")
159    }
160
161    /// Sets an attribute for the tag, replacing it if it already exists.
162    pub fn set_attr(&mut self, key: &str, value: String) {
163        if let Some(attr) = self.attributes.iter_mut().find(|(k, _)| k == key) {
164            attr.1 = TagAttr::Str(value);
165        } else {
166            self.attributes.push((key.to_string(), TagAttr::Str(value)));
167        }
168    }
169
170    /// Get an attribute for the tag
171    pub fn get_attr(&self, key: &str) -> Option<&TagAttr> {
172        self.attributes
173            .iter()
174            .find(|(k, _)| k == key)
175            .map(|(_, v)| v)
176    }
177
178    fn to_xml_tag(&self) -> String {
179        let attr_str = self.ser_attributes_xml();
180        if attr_str.is_empty() {
181            format!("<{}>", self.name)
182        } else {
183            format!("<{} {}>", self.name, attr_str)
184        }
185    }
186}
187
188impl Node for TagNode {
189    fn serialize(&self) -> String {
190        let attr_str = self.serialize_attributes();
191        if attr_str.is_empty() {
192            format!("[{}]", self.name)
193        } else {
194            format!("[{} {}]", self.name, attr_str)
195        }
196    }
197}
198
199#[derive(Clone)]
200/// Command Node
201pub struct CommandNode {
202    /// Same as TagNode, but used for commands
203    pub inner: TagNode,
204}
205
206impl Deref for CommandNode {
207    type Target = TagNode;
208
209    fn deref(&self) -> &Self::Target {
210        &self.inner
211    }
212}
213
214impl DerefMut for CommandNode {
215    fn deref_mut(&mut self) -> &mut Self::Target {
216        &mut self.inner
217    }
218}
219
220impl std::fmt::Debug for CommandNode {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        f.debug_struct("CommandNode")
223            .field("name", &self.inner.name)
224            .field("attributes", &self.inner.attributes)
225            .finish()
226    }
227}
228
229impl Node for CommandNode {
230    fn serialize(&self) -> String {
231        let attr_str = self.inner.serialize_attributes();
232        if attr_str.is_empty() {
233            format!("@{}", self.inner.name)
234        } else {
235            format!("@{} {}", self.inner.name, attr_str)
236        }
237    }
238}
239
240#[derive(Clone, Debug)]
241/// Script Block Node
242pub struct ScriptBlockNode(pub String);
243
244impl Node for ScriptBlockNode {
245    fn serialize(&self) -> String {
246        format!("[iscript]\n{}\n[endscript]", self.0)
247    }
248}
249
250#[derive(Clone, Debug)]
251/// Parsed Line Node
252pub enum ParsedLineNode {
253    /// Text node containing plain text
254    Text(TextNode),
255    /// Tag node
256    Tag(TagNode),
257}
258
259impl ParsedLineNode {
260    fn to_xml(&self) -> String {
261        match self {
262            ParsedLineNode::Text(text_node) => escape_xml_text_value(&text_node.0),
263            ParsedLineNode::Tag(tag_node) => {
264                if tag_node.name == "r" && tag_node.attributes.is_empty() {
265                    "\n".to_string()
266                } else {
267                    tag_node.to_xml_tag()
268                }
269            }
270        }
271    }
272
273    fn is_np(&self) -> bool {
274        matches!(self, ParsedLineNode::Tag(tag) if tag.name == "np")
275    }
276
277    fn is_tag(&self, name: &str) -> bool {
278        matches!(self, ParsedLineNode::Tag(tag) if tag.name == name)
279    }
280
281    fn set_attr(&mut self, key: &str, value: String) {
282        if let ParsedLineNode::Tag(tag) = self {
283            tag.set_attr(key, value);
284        }
285    }
286}
287
288impl Node for ParsedLineNode {
289    fn serialize(&self) -> String {
290        match self {
291            ParsedLineNode::Text(text_node) => text_node.serialize(),
292            ParsedLineNode::Tag(tag_node) => tag_node.serialize(),
293        }
294    }
295}
296
297#[derive(Clone, Debug)]
298/// Parsed Line
299pub struct ParsedLine(pub Vec<ParsedLineNode>);
300
301impl ParsedLine {
302    fn to_xml(&self) -> String {
303        let mut s = String::new();
304        for node in &self.0 {
305            s.push_str(&node.to_xml());
306        }
307        s
308    }
309}
310
311impl Deref for ParsedLine {
312    type Target = Vec<ParsedLineNode>;
313
314    fn deref(&self) -> &Self::Target {
315        &self.0
316    }
317}
318
319impl DerefMut for ParsedLine {
320    fn deref_mut(&mut self) -> &mut Self::Target {
321        &mut self.0
322    }
323}
324
325impl Node for ParsedLine {
326    fn serialize(&self) -> String {
327        self.0
328            .iter()
329            .map(|node| node.serialize())
330            .collect::<Vec<_>>()
331            .join("")
332    }
333}
334
335#[derive(Clone, Debug)]
336/// Parsed Script Node
337pub enum ParsedScriptNode {
338    /// Comment node
339    Comment(CommentNode),
340    /// Label node
341    Label(LabelNode),
342    /// Command node
343    Command(CommandNode),
344    /// Script block node
345    ScriptBlock(ScriptBlockNode),
346    /// Line
347    Line(ParsedLine),
348    /// Empty line node
349    EmptyLine(EmptyLineNode),
350}
351
352impl ParsedScriptNode {
353    /// Returns true if the node is empty line node
354    pub fn is_empty(&self) -> bool {
355        matches!(self, ParsedScriptNode::EmptyLine(_))
356    }
357
358    /// Sets an attribute for the command node, replacing it if it already exists.
359    pub fn set_attr(&mut self, key: &str, value: String) {
360        if let ParsedScriptNode::Command(command) = self {
361            command.set_attr(key, value);
362        }
363    }
364}
365
366impl Node for ParsedScriptNode {
367    fn serialize(&self) -> String {
368        match self {
369            ParsedScriptNode::Comment(comment) => comment.serialize(),
370            ParsedScriptNode::Label(label) => label.serialize(),
371            ParsedScriptNode::Command(command) => command.serialize(),
372            ParsedScriptNode::ScriptBlock(script_block) => script_block.serialize(),
373            ParsedScriptNode::Line(line) => line.serialize(),
374            ParsedScriptNode::EmptyLine(empty_line) => empty_line.serialize(),
375        }
376    }
377}
378
379#[derive(Clone, Debug)]
380/// Parsed ks script
381pub struct ParsedScript(pub Vec<ParsedScriptNode>);
382
383impl Deref for ParsedScript {
384    type Target = Vec<ParsedScriptNode>;
385
386    fn deref(&self) -> &Self::Target {
387        &self.0
388    }
389}
390
391impl DerefMut for ParsedScript {
392    fn deref_mut(&mut self) -> &mut Self::Target {
393        &mut self.0
394    }
395}
396
397impl Index<usize> for ParsedScript {
398    type Output = ParsedScriptNode;
399
400    fn index(&self, index: usize) -> &Self::Output {
401        &self.0[index]
402    }
403}
404
405impl IndexMut<usize> for ParsedScript {
406    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
407        if index < self.0.len() {
408            &mut self.0[index]
409        } else {
410            self.0.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
411            self.0.last_mut().unwrap()
412        }
413    }
414}
415
416impl Node for ParsedScript {
417    fn serialize(&self) -> String {
418        self.0
419            .iter()
420            .map(|node| node.serialize())
421            .collect::<Vec<_>>()
422            .join("\n")
423    }
424}
425
426lazy_static::lazy_static! {
427    static ref LINE_SPLIT_RE: Regex = Regex::new(r"(\[.*?\])").unwrap();
428    static ref ATTR_RE: Regex = Regex::new("([a-zA-Z0-9_]+)(?:=(\"[^\"]*\"|'[^']*'|[^\\s\\]]+))?").unwrap();
429}
430
431/// Parser for Kirikiri Script (.ks)
432pub struct Parser {
433    lines: Vec<String>,
434}
435
436impl Parser {
437    /// Creates a new parser for the given script
438    ///
439    /// * `script` - The script to parse
440    pub fn new(script: &str) -> Self {
441        let lines = script.lines().map(|s| s.to_string()).collect();
442        Self { lines }
443    }
444
445    fn parse_attributes(attr_str: &str) -> Result<Vec<(String, TagAttr)>> {
446        let mut attributes = Vec::new();
447        for cap in ATTR_RE.captures_iter(attr_str) {
448            let cap = cap?;
449            let key = cap
450                .get(1)
451                .ok_or(anyhow::anyhow!("Invalid attribute key"))?
452                .as_str()
453                .to_string();
454            let value = cap
455                .get(2)
456                .map(|v| {
457                    let mut s = v.as_str().trim().to_string();
458                    if s.starts_with("\"") && s.ends_with("\"") {
459                        s = s[1..s.len() - 1].to_string();
460                    } else if s.starts_with("'") && s.ends_with("'") {
461                        s = s[1..s.len() - 1].to_string();
462                    }
463                    s = s.replace("`", "");
464                    TagAttr::Str(s)
465                })
466                .unwrap_or(TagAttr::True);
467            attributes.push((key, value));
468        }
469        Ok(attributes)
470    }
471
472    fn parse_tag_or_command(content: &str) -> Result<TagNode> {
473        let parts = content.trim().split_ascii_whitespace().collect::<Vec<_>>();
474        let tag_name = parts[0].to_string();
475        let attr_string = parts[1..].join(" ");
476        let attrs = Self::parse_attributes(&attr_string)?;
477        Ok(TagNode {
478            name: tag_name,
479            attributes: attrs,
480        })
481    }
482
483    /// Parses the script and returns a `ParsedScript`
484    ///
485    /// * `preserve_empty_lines` - If true, empty lines will be preserved in the parsed script
486    pub fn parse(&self, preserve_empty_lines: bool) -> Result<ParsedScript> {
487        let mut parsed_scripts = Vec::new();
488        let mut in_script_block = false;
489        let mut script_buffer = Vec::new();
490        let mut i = 0;
491        let line_count = self.lines.len();
492        while i < line_count {
493            let line = self.lines[i].trim();
494            i += 1;
495            if line.is_empty() {
496                if preserve_empty_lines {
497                    parsed_scripts.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
498                } else {
499                    continue;
500                }
501            }
502            if in_script_block {
503                if line == "[endscript]" {
504                    in_script_block = false;
505                    parsed_scripts.push(ParsedScriptNode::ScriptBlock(ScriptBlockNode(
506                        script_buffer.join("\n"),
507                    )));
508                    script_buffer.clear();
509                } else {
510                    script_buffer.push(line.to_string());
511                }
512                continue;
513            }
514            if line == "[iscript]" {
515                in_script_block = true;
516                continue;
517            }
518            if line.starts_with(";") {
519                parsed_scripts.push(ParsedScriptNode::Comment(CommentNode(
520                    line[1..].trim().to_string(),
521                )));
522                continue;
523            }
524            if line.starts_with("*") {
525                let parts: Vec<&str> = line.split('|').collect();
526                let label_name = parts[0][1..].trim().to_string();
527                let page = if parts.len() > 1 {
528                    Some(parts[1..].join("|"))
529                } else {
530                    None
531                };
532                parsed_scripts.push(ParsedScriptNode::Label(LabelNode {
533                    name: label_name,
534                    page,
535                }));
536                continue;
537            }
538            if line.starts_with("@") {
539                let content = &line[1..];
540                let tag_node = Self::parse_tag_or_command(content)?;
541                parsed_scripts.push(ParsedScriptNode::Command(CommandNode { inner: tag_node }));
542                continue;
543            }
544            let mut full_line = line.to_string();
545            while full_line.ends_with("\\") {
546                full_line.pop(); // Remove the trailing backslash
547                full_line = full_line.trim_end().to_string();
548                if i < line_count {
549                    full_line.push(' ');
550                    full_line.push_str(&self.lines[i].trim());
551                    i += 1;
552                } else {
553                    break; // No more lines to append
554                }
555            }
556            let mut parsed_line_nodes = Vec::new();
557            for part in LINE_SPLIT_RE.py_split(&full_line)? {
558                let part = part.trim();
559                if part.is_empty() {
560                    continue;
561                }
562                if part.starts_with("[") && part.ends_with("]") {
563                    if part == "[[r]]" {
564                        parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[r]".to_string())));
565                    } else if part == "[[[[" {
566                        parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[[".to_string())));
567                    } else if part.starts_with("[[") {
568                        parsed_line_nodes
569                            .push(ParsedLineNode::Text(TextNode(part[1..].to_string())))
570                    } else {
571                        parsed_line_nodes.push(ParsedLineNode::Tag(Self::parse_tag_or_command(
572                            &part[1..part.len() - 1],
573                        )?));
574                    }
575                } else {
576                    parsed_line_nodes.push(ParsedLineNode::Text(TextNode(part.to_string())));
577                }
578            }
579            if !parsed_line_nodes.is_empty() {
580                parsed_scripts.push(ParsedScriptNode::Line(ParsedLine(parsed_line_nodes)));
581            }
582        }
583        Ok(ParsedScript(parsed_scripts))
584    }
585}
586
587struct XMLTextParser {
588    str: String,
589    pos: usize,
590    lf: String,
591    no_np: bool,
592}
593
594impl XMLTextParser {
595    pub fn new(text: &str, lf: Option<String>) -> Self {
596        let lf = lf.unwrap_or_else(|| String::from("<r>"));
597        Self {
598            str: text.replace("\n", &lf),
599            pos: 0,
600            lf,
601            no_np: false,
602        }
603    }
604
605    fn no_np(mut self) -> Self {
606        self.no_np = true;
607        self
608    }
609
610    fn parse_tag(&mut self) -> Result<TagNode> {
611        let mut name = String::new();
612        let mut attributes = Vec::new();
613        let mut is_name = true;
614        let mut is_key = false;
615        let mut is_value = false;
616        let mut is_in_quote = false;
617        let mut key = String::new();
618        let mut value = String::new();
619        while let Some(c) = self.next() {
620            match c {
621                '>' => {
622                    if !name.is_empty() {
623                        return Ok(TagNode { name, attributes });
624                    } else {
625                        return Err(anyhow::anyhow!("Empty tag name"));
626                    }
627                }
628                ' ' | '\t' => {
629                    if is_name {
630                        is_name = false;
631                        is_key = true;
632                    } else if is_key {
633                        if !key.is_empty() {
634                            attributes.push((key.clone(), TagAttr::True));
635                            key.clear();
636                        }
637                    } else if is_value {
638                        if is_in_quote {
639                            value.push(c);
640                        } else {
641                            if !value.is_empty() {
642                                attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
643                                key.clear();
644                                value.clear();
645                            }
646                            is_key = true;
647                            is_value = false;
648                        }
649                    }
650                }
651                '"' => {
652                    if is_in_quote {
653                        is_in_quote = false;
654                        if !value.is_empty() {
655                            attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
656                            key.clear();
657                            value.clear();
658                        }
659                        is_key = true;
660                    } else {
661                        is_in_quote = true;
662                    }
663                }
664                '=' => {
665                    if is_key {
666                        is_key = false;
667                        is_value = true;
668                    }
669                }
670                _ => {
671                    if is_name {
672                        name.push(c);
673                    } else if is_key {
674                        key.push(c);
675                    } else if is_value {
676                        value.push(c);
677                    } else {
678                        return Err(anyhow::anyhow!("Unexpected character in tag: {}", c));
679                    }
680                }
681            }
682        }
683        Err(anyhow::anyhow!("Unexpected end of input while parsing tag"))
684    }
685
686    pub fn parse(mut self) -> Result<Vec<ParsedLine>> {
687        let mut lines = Vec::new();
688        let mut current_line = Vec::new();
689        let mut text = String::new();
690        while let Some(c) = self.next() {
691            match c {
692                '<' => {
693                    if !text.is_empty() {
694                        current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
695                        text.clear();
696                    }
697                    let tag = self.parse_tag()?;
698                    let is_r = tag.name == "r";
699                    current_line.push(ParsedLineNode::Tag(tag));
700                    if is_r {
701                        lines.push(ParsedLine(current_line));
702                        current_line = Vec::new();
703                    }
704                }
705                _ => {
706                    text.push(c);
707                    if text.ends_with(&self.lf) {
708                        if !text.is_empty() {
709                            current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
710                            text.clear();
711                        }
712                        lines.push(ParsedLine(current_line));
713                        current_line = Vec::new();
714                    }
715                }
716            }
717        }
718        if !text.is_empty() {
719            current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
720        }
721        if !self.no_np {
722            current_line.push(ParsedLineNode::Tag(TagNode {
723                name: "np".to_string(),
724                attributes: Vec::new(),
725            }));
726        }
727        lines.push(ParsedLine(current_line));
728        Ok(lines)
729    }
730
731    fn next(&mut self) -> Option<char> {
732        if self.pos < self.str.len() {
733            let c = self.str[self.pos..].chars().next()?;
734            self.pos += c.len_utf8();
735            Some(c)
736        } else {
737            None
738        }
739    }
740}
741
742#[derive(Debug)]
743/// Kirikiri Script
744pub struct KsScript {
745    bom: BomType,
746    tree: ParsedScript,
747    name_commands: Arc<HashSet<String>>,
748    message_commands: Arc<HashSet<String>>,
749    remove_empty_lines: bool,
750    hitret: bool,
751    lf: Option<String>,
752    message_tags: Arc<HashSet<String>>,
753}
754
755impl KsScript {
756    /// Creates a new `KsScript` from the given reader and encoding
757    ///
758    /// * `reader` - The reader containing the script data
759    /// * `encoding` - The encoding of the script
760    /// * `config` - Extra configuration options
761    pub fn new(reader: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
762        let (text, bom) = decode_with_bom_detect(encoding, &reader, true)?;
763        let parser = Parser::new(&text);
764        let tree = parser.parse(!config.kirikiri_remove_empty_lines)?;
765        let hitret = if let Some(hitret) = config.kirikiri_ks_hitret {
766            hitret
767        } else {
768            let mut talk_count = 0u64;
769            let mut hitret_count = 0u64;
770            for node in tree.iter() {
771                match node {
772                    ParsedScriptNode::Line(line) => {
773                        for node in line.iter() {
774                            if let ParsedLineNode::Tag(node) = node {
775                                if node.name == "Talk" {
776                                    talk_count += 1;
777                                } else if node.name == "Hitret" {
778                                    hitret_count += 1;
779                                }
780                            }
781                        }
782                    }
783                    _ => {}
784                }
785            }
786            talk_count == hitret_count && talk_count > 3
787        };
788        Ok(Self {
789            bom: config.kirikiri_ks_bom.unwrap_or(bom),
790            tree,
791            name_commands: config.kirikiri_name_commands.clone(),
792            message_commands: config.kirikiri_message_commands.clone(),
793            remove_empty_lines: config.kirikiri_remove_empty_lines,
794            hitret,
795            lf: config.kirikiri_ks_lf.clone(),
796            message_tags: config.kirikiri_message_tags.clone(),
797        })
798    }
799}
800
801impl Script for KsScript {
802    fn default_output_script_type(&self) -> OutputScriptType {
803        OutputScriptType::Json
804    }
805
806    fn default_format_type(&self) -> FormatOptions {
807        FormatOptions::None
808    }
809
810    fn extract_messages(&self) -> Result<Vec<Message>> {
811        let mut messages = Vec::new();
812        let mut name = None;
813        let mut message = String::new();
814        if self.hitret {
815            for obj in self.tree.iter() {
816                match obj {
817                    ParsedScriptNode::Line(line) => {
818                        for node in line.iter() {
819                            if node.is_tag("Talk") {
820                                if let ParsedLineNode::Tag(tag) = &node {
821                                    if let Some(attr) = tag.get_attr("name") {
822                                        if let TagAttr::Str(s) = attr {
823                                            name = Some(s.to_string());
824                                        }
825                                    }
826                                    if name.is_none() {
827                                        for attr in &tag.attributes {
828                                            if let TagAttr::Str(value) = &attr.1 {
829                                                if !value.is_empty() && !value.is_ascii() {
830                                                    name = Some(value.clone());
831                                                    break;
832                                                }
833                                            }
834                                        }
835                                    }
836                                    if name.is_none() {
837                                        anyhow::bail!("name not found for Talk command");
838                                    }
839                                    continue;
840                                }
841                            } else if node.is_tag("Hitret") {
842                                if let Some(lf) = self.lf.as_ref() {
843                                    message = message.replace(lf, "\n");
844                                }
845                                messages.push(Message {
846                                    name: if name.as_ref().is_some_and(|name| name == "心の声") {
847                                        None
848                                    } else {
849                                        name.clone()
850                                    },
851                                    message: message.trim_end_matches("<np>").to_owned(),
852                                });
853                                message.clear();
854                                name = None;
855                                continue;
856                            } else if let ParsedLineNode::Tag(tag) = &node {
857                                if self.message_tags.contains(&tag.name) {
858                                    for attr in &tag.attributes {
859                                        if let TagAttr::Str(value) = &attr.1 {
860                                            if !value.is_empty() && !value.is_ascii() {
861                                                messages.push(Message {
862                                                    name: None,
863                                                    message: value.clone(),
864                                                });
865                                                break;
866                                            }
867                                        }
868                                    }
869                                }
870                            }
871                            if name.is_some() {
872                                message.push_str(&node.to_xml());
873                            }
874                        }
875                    }
876                    _ => {}
877                }
878            }
879            return Ok(messages);
880        }
881        for obj in self.tree.iter() {
882            match obj {
883                ParsedScriptNode::Label(_) => {
884                    if !message.is_empty() {
885                        if let Some(lf) = self.lf.as_ref() {
886                            message = message.replace(lf, "\n");
887                        }
888                        messages.push(Message {
889                            name: name.clone(),
890                            message: message.trim_end_matches("<np>").to_owned(),
891                        });
892                        message.clear();
893                        name = None;
894                    }
895                }
896                ParsedScriptNode::Line(line) => {
897                    if !message.ends_with("<np>") {
898                        message.push_str(&line.to_xml())
899                    }
900                }
901                ParsedScriptNode::Command(cmd) => {
902                    if self.name_commands.contains(&cmd.name) {
903                        for attr in &cmd.attributes {
904                            if let TagAttr::Str(value) = &attr.1 {
905                                if !value.is_empty() && !value.is_ascii() {
906                                    name = Some(value.clone());
907                                    break; // Only take the first name found
908                                }
909                            }
910                        }
911                    } else if self.message_commands.contains(&cmd.name) {
912                        for attr in &cmd.attributes {
913                            if let TagAttr::Str(value) = &attr.1 {
914                                if !value.is_empty() && !value.is_ascii() {
915                                    messages.push(Message {
916                                        name: None,
917                                        message: value.clone(),
918                                    });
919                                    break; // Only take the first message found
920                                }
921                            }
922                        }
923                    }
924                }
925                _ => {}
926            }
927        }
928        if !message.is_empty() {
929            if let Some(lf) = self.lf.as_ref() {
930                message = message.replace(lf, "\n");
931            }
932            messages.push(Message {
933                name,
934                message: message.trim_end_matches("<np>").to_owned(),
935            });
936        }
937        Ok(messages)
938    }
939
940    fn import_messages<'a>(
941        &'a self,
942        messages: Vec<Message>,
943        mut file: Box<dyn WriteSeek + 'a>,
944        _filename: &str,
945        encoding: Encoding,
946        replacement: Option<&'a ReplacementTable>,
947    ) -> Result<()> {
948        let mut mes = messages.iter();
949        let mut cur_mes = None;
950        let mut tree = self.tree.clone();
951        let mut i = 0;
952        if self.hitret {
953            let mut name_tag_loc = None;
954            let mut message_blocks = Vec::new();
955            let mut in_block = false;
956            cur_mes = mes.next();
957            while i < tree.len() {
958                match tree[i].clone() {
959                    ParsedScriptNode::Line(line) => {
960                        let mut j = 0;
961                        while j < line.len() {
962                            let node = line[j].clone();
963                            if node.is_tag("Talk") {
964                                if let ParsedLineNode::Tag(tag) = &node {
965                                    if let Some(attr) = tag.get_attr("name") {
966                                        if let TagAttr::Str(_) = attr {
967                                            name_tag_loc = Some((i, j, "name".to_string()));
968                                        }
969                                    }
970                                    if name_tag_loc.is_none() {
971                                        for attr in &tag.attributes {
972                                            if let TagAttr::Str(value) = &attr.1 {
973                                                if !value.is_empty() && !value.is_ascii() {
974                                                    name_tag_loc = Some((i, j, attr.0.clone()));
975                                                    break;
976                                                }
977                                            }
978                                        }
979                                    }
980                                }
981                                in_block = true;
982                                j += 1;
983                                continue;
984                            } else if node.is_tag("Hitret") {
985                                in_block = false;
986                                let m = cur_mes
987                                    .take()
988                                    .ok_or(anyhow::anyhow!("Not enough messages"))?;
989                                let (x, y, key) = name_tag_loc.take().ok_or(anyhow::anyhow!(
990                                    "Name tag not found for Talk command"
991                                ))?;
992                                let mut name =
993                                    m.name.clone().unwrap_or_else(|| "心の声".to_string());
994                                if let Some(replacement) = replacement {
995                                    for (key, value) in replacement.map.iter() {
996                                        name = name.replace(key, value);
997                                    }
998                                }
999                                let mut li = &mut tree[x];
1000                                if let ParsedScriptNode::Line(line) = &mut li {
1001                                    line[y].set_attr(&key, name);
1002                                }
1003                                let mut text = m.message.clone();
1004                                if let Some(replacement) = replacement {
1005                                    for (key, value) in replacement.map.iter() {
1006                                        text = text.replace(key, value);
1007                                    }
1008                                }
1009                                cur_mes = mes.next();
1010                                let mut mess =
1011                                    XMLTextParser::new(&text, self.lf.clone()).no_np().parse()?;
1012                                let first_line_len = mess[0].len();
1013                                let line_indexs =
1014                                    BTreeSet::from_iter(message_blocks.iter().map(|(i, _)| *i));
1015                                let (start_x, start_y) =
1016                                    message_blocks.first().cloned().unwrap_or((i, j));
1017                                let (end_x, end_y) =
1018                                    message_blocks.last().cloned().unwrap_or((x, y));
1019                                {
1020                                    let li = &mut mess[0];
1021                                    let source_line = &tree[start_x];
1022                                    let source_line = match source_line {
1023                                        ParsedScriptNode::Line(line) => line,
1024                                        _ => return Err(anyhow::anyhow!("Expected line node")),
1025                                    };
1026                                    for z in 0..start_y {
1027                                        li.insert(z, source_line[z].clone());
1028                                    }
1029                                }
1030                                {
1031                                    let loc = mess.len() - 1;
1032                                    let li = &mut mess[loc];
1033                                    let source_line = &tree[end_x];
1034                                    let source_line = match source_line {
1035                                        ParsedScriptNode::Line(line) => line,
1036                                        _ => return Err(anyhow::anyhow!("Expected line node")),
1037                                    };
1038                                    for z in end_y + 1..source_line.len() {
1039                                        li.push(source_line[z].clone());
1040                                    }
1041                                }
1042                                let diff = mess.len() as isize - line_indexs.len() as isize;
1043                                let common_lines = line_indexs.len().min(mess.len());
1044                                let mut last_index = end_x;
1045                                let message_lines = Vec::from_iter(line_indexs.iter().cloned());
1046                                for z in 0..common_lines {
1047                                    tree[message_lines[z]] =
1048                                        ParsedScriptNode::Line(mess[z].clone());
1049                                }
1050                                for z in common_lines..message_lines.len() {
1051                                    tree.remove(message_lines[z] - (z - common_lines));
1052                                }
1053                                for z in common_lines..mess.len() {
1054                                    let new_line = ParsedScriptNode::Line(mess[z].clone());
1055                                    if last_index < tree.len() {
1056                                        tree.insert(last_index + 1, new_line);
1057                                        last_index += 1;
1058                                    } else {
1059                                        tree.push(new_line);
1060                                    }
1061                                }
1062                                i = (i as isize + diff) as usize;
1063                                j = start_y + first_line_len + 2;
1064                                message_blocks.clear();
1065                                continue;
1066                            } else if let ParsedLineNode::Tag(tag) = &node {
1067                                if self.message_tags.contains(&tag.name) {
1068                                    for attr in &tag.attributes {
1069                                        if let TagAttr::Str(value) = &attr.1 {
1070                                            if !value.is_empty() && !value.is_ascii() {
1071                                                let m = cur_mes.take().ok_or(anyhow::anyhow!(
1072                                                    "No enough messages."
1073                                                ))?;
1074                                                cur_mes = mes.next();
1075                                                let mut text = m.message.clone();
1076                                                if let Some(replacement) = replacement {
1077                                                    for (key, value) in replacement.map.iter() {
1078                                                        text = text.replace(key, value);
1079                                                    }
1080                                                }
1081                                                let li = &mut tree[i];
1082                                                if let ParsedScriptNode::Line(line) = li {
1083                                                    line[j].set_attr(&attr.0, text);
1084                                                }
1085                                                j += 1;
1086                                                continue;
1087                                            }
1088                                        }
1089                                    }
1090                                }
1091                            }
1092                            if in_block {
1093                                message_blocks.push((i, j));
1094                            }
1095                            j += 1;
1096                        }
1097                    }
1098                    _ => {}
1099                }
1100                i += 1;
1101            }
1102        } else {
1103            let mut is_end = false;
1104            let mut name_command_block_line: Option<(usize, String)> = None;
1105            let mut message_lines = Vec::new();
1106            while i < tree.len() {
1107                match tree[i].clone() {
1108                    ParsedScriptNode::Label(_) => {
1109                        if !message_lines.is_empty() {
1110                            let m: &Message = cur_mes
1111                                .take()
1112                                .ok_or(anyhow::anyhow!("Not enough messages"))?;
1113                            if let Some((line, key)) = name_command_block_line.take() {
1114                                let name = m
1115                                    .name
1116                                    .as_ref()
1117                                    .ok_or(anyhow::anyhow!("Name not found in message"))?;
1118                                let mut name = name.clone();
1119                                if let Some(replacement) = replacement {
1120                                    for (key, value) in replacement.map.iter() {
1121                                        name = name.replace(key, value);
1122                                    }
1123                                }
1124                                tree[line].set_attr(&key, name);
1125                            }
1126                            let mut text = m.message.to_owned();
1127                            if let Some(replacement) = replacement {
1128                                for (key, value) in replacement.map.iter() {
1129                                    text = text.replace(key, value);
1130                                }
1131                            }
1132                            let mess = XMLTextParser::new(&text, self.lf.clone()).parse()?;
1133                            let diff = mess.len() as isize - message_lines.len() as isize;
1134                            let common_lines = message_lines.len().min(mess.len());
1135                            let mut last_index = message_lines.last().cloned().unwrap_or(0);
1136                            for j in 0..common_lines {
1137                                tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
1138                            }
1139                            for j in common_lines..message_lines.len() {
1140                                tree.remove(message_lines[j] - (j - common_lines));
1141                            }
1142                            for i in common_lines..mess.len() {
1143                                let new_line = ParsedScriptNode::Line(mess[i].clone());
1144                                if last_index < tree.len() {
1145                                    tree.insert(last_index + 1, new_line);
1146                                    last_index += 1;
1147                                } else {
1148                                    tree.push(new_line);
1149                                }
1150                            }
1151                            i = (i as isize + diff) as usize;
1152                        }
1153                        message_lines.clear();
1154                        is_end = false;
1155                        if cur_mes.is_none() {
1156                            cur_mes = mes.next();
1157                        }
1158                    }
1159                    ParsedScriptNode::Line(line) => {
1160                        if !is_end {
1161                            message_lines.push(i);
1162                            is_end = line.last().map(|e| e.is_np()).unwrap_or(false);
1163                        }
1164                    }
1165                    ParsedScriptNode::Command(cmd) => {
1166                        if self.name_commands.contains(&cmd.name) {
1167                            for attr in &cmd.attributes {
1168                                if let TagAttr::Str(value) = &attr.1 {
1169                                    if !value.is_empty() && !value.is_ascii() {
1170                                        name_command_block_line = Some((i, attr.0.clone()));
1171                                        break; // Only update the first name found
1172                                    }
1173                                }
1174                            }
1175                        } else if self.message_commands.contains(&cmd.name) {
1176                            for attr in &cmd.attributes {
1177                                if let TagAttr::Str(value) = &attr.1 {
1178                                    if !value.is_empty() && !value.is_ascii() {
1179                                        let m = cur_mes
1180                                            .take()
1181                                            .ok_or(anyhow::anyhow!("Not enough messages"))?;
1182                                        let mut text = m.message.clone();
1183                                        if let Some(replacement) = replacement {
1184                                            for (key, value) in replacement.map.iter() {
1185                                                text = text.replace(key, value);
1186                                            }
1187                                        }
1188                                        tree[i].set_attr(&attr.0, text);
1189                                        cur_mes = mes.next();
1190                                        break; // Only update the first message found
1191                                    }
1192                                }
1193                            }
1194                        }
1195                    }
1196                    _ => {}
1197                }
1198                i += 1;
1199            }
1200            if !message_lines.is_empty() {
1201                let m: &Message = cur_mes
1202                    .take()
1203                    .ok_or(anyhow::anyhow!("Not enough messages"))?;
1204                if let Some((line, key)) = name_command_block_line.take() {
1205                    let name = m
1206                        .name
1207                        .as_ref()
1208                        .ok_or(anyhow::anyhow!("Name not found in message"))?;
1209                    let mut name = name.clone();
1210                    if let Some(replacement) = replacement {
1211                        for (key, value) in replacement.map.iter() {
1212                            name = name.replace(key, value);
1213                        }
1214                    }
1215                    tree[line].set_attr(&key, name);
1216                }
1217                let mut text = m.message.to_owned();
1218                if let Some(replacement) = replacement {
1219                    for (key, value) in replacement.map.iter() {
1220                        text = text.replace(key, value);
1221                    }
1222                }
1223                let mess = XMLTextParser::new(&text, self.lf.clone()).parse()?;
1224                let common_lines = message_lines.len().min(mess.len());
1225                let mut last_index = message_lines.last().cloned().unwrap_or(0);
1226                for j in 0..common_lines {
1227                    tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
1228                }
1229                for j in common_lines..message_lines.len() {
1230                    tree.remove(message_lines[j] - (j - common_lines));
1231                }
1232                for i in common_lines..mess.len() {
1233                    let new_line = ParsedScriptNode::Line(mess[i].clone());
1234                    if last_index < tree.len() {
1235                        tree.insert(last_index + 1, new_line);
1236                        last_index += 1;
1237                    } else {
1238                        tree.push(new_line);
1239                    }
1240                }
1241            }
1242        }
1243        if cur_mes.is_some() || mes.next().is_some() {
1244            return Err(anyhow::anyhow!("Some messages were not processed."));
1245        }
1246        if self.remove_empty_lines {
1247            tree.retain(|node| !node.is_empty());
1248        }
1249        let s = tree.serialize() + "\n";
1250        let data = encode_string_with_bom(encoding, &s, false, self.bom)?;
1251        file.write_all(&data)?;
1252        Ok(())
1253    }
1254}