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::HashSet;
10use std::io::Write;
11use std::ops::{Deref, DerefMut, Index, IndexMut};
12use std::sync::Arc;
13
14#[derive(Debug)]
15/// Kirikiri Script Builder
16pub struct KsBuilder {}
17
18impl KsBuilder {
19    /// Creates a new instance of `KsBuilder`
20    pub fn new() -> Self {
21        Self {}
22    }
23}
24
25impl ScriptBuilder for KsBuilder {
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(KsScript::new(buf, encoding, config)?))
40    }
41
42    fn extensions(&self) -> &'static [&'static str] {
43        &["ks", "soc"]
44    }
45
46    fn script_type(&self) -> &'static ScriptType {
47        &ScriptType::Kirikiri
48    }
49}
50
51/// Kirikiri Script Node Trait
52pub trait Node {
53    /// Serializes the node to ks format
54    fn serialize(&self) -> String;
55}
56
57#[derive(Clone, Debug)]
58/// Comment Node
59pub struct CommentNode(pub String);
60
61impl Node for CommentNode {
62    fn serialize(&self) -> String {
63        format!("; {}", self.0)
64    }
65}
66
67#[derive(Clone, Debug)]
68/// Label Node
69pub struct LabelNode {
70    /// The name of the label
71    pub name: String,
72    /// The page of the label
73    pub page: Option<String>,
74}
75
76impl Node for LabelNode {
77    fn serialize(&self) -> String {
78        if let Some(page) = &self.page {
79            format!("*{}|{}", self.name, page)
80        } else {
81            format!("*{}", self.name)
82        }
83    }
84}
85
86#[derive(Clone, Debug)]
87/// Text Node
88pub struct TextNode(pub String);
89
90impl Node for TextNode {
91    fn serialize(&self) -> String {
92        // In KAG, [ is escaped as [[
93        self.0.replace("[", "[[")
94    }
95}
96
97#[derive(Clone, Debug)]
98/// Empty Line Node
99pub struct EmptyLineNode;
100
101impl Node for EmptyLineNode {
102    fn serialize(&self) -> String {
103        String::new()
104    }
105}
106
107#[derive(Clone, Debug)]
108/// Represents a tag attribute's value
109pub enum TagAttr {
110    /// true if no value is specified
111    True,
112    /// String value of the attribute
113    Str(String),
114}
115
116#[derive(Clone, Debug)]
117/// Tag Node
118pub struct TagNode {
119    /// The name of the tag
120    pub name: String,
121    /// The attributes of the tag
122    pub attributes: Vec<(String, TagAttr)>,
123}
124
125impl TagNode {
126    fn serialize_attributes(&self) -> String {
127        let mut parts = Vec::new();
128        for (key, value) in self.attributes.iter() {
129            match value {
130                TagAttr::True => {
131                    parts.push(key.clone());
132                }
133                TagAttr::Str(val) => {
134                    if val.contains(" ") || val.contains("=") {
135                        parts.push(format!("{}=\"{}\"", key, val));
136                    } else {
137                        parts.push(format!("{}={}", key, val));
138                    }
139                }
140            }
141        }
142        parts.join(" ")
143    }
144
145    fn ser_attributes_xml(&self) -> String {
146        let mut parts = Vec::new();
147        for (key, value) in self.attributes.iter() {
148            match value {
149                TagAttr::True => {
150                    parts.push(key.clone());
151                }
152                TagAttr::Str(val) => {
153                    parts.push(format!("{}=\"{}\"", key, escape_xml_attr_value(val)));
154                }
155            }
156        }
157        parts.join(" ")
158    }
159
160    /// Sets an attribute for the tag, replacing it if it already exists.
161    pub fn set_attr(&mut self, key: &str, value: String) {
162        if let Some(attr) = self.attributes.iter_mut().find(|(k, _)| k == key) {
163            attr.1 = TagAttr::Str(value);
164        } else {
165            self.attributes.push((key.to_string(), TagAttr::Str(value)));
166        }
167    }
168
169    fn to_xml_tag(&self) -> String {
170        let attr_str = self.ser_attributes_xml();
171        if attr_str.is_empty() {
172            format!("<{}>", self.name)
173        } else {
174            format!("<{} {}>", self.name, attr_str)
175        }
176    }
177}
178
179impl Node for TagNode {
180    fn serialize(&self) -> String {
181        let attr_str = self.serialize_attributes();
182        if attr_str.is_empty() {
183            format!("[{}]", self.name)
184        } else {
185            format!("[{} {}]", self.name, attr_str)
186        }
187    }
188}
189
190#[derive(Clone)]
191/// Command Node
192pub struct CommandNode {
193    /// Same as TagNode, but used for commands
194    pub inner: TagNode,
195}
196
197impl Deref for CommandNode {
198    type Target = TagNode;
199
200    fn deref(&self) -> &Self::Target {
201        &self.inner
202    }
203}
204
205impl DerefMut for CommandNode {
206    fn deref_mut(&mut self) -> &mut Self::Target {
207        &mut self.inner
208    }
209}
210
211impl std::fmt::Debug for CommandNode {
212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213        f.debug_struct("CommandNode")
214            .field("name", &self.inner.name)
215            .field("attributes", &self.inner.attributes)
216            .finish()
217    }
218}
219
220impl Node for CommandNode {
221    fn serialize(&self) -> String {
222        let attr_str = self.inner.serialize_attributes();
223        if attr_str.is_empty() {
224            format!("@{}", self.inner.name)
225        } else {
226            format!("@{} {}", self.inner.name, attr_str)
227        }
228    }
229}
230
231#[derive(Clone, Debug)]
232/// Script Block Node
233pub struct ScriptBlockNode(pub String);
234
235impl Node for ScriptBlockNode {
236    fn serialize(&self) -> String {
237        format!("[iscript]\n{}\n[endscript]", self.0)
238    }
239}
240
241#[derive(Clone, Debug)]
242/// Parsed Line Node
243pub enum ParsedLineNode {
244    /// Text node containing plain text
245    Text(TextNode),
246    /// Tag node
247    Tag(TagNode),
248}
249
250impl ParsedLineNode {
251    fn to_xml(&self) -> String {
252        match self {
253            ParsedLineNode::Text(text_node) => escape_xml_text_value(&text_node.0),
254            ParsedLineNode::Tag(tag_node) => {
255                if tag_node.name == "r" && tag_node.attributes.is_empty() {
256                    "\n".to_string()
257                } else {
258                    tag_node.to_xml_tag()
259                }
260            }
261        }
262    }
263
264    fn is_np(&self) -> bool {
265        matches!(self, ParsedLineNode::Tag(tag) if tag.name == "np")
266    }
267}
268
269impl Node for ParsedLineNode {
270    fn serialize(&self) -> String {
271        match self {
272            ParsedLineNode::Text(text_node) => text_node.serialize(),
273            ParsedLineNode::Tag(tag_node) => tag_node.serialize(),
274        }
275    }
276}
277
278#[derive(Clone, Debug)]
279/// Parsed Line
280pub struct ParsedLine(pub Vec<ParsedLineNode>);
281
282impl ParsedLine {
283    fn to_xml(&self) -> String {
284        let mut s = String::new();
285        for node in &self.0 {
286            s.push_str(&node.to_xml());
287        }
288        s
289    }
290}
291
292impl Deref for ParsedLine {
293    type Target = Vec<ParsedLineNode>;
294
295    fn deref(&self) -> &Self::Target {
296        &self.0
297    }
298}
299
300impl DerefMut for ParsedLine {
301    fn deref_mut(&mut self) -> &mut Self::Target {
302        &mut self.0
303    }
304}
305
306impl Node for ParsedLine {
307    fn serialize(&self) -> String {
308        self.0
309            .iter()
310            .map(|node| node.serialize())
311            .collect::<Vec<_>>()
312            .join("")
313    }
314}
315
316#[derive(Clone, Debug)]
317/// Parsed Script Node
318pub enum ParsedScriptNode {
319    /// Comment node
320    Comment(CommentNode),
321    /// Label node
322    Label(LabelNode),
323    /// Command node
324    Command(CommandNode),
325    /// Script block node
326    ScriptBlock(ScriptBlockNode),
327    /// Line
328    Line(ParsedLine),
329    /// Empty line node
330    EmptyLine(EmptyLineNode),
331}
332
333impl ParsedScriptNode {
334    /// Returns true if the node is empty line node
335    pub fn is_empty(&self) -> bool {
336        matches!(self, ParsedScriptNode::EmptyLine(_))
337    }
338
339    /// Sets an attribute for the command node, replacing it if it already exists.
340    pub fn set_attr(&mut self, key: &str, value: String) {
341        if let ParsedScriptNode::Command(command) = self {
342            command.set_attr(key, value);
343        }
344    }
345}
346
347impl Node for ParsedScriptNode {
348    fn serialize(&self) -> String {
349        match self {
350            ParsedScriptNode::Comment(comment) => comment.serialize(),
351            ParsedScriptNode::Label(label) => label.serialize(),
352            ParsedScriptNode::Command(command) => command.serialize(),
353            ParsedScriptNode::ScriptBlock(script_block) => script_block.serialize(),
354            ParsedScriptNode::Line(line) => line.serialize(),
355            ParsedScriptNode::EmptyLine(empty_line) => empty_line.serialize(),
356        }
357    }
358}
359
360#[derive(Clone, Debug)]
361/// Parsed ks script
362pub struct ParsedScript(pub Vec<ParsedScriptNode>);
363
364impl Deref for ParsedScript {
365    type Target = Vec<ParsedScriptNode>;
366
367    fn deref(&self) -> &Self::Target {
368        &self.0
369    }
370}
371
372impl DerefMut for ParsedScript {
373    fn deref_mut(&mut self) -> &mut Self::Target {
374        &mut self.0
375    }
376}
377
378impl Index<usize> for ParsedScript {
379    type Output = ParsedScriptNode;
380
381    fn index(&self, index: usize) -> &Self::Output {
382        &self.0[index]
383    }
384}
385
386impl IndexMut<usize> for ParsedScript {
387    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
388        if index < self.0.len() {
389            &mut self.0[index]
390        } else {
391            self.0.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
392            self.0.last_mut().unwrap()
393        }
394    }
395}
396
397impl Node for ParsedScript {
398    fn serialize(&self) -> String {
399        self.0
400            .iter()
401            .map(|node| node.serialize())
402            .collect::<Vec<_>>()
403            .join("\n")
404    }
405}
406
407lazy_static::lazy_static! {
408    static ref LINE_SPLIT_RE: Regex = Regex::new(r"(\[.*?\])").unwrap();
409    static ref ATTR_RE: Regex = Regex::new("([a-zA-Z0-9_]+)(?:=(\"[^\"]*\"|'[^']*'|[^\\s\\]]+))?").unwrap();
410}
411
412/// Parser for Kirikiri Script (.ks)
413pub struct Parser {
414    lines: Vec<String>,
415}
416
417impl Parser {
418    /// Creates a new parser for the given script
419    ///
420    /// * `script` - The script to parse
421    pub fn new(script: &str) -> Self {
422        let lines = script.lines().map(|s| s.to_string()).collect();
423        Self { lines }
424    }
425
426    fn parse_attributes(attr_str: &str) -> Result<Vec<(String, TagAttr)>> {
427        let mut attributes = Vec::new();
428        for cap in ATTR_RE.captures_iter(attr_str) {
429            let cap = cap?;
430            let key = cap
431                .get(1)
432                .ok_or(anyhow::anyhow!("Invalid attribute key"))?
433                .as_str()
434                .to_string();
435            let value = cap
436                .get(2)
437                .map(|v| {
438                    let mut s = v.as_str().trim().to_string();
439                    if s.starts_with("\"") && s.ends_with("\"") {
440                        s = s[1..s.len() - 1].to_string();
441                    } else if s.starts_with("'") && s.ends_with("'") {
442                        s = s[1..s.len() - 1].to_string();
443                    }
444                    s = s.replace("`", "");
445                    TagAttr::Str(s)
446                })
447                .unwrap_or(TagAttr::True);
448            attributes.push((key, value));
449        }
450        Ok(attributes)
451    }
452
453    fn parse_tag_or_command(content: &str) -> Result<TagNode> {
454        let parts = content.trim().split_ascii_whitespace().collect::<Vec<_>>();
455        let tag_name = parts[0].to_string();
456        let attr_string = parts[1..].join(" ");
457        let attrs = Self::parse_attributes(&attr_string)?;
458        Ok(TagNode {
459            name: tag_name,
460            attributes: attrs,
461        })
462    }
463
464    /// Parses the script and returns a `ParsedScript`
465    ///
466    /// * `preserve_empty_lines` - If true, empty lines will be preserved in the parsed script
467    pub fn parse(&self, preserve_empty_lines: bool) -> Result<ParsedScript> {
468        let mut parsed_scripts = Vec::new();
469        let mut in_script_block = false;
470        let mut script_buffer = Vec::new();
471        let mut i = 0;
472        let line_count = self.lines.len();
473        while i < line_count {
474            let line = self.lines[i].trim();
475            i += 1;
476            if line.is_empty() {
477                if preserve_empty_lines {
478                    parsed_scripts.push(ParsedScriptNode::EmptyLine(EmptyLineNode));
479                } else {
480                    continue;
481                }
482            }
483            if in_script_block {
484                if line == "[endscript]" {
485                    in_script_block = false;
486                    parsed_scripts.push(ParsedScriptNode::ScriptBlock(ScriptBlockNode(
487                        script_buffer.join("\n"),
488                    )));
489                    script_buffer.clear();
490                } else {
491                    script_buffer.push(line.to_string());
492                }
493                continue;
494            }
495            if line == "[iscript]" {
496                in_script_block = true;
497                continue;
498            }
499            if line.starts_with(";") {
500                parsed_scripts.push(ParsedScriptNode::Comment(CommentNode(
501                    line[1..].trim().to_string(),
502                )));
503                continue;
504            }
505            if line.starts_with("*") {
506                let parts: Vec<&str> = line.split('|').collect();
507                let label_name = parts[0][1..].trim().to_string();
508                let page = if parts.len() > 1 {
509                    Some(parts[1..].join("|"))
510                } else {
511                    None
512                };
513                parsed_scripts.push(ParsedScriptNode::Label(LabelNode {
514                    name: label_name,
515                    page,
516                }));
517                continue;
518            }
519            if line.starts_with("@") {
520                let content = &line[1..];
521                let tag_node = Self::parse_tag_or_command(content)?;
522                parsed_scripts.push(ParsedScriptNode::Command(CommandNode { inner: tag_node }));
523                continue;
524            }
525            let mut full_line = line.to_string();
526            while full_line.ends_with("\\") {
527                full_line.pop(); // Remove the trailing backslash
528                full_line = full_line.trim_end().to_string();
529                if i < line_count {
530                    full_line.push(' ');
531                    full_line.push_str(&self.lines[i].trim());
532                    i += 1;
533                } else {
534                    break; // No more lines to append
535                }
536            }
537            let mut parsed_line_nodes = Vec::new();
538            for part in LINE_SPLIT_RE.py_split(&full_line)? {
539                let part = part.trim();
540                if part.is_empty() {
541                    continue;
542                }
543                if part.starts_with("[") && part.ends_with("]") {
544                    if part == "[[r]]" {
545                        parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[r]".to_string())));
546                    } else if part == "[[[[" {
547                        parsed_line_nodes.push(ParsedLineNode::Text(TextNode("[[".to_string())));
548                    } else if part.starts_with("[[") {
549                        parsed_line_nodes
550                            .push(ParsedLineNode::Text(TextNode(part[1..].to_string())))
551                    } else {
552                        parsed_line_nodes.push(ParsedLineNode::Tag(Self::parse_tag_or_command(
553                            &part[1..part.len() - 1],
554                        )?));
555                    }
556                } else {
557                    parsed_line_nodes.push(ParsedLineNode::Text(TextNode(part.to_string())));
558                }
559            }
560            if !parsed_line_nodes.is_empty() {
561                parsed_scripts.push(ParsedScriptNode::Line(ParsedLine(parsed_line_nodes)));
562            }
563        }
564        Ok(ParsedScript(parsed_scripts))
565    }
566}
567
568struct XMLTextParser {
569    str: String,
570    pos: usize,
571}
572
573impl XMLTextParser {
574    pub fn new(text: &str) -> Self {
575        Self {
576            str: text.replace("\n", "<r>"),
577            pos: 0,
578        }
579    }
580
581    fn parse_tag(&mut self) -> Result<TagNode> {
582        let mut name = String::new();
583        let mut attributes = Vec::new();
584        let mut is_name = true;
585        let mut is_key = false;
586        let mut is_value = false;
587        let mut is_in_quote = false;
588        let mut key = String::new();
589        let mut value = String::new();
590        while let Some(c) = self.next() {
591            match c {
592                '>' => {
593                    if !name.is_empty() {
594                        return Ok(TagNode { name, attributes });
595                    } else {
596                        return Err(anyhow::anyhow!("Empty tag name"));
597                    }
598                }
599                ' ' | '\t' => {
600                    if is_name {
601                        is_name = false;
602                        is_key = true;
603                    } else if is_key {
604                        if !key.is_empty() {
605                            attributes.push((key.clone(), TagAttr::True));
606                            key.clear();
607                        }
608                    } else if is_value {
609                        if is_in_quote {
610                            value.push(c);
611                        } else {
612                            if !value.is_empty() {
613                                attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
614                                key.clear();
615                                value.clear();
616                            }
617                            is_key = true;
618                            is_value = false;
619                        }
620                    }
621                }
622                '"' => {
623                    if is_in_quote {
624                        is_in_quote = false;
625                        if !value.is_empty() {
626                            attributes.push((key.clone(), TagAttr::Str(unescape_xml(&value))));
627                            key.clear();
628                            value.clear();
629                        }
630                        is_key = true;
631                    } else {
632                        is_in_quote = true;
633                    }
634                }
635                '=' => {
636                    if is_key {
637                        is_key = false;
638                        is_value = true;
639                    }
640                }
641                _ => {
642                    if is_name {
643                        name.push(c);
644                    } else if is_key {
645                        key.push(c);
646                    } else if is_value {
647                        value.push(c);
648                    } else {
649                        return Err(anyhow::anyhow!("Unexpected character in tag: {}", c));
650                    }
651                }
652            }
653        }
654        Err(anyhow::anyhow!("Unexpected end of input while parsing tag"))
655    }
656
657    pub fn parse(mut self) -> Result<Vec<ParsedLine>> {
658        let mut lines = Vec::new();
659        let mut current_line = Vec::new();
660        let mut text = String::new();
661        while let Some(c) = self.next() {
662            match c {
663                '<' => {
664                    if !text.is_empty() {
665                        current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
666                        text.clear();
667                    }
668                    let tag = self.parse_tag()?;
669                    let is_r = tag.name == "r";
670                    current_line.push(ParsedLineNode::Tag(tag));
671                    if is_r {
672                        lines.push(ParsedLine(current_line));
673                        current_line = Vec::new();
674                    }
675                }
676                _ => text.push(c),
677            }
678        }
679        if !text.is_empty() {
680            current_line.push(ParsedLineNode::Text(TextNode(unescape_xml(&text))));
681        }
682        current_line.push(ParsedLineNode::Tag(TagNode {
683            name: "np".to_string(),
684            attributes: Vec::new(),
685        }));
686        lines.push(ParsedLine(current_line));
687        Ok(lines)
688    }
689
690    fn next(&mut self) -> Option<char> {
691        if self.pos < self.str.len() {
692            let c = self.str[self.pos..].chars().next()?;
693            self.pos += c.len_utf8();
694            Some(c)
695        } else {
696            None
697        }
698    }
699}
700
701#[derive(Debug)]
702/// Kirikiri Script
703pub struct KsScript {
704    bom: BomType,
705    tree: ParsedScript,
706    name_commands: Arc<HashSet<String>>,
707    message_commands: Arc<HashSet<String>>,
708    remove_empty_lines: bool,
709}
710
711impl KsScript {
712    /// Creates a new `KsScript` from the given reader and encoding
713    ///
714    /// * `reader` - The reader containing the script data
715    /// * `encoding` - The encoding of the script
716    /// * `config` - Extra configuration options
717    pub fn new(reader: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
718        let (text, bom) = decode_with_bom_detect(encoding, &reader, true)?;
719        let parser = Parser::new(&text);
720        let tree = parser.parse(!config.kirikiri_remove_empty_lines)?;
721        Ok(Self {
722            bom,
723            tree,
724            name_commands: config.kirikiri_name_commands.clone(),
725            message_commands: config.kirikiri_message_commands.clone(),
726            remove_empty_lines: config.kirikiri_remove_empty_lines,
727        })
728    }
729}
730
731impl Script for KsScript {
732    fn default_output_script_type(&self) -> OutputScriptType {
733        OutputScriptType::Json
734    }
735
736    fn default_format_type(&self) -> FormatOptions {
737        FormatOptions::None
738    }
739
740    fn extract_messages(&self) -> Result<Vec<Message>> {
741        let mut messages = Vec::new();
742        let mut name = None;
743        let mut message = String::new();
744        for obj in self.tree.iter() {
745            match obj {
746                ParsedScriptNode::Label(_) => {
747                    if !message.is_empty() {
748                        messages.push(Message {
749                            name: name.clone(),
750                            message: message.trim_end_matches("<np>").to_owned(),
751                        });
752                        message.clear();
753                        name = None;
754                    }
755                }
756                ParsedScriptNode::Line(line) => {
757                    if !message.ends_with("<np>") {
758                        message.push_str(&line.to_xml())
759                    }
760                }
761                ParsedScriptNode::Command(cmd) => {
762                    if self.name_commands.contains(&cmd.name) {
763                        for attr in &cmd.attributes {
764                            if let TagAttr::Str(value) = &attr.1 {
765                                if !value.is_empty() && !value.is_ascii() {
766                                    name = Some(value.clone());
767                                    break; // Only take the first name found
768                                }
769                            }
770                        }
771                    } else if self.message_commands.contains(&cmd.name) {
772                        for attr in &cmd.attributes {
773                            if let TagAttr::Str(value) = &attr.1 {
774                                if !value.is_empty() && !value.is_ascii() {
775                                    messages.push(Message {
776                                        name: None,
777                                        message: value.clone(),
778                                    });
779                                    break; // Only take the first message found
780                                }
781                            }
782                        }
783                    }
784                }
785                _ => {}
786            }
787        }
788        if !message.is_empty() {
789            messages.push(Message {
790                name,
791                message: message.trim_end_matches("<np>").to_owned(),
792            });
793        }
794        Ok(messages)
795    }
796
797    fn import_messages<'a>(
798        &'a self,
799        messages: Vec<Message>,
800        mut file: Box<dyn WriteSeek + 'a>,
801        _filename: &str,
802        encoding: Encoding,
803        replacement: Option<&'a ReplacementTable>,
804    ) -> Result<()> {
805        let mut mes = messages.iter();
806        let mut cur_mes = None;
807        let mut tree = self.tree.clone();
808        let mut message_lines = Vec::new();
809        let mut i = 0;
810        let mut is_end = false;
811        let mut name_command_block_line: Option<(usize, String)> = None;
812        while i < tree.len() {
813            match tree[i].clone() {
814                ParsedScriptNode::Label(_) => {
815                    if !message_lines.is_empty() {
816                        let m: &Message = cur_mes
817                            .take()
818                            .ok_or(anyhow::anyhow!("Not enough messages"))?;
819                        if let Some((line, key)) = name_command_block_line.take() {
820                            let name = m
821                                .name
822                                .as_ref()
823                                .ok_or(anyhow::anyhow!("Name not found in message"))?;
824                            let mut name = name.clone();
825                            if let Some(replacement) = replacement {
826                                for (key, value) in replacement.map.iter() {
827                                    name = name.replace(key, value);
828                                }
829                            }
830                            tree[line].set_attr(&key, name);
831                        }
832                        let mut text = m.message.to_owned();
833                        if let Some(replacement) = replacement {
834                            for (key, value) in replacement.map.iter() {
835                                text = text.replace(key, value);
836                            }
837                        }
838                        let mess = XMLTextParser::new(&text).parse()?;
839                        let diff = mess.len() as isize - message_lines.len() as isize;
840                        let common_lines = message_lines.len().min(mess.len());
841                        let mut last_index = message_lines.last().cloned().unwrap_or(0);
842                        for j in 0..common_lines {
843                            tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
844                        }
845                        for j in common_lines..message_lines.len() {
846                            tree.remove(message_lines[j] - (j - common_lines));
847                        }
848                        for i in common_lines..mess.len() {
849                            let new_line = ParsedScriptNode::Line(mess[i].clone());
850                            if last_index < tree.len() {
851                                tree.insert(last_index + 1, new_line);
852                                last_index += 1;
853                            } else {
854                                tree.push(new_line);
855                            }
856                        }
857                        i = (i as isize + diff) as usize;
858                    }
859                    message_lines.clear();
860                    is_end = false;
861                    if cur_mes.is_none() {
862                        cur_mes = mes.next();
863                    }
864                }
865                ParsedScriptNode::Line(line) => {
866                    if !is_end {
867                        message_lines.push(i);
868                        is_end = line.last().map(|e| e.is_np()).unwrap_or(false);
869                    }
870                }
871                ParsedScriptNode::Command(cmd) => {
872                    if self.name_commands.contains(&cmd.name) {
873                        for attr in &cmd.attributes {
874                            if let TagAttr::Str(value) = &attr.1 {
875                                if !value.is_empty() && !value.is_ascii() {
876                                    name_command_block_line = Some((i, attr.0.clone()));
877                                    break; // Only update the first name found
878                                }
879                            }
880                        }
881                    } else if self.message_commands.contains(&cmd.name) {
882                        for attr in &cmd.attributes {
883                            if let TagAttr::Str(value) = &attr.1 {
884                                if !value.is_empty() && !value.is_ascii() {
885                                    let m = cur_mes
886                                        .take()
887                                        .ok_or(anyhow::anyhow!("Not enough messages"))?;
888                                    let mut text = m.message.clone();
889                                    if let Some(replacement) = replacement {
890                                        for (key, value) in replacement.map.iter() {
891                                            text = text.replace(key, value);
892                                        }
893                                    }
894                                    tree[i].set_attr(&attr.0, text);
895                                    cur_mes = mes.next();
896                                    break; // Only update the first message found
897                                }
898                            }
899                        }
900                    }
901                }
902                _ => {}
903            }
904            i += 1;
905        }
906        if !message_lines.is_empty() {
907            let m: &Message = cur_mes
908                .take()
909                .ok_or(anyhow::anyhow!("Not enough messages"))?;
910            if let Some((line, key)) = name_command_block_line.take() {
911                let name = m
912                    .name
913                    .as_ref()
914                    .ok_or(anyhow::anyhow!("Name not found in message"))?;
915                let mut name = name.clone();
916                if let Some(replacement) = replacement {
917                    for (key, value) in replacement.map.iter() {
918                        name = name.replace(key, value);
919                    }
920                }
921                tree[line].set_attr(&key, name);
922            }
923            let mut text = m.message.to_owned();
924            if let Some(replacement) = replacement {
925                for (key, value) in replacement.map.iter() {
926                    text = text.replace(key, value);
927                }
928            }
929            let mess = XMLTextParser::new(&text).parse()?;
930            let common_lines = message_lines.len().min(mess.len());
931            let mut last_index = message_lines.last().cloned().unwrap_or(0);
932            for j in 0..common_lines {
933                tree[message_lines[j]] = ParsedScriptNode::Line(mess[j].clone());
934            }
935            for j in common_lines..message_lines.len() {
936                tree.remove(message_lines[j] - (j - common_lines));
937            }
938            for i in common_lines..mess.len() {
939                let new_line = ParsedScriptNode::Line(mess[i].clone());
940                if last_index < tree.len() {
941                    tree.insert(last_index + 1, new_line);
942                    last_index += 1;
943                } else {
944                    tree.push(new_line);
945                }
946            }
947        }
948        if cur_mes.is_some() || mes.next().is_some() {
949            return Err(anyhow::anyhow!("Some messages were not processed."));
950        }
951        if self.remove_empty_lines {
952            tree.retain(|node| !node.is_empty());
953        }
954        let s = tree.serialize() + "\n";
955        let data = encode_string_with_bom(encoding, &s, false, self.bom)?;
956        file.write_all(&data)?;
957        Ok(())
958    }
959}