mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-16 18:14:19 +08:00
Add new argument --custom-yaml to support custom export as yaml format
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -320,6 +320,7 @@ dependencies = [
|
||||
"encoding",
|
||||
"flate2",
|
||||
"itertools",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2024"
|
||||
repository = "https://github.com/lifegpc/msg-tool"
|
||||
description = "A command-line tool for exporting, importing, packing, and unpacking script files."
|
||||
license = "MIT"
|
||||
exclude = [".github", "*.py"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
@@ -13,7 +14,7 @@ clap = { version = "4.5", features = ["derive"] }
|
||||
clap-num = "1.2"
|
||||
csv = "1.3"
|
||||
ctrlc = "3.4"
|
||||
emote-psb = { version = "0.5", optional = true }
|
||||
emote-psb = { version = "0.5", optional = true , features = ["serde"] }
|
||||
encoding_rs = "0.8"
|
||||
fancy-regex = { version = "0.16", optional = true }
|
||||
flate2 = { version = "1.1", optional = true }
|
||||
|
||||
@@ -329,6 +329,10 @@ pub struct Arg {
|
||||
#[arg(short = 'W', long, global = true, value_name = "QUALITY", group = "webp_qualityg", value_parser = parse_webp_quality, default_value_t = 80)]
|
||||
/// WebP quality for output images, 0-100. 100 means best quality.
|
||||
pub webp_quality: u8,
|
||||
#[arg(long, global = true)]
|
||||
/// Try use YAML format instead of JSON when custom exporting.
|
||||
/// By default, this is based on output type. But can be overridden by this option.
|
||||
pub custom_yaml: Option<bool>,
|
||||
#[command(subcommand)]
|
||||
/// Command
|
||||
pub command: Command,
|
||||
|
||||
@@ -8,13 +8,15 @@ use emote_psb::types::string::*;
|
||||
use emote_psb::types::*;
|
||||
#[cfg(feature = "json")]
|
||||
use json::JsonValue;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::PartialEq;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
const NONE: PsbValueFixed = PsbValueFixed::None;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
/// Represents of a PSB value.
|
||||
pub enum PsbValueFixed {
|
||||
/// No value.
|
||||
@@ -448,7 +450,8 @@ impl PsbValueExt for PsbValue {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
/// Represents a PSB list of PSB values.
|
||||
pub struct PsbListFixed {
|
||||
/// The values in the list.
|
||||
@@ -602,7 +605,8 @@ impl PsbListExt for PsbList {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
/// Represents a PSB object with key-value pairs.
|
||||
pub struct PsbObjectFixed {
|
||||
/// The key-value pairs in the object.
|
||||
@@ -785,6 +789,26 @@ pub struct VirtualPsbFixed {
|
||||
root: PsbObjectFixed,
|
||||
}
|
||||
|
||||
impl Serialize for VirtualPsbFixed {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("VirtualPsbFixed", 3)?;
|
||||
state.serialize_field("version", &self.header.version)?;
|
||||
state.serialize_field("encryption", &self.header.encryption)?;
|
||||
state.serialize_field("data", &self.root)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct VirtualPsbFixedData {
|
||||
version: u16,
|
||||
encryption: u16,
|
||||
data: PsbObjectFixed,
|
||||
}
|
||||
|
||||
impl VirtualPsbFixed {
|
||||
/// Creates a new fixed virtual PSB.
|
||||
pub fn new(
|
||||
@@ -867,6 +891,12 @@ impl VirtualPsbFixed {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_data(&mut self, data: VirtualPsbFixedData) {
|
||||
self.header.version = data.version;
|
||||
self.header.encryption = data.encryption;
|
||||
self.root = data.data;
|
||||
}
|
||||
|
||||
/// Converts this fixed PSB to a JSON object.
|
||||
#[cfg(feature = "json")]
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
|
||||
@@ -1746,6 +1746,11 @@ fn main() {
|
||||
webp_quality: arg.webp_quality,
|
||||
#[cfg(feature = "circus-img")]
|
||||
circus_crx_canvas: arg.circus_crx_canvas,
|
||||
custom_yaml: arg.custom_yaml.unwrap_or_else(|| {
|
||||
arg.output_type
|
||||
.map(|s| s == types::OutputScriptType::Yaml)
|
||||
.unwrap_or(false)
|
||||
}),
|
||||
};
|
||||
match &arg.command {
|
||||
args::Command::Export { input, output } => {
|
||||
|
||||
@@ -64,9 +64,15 @@ impl ScriptBuilder for ArtemisAsbBuilder {
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(filename, writer, encoding, file_encoding)
|
||||
create_file(
|
||||
filename,
|
||||
writer,
|
||||
encoding,
|
||||
file_encoding,
|
||||
config.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +420,7 @@ impl<'a> TextParser<'a> {
|
||||
/// The Artemis ASB script.
|
||||
pub struct Asb {
|
||||
items: Vec<Item>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl Asb {
|
||||
@@ -422,7 +429,7 @@ impl Asb {
|
||||
/// * `buf` - The buffer containing the ASB data.
|
||||
/// * `encoding` - The encoding used for the ASB data.
|
||||
/// * `config` - Extra configuration options.
|
||||
pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
|
||||
pub fn new(buf: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
|
||||
let mut data = MemReader::new(buf);
|
||||
let mut magic = [0; 5];
|
||||
data.read_exact(&mut magic)?;
|
||||
@@ -434,7 +441,10 @@ impl Asb {
|
||||
for _ in 0..nums {
|
||||
items.push(data.read_item(encoding)?);
|
||||
}
|
||||
Ok(Asb { items })
|
||||
Ok(Asb {
|
||||
items,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +462,7 @@ impl Script for Asb {
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
@@ -645,7 +655,11 @@ impl Script for Asb {
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
let s = serde_json::to_string_pretty(&self.items)?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&self.items)?
|
||||
} else {
|
||||
serde_json::to_string_pretty(&self.items)?
|
||||
};
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
let mut file = std::fs::File::create(filename)?;
|
||||
file.write_all(&s)?;
|
||||
@@ -659,7 +673,13 @@ impl Script for Asb {
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(custom_filename, file, encoding, output_encoding)
|
||||
create_file(
|
||||
custom_filename,
|
||||
file,
|
||||
encoding,
|
||||
output_encoding,
|
||||
self.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,15 +689,21 @@ impl Script for Asb {
|
||||
/// * `writer` - The writer to write the ASB script.
|
||||
/// * `encoding` - The encoding used for the ASB script.
|
||||
/// * `output_encoding` - The encoding used for the input file.
|
||||
/// * `yaml` - Whether to use YAML format instead of JSON for the input file.
|
||||
pub fn create_file<'a>(
|
||||
custom_filename: &'a str,
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
yaml: bool,
|
||||
) -> Result<()> {
|
||||
let f = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &f, true)?;
|
||||
let items: Vec<Item> = serde_json::from_str(&s)?;
|
||||
let items: Vec<Item> = if yaml {
|
||||
serde_yaml_ng::from_str(&s)?
|
||||
} else {
|
||||
serde_json::from_str(&s)?
|
||||
};
|
||||
writer.write_all(b"ASB\0\0")?;
|
||||
writer.write_u32(items.len() as u32)?;
|
||||
for item in items {
|
||||
|
||||
@@ -53,9 +53,15 @@ impl ScriptBuilder for BGIBsiScriptBuilder {
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(filename, writer, encoding, file_encoding)
|
||||
create_file(
|
||||
filename,
|
||||
writer,
|
||||
encoding,
|
||||
file_encoding,
|
||||
config.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +70,7 @@ impl ScriptBuilder for BGIBsiScriptBuilder {
|
||||
pub struct BGIBsiScript {
|
||||
/// Section name and its data map.
|
||||
pub data: BTreeMap<String, BTreeMap<String, String>>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl BGIBsiScript {
|
||||
@@ -72,7 +79,7 @@ impl BGIBsiScript {
|
||||
/// * `buf` - The buffer containing the script data.
|
||||
/// * `encoding` - The encoding of the script.
|
||||
/// * `config` - Extra configuration options.
|
||||
pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
|
||||
pub fn new(buf: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
|
||||
let mut data = BTreeMap::new();
|
||||
let mut reader = MemReader::new(buf);
|
||||
let section_count = reader.read_u32()?;
|
||||
@@ -97,7 +104,10 @@ impl BGIBsiScript {
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
Ok(BGIBsiScript { data })
|
||||
Ok(BGIBsiScript {
|
||||
data,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,12 +125,17 @@ impl Script for BGIBsiScript {
|
||||
}
|
||||
|
||||
fn custom_output_extension(&self) -> &'static str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
let s = serde_json::to_string_pretty(&self.data)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to write BSI Map data to JSON: {}", e))?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&self.data)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::to_string(&self.data)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
|
||||
};
|
||||
let mut writer = crate::utils::files::write_file(filename)?;
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
writer.write_all(&s)?;
|
||||
@@ -135,7 +150,13 @@ impl Script for BGIBsiScript {
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(custom_filename, file, encoding, output_encoding)
|
||||
create_file(
|
||||
custom_filename,
|
||||
file,
|
||||
encoding,
|
||||
output_encoding,
|
||||
self.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,11 +165,15 @@ fn create_file<'a>(
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
yaml: bool,
|
||||
) -> Result<()> {
|
||||
let input = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &input, true)?;
|
||||
let data: BTreeMap<String, BTreeMap<String, String>> = serde_json::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to read BSI Map data from JSON: {}", e))?;
|
||||
let data: BTreeMap<String, BTreeMap<String, String>> = if yaml {
|
||||
serde_yaml_ng::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
|
||||
};
|
||||
writer.write_u32(data.len() as u32)?;
|
||||
for (section_name, section_data) in data {
|
||||
let section_name_bytes = encode_string(encoding, §ion_name, false)?;
|
||||
|
||||
@@ -60,9 +60,15 @@ impl ScriptBuilder for CstlScriptBuilder {
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(filename, writer, encoding, file_encoding)
|
||||
create_file(
|
||||
filename,
|
||||
writer,
|
||||
encoding,
|
||||
file_encoding,
|
||||
config.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,15 +78,21 @@ impl ScriptBuilder for CstlScriptBuilder {
|
||||
/// * `file` - The writer to write the CSTL file to.
|
||||
/// * `encoding` - The encoding of the CSTL file.
|
||||
/// * `output_encoding` - The encoding to use for the input file.
|
||||
/// * `yaml` - Whether to use YAML format.
|
||||
pub fn create_file<T: Write>(
|
||||
custom_filename: &str,
|
||||
mut file: T,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
yaml: bool,
|
||||
) -> Result<()> {
|
||||
let input = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &input, true)?;
|
||||
let data: BTreeMap<String, Vec<Message>> = serde_json::from_str(&s)?;
|
||||
let data: BTreeMap<String, Vec<Message>> = if yaml {
|
||||
serde_yaml_ng::from_str(&s)?
|
||||
} else {
|
||||
serde_json::from_str(&s)?
|
||||
};
|
||||
let count = data
|
||||
.first_key_value()
|
||||
.ok_or(anyhow::anyhow!("No data found in JSON"))?
|
||||
@@ -165,6 +177,7 @@ pub struct CstlScript {
|
||||
langs: Vec<String>,
|
||||
data: Vec<Vec<Message>>,
|
||||
lang_index: Option<usize>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl CstlScript {
|
||||
@@ -242,6 +255,7 @@ impl CstlScript {
|
||||
langs,
|
||||
data,
|
||||
lang_index,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -260,7 +274,7 @@ impl Script for CstlScript {
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
@@ -348,7 +362,13 @@ impl Script for CstlScript {
|
||||
for (lang, data) in self.langs.iter().zip(&self.data) {
|
||||
d.insert(lang, data);
|
||||
}
|
||||
let s = serde_json::to_string_pretty(&d)?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&d)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::to_string(&d)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
|
||||
};
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
let mut file = std::fs::File::create(filename)?;
|
||||
file.write_all(&s)?;
|
||||
@@ -362,6 +382,12 @@ impl Script for CstlScript {
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(custom_filename, file, encoding, output_encoding)
|
||||
create_file(
|
||||
custom_filename,
|
||||
file,
|
||||
encoding,
|
||||
output_encoding,
|
||||
self.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +64,15 @@ impl ScriptBuilder for EscudeBinListBuilder {
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(filename, writer, encoding, file_encoding)
|
||||
create_file(
|
||||
filename,
|
||||
writer,
|
||||
encoding,
|
||||
file_encoding,
|
||||
config.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +81,7 @@ impl ScriptBuilder for EscudeBinListBuilder {
|
||||
pub struct EscudeBinList {
|
||||
/// List of entries in the Escu:de list
|
||||
pub entries: Vec<ListEntry>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl EscudeBinList {
|
||||
@@ -88,7 +95,7 @@ impl EscudeBinList {
|
||||
data: Vec<u8>,
|
||||
filename: &str,
|
||||
encoding: Encoding,
|
||||
_config: &ExtraConfig,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<Self> {
|
||||
let mut reader = MemReader::new(data);
|
||||
let mut magic = [0; 4];
|
||||
@@ -111,7 +118,10 @@ impl EscudeBinList {
|
||||
data: ListData::Unknown(data),
|
||||
});
|
||||
}
|
||||
let mut s = EscudeBinList { entries };
|
||||
let mut s = EscudeBinList {
|
||||
entries,
|
||||
custom_yaml: config.custom_yaml,
|
||||
};
|
||||
match s.try_decode(filename, encoding) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
@@ -293,11 +303,15 @@ fn create_file<'a>(
|
||||
mut writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
yaml: bool,
|
||||
) -> Result<()> {
|
||||
let input = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &input, true)?;
|
||||
let entries: Vec<ListEntry> = serde_json::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to read Escude list from JSON: {}", e))?;
|
||||
let entries: Vec<ListEntry> = if yaml {
|
||||
serde_yaml_ng::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
|
||||
};
|
||||
writer.write_all(b"LIST")?;
|
||||
writer.write_u32(0)?; // Placeholder for size
|
||||
let mut total_size = 0;
|
||||
@@ -333,12 +347,17 @@ impl Script for EscudeBinList {
|
||||
}
|
||||
|
||||
fn custom_output_extension(&self) -> &'static str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
let s = serde_json::to_string_pretty(&self.entries)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to write Escude list to JSON: {}", e))?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&self.entries)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::to_string(&self.entries)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
|
||||
};
|
||||
let mut writer = crate::utils::files::write_file(filename)?;
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
writer.write_all(&s)?;
|
||||
@@ -353,7 +372,13 @@ impl Script for EscudeBinList {
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(custom_filename, writer, encoding, output_encoding)
|
||||
create_file(
|
||||
custom_filename,
|
||||
writer,
|
||||
encoding,
|
||||
output_encoding,
|
||||
self.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ pub struct RldScript {
|
||||
ops: Vec<OpExt>,
|
||||
is_def_chara: bool,
|
||||
name_table: Option<BTreeMap<u32, String>>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl RldScript {
|
||||
@@ -283,6 +284,7 @@ impl RldScript {
|
||||
ops,
|
||||
is_def_chara,
|
||||
name_table,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -375,7 +377,7 @@ impl Script for RldScript {
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
@@ -472,9 +474,21 @@ impl Script for RldScript {
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
let s = if self.is_def_chara {
|
||||
let names = self.name_table()?;
|
||||
serde_json::to_string_pretty(&names)?
|
||||
if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&names)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::to_string(&names)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
|
||||
}
|
||||
} else {
|
||||
serde_json::to_string_pretty(&self.ops)?
|
||||
if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&self.ops)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::to_string(&self.ops)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
|
||||
}
|
||||
};
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
let mut file = std::fs::File::create(filename)?;
|
||||
@@ -493,7 +507,13 @@ impl Script for RldScript {
|
||||
let s = decode_to_string(output_encoding, &f, true)?;
|
||||
let ops: Vec<OpExt> = if self.is_def_chara {
|
||||
let mut ops = self.ops.clone();
|
||||
let names: BTreeMap<u32, String> = serde_json::from_str(&s)?;
|
||||
let names: BTreeMap<u32, String> = if self.custom_yaml {
|
||||
serde_yaml_ng::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
|
||||
};
|
||||
for op in ops.iter_mut() {
|
||||
if op.op == 48 {
|
||||
if op.strs.is_empty() {
|
||||
@@ -516,7 +536,13 @@ impl Script for RldScript {
|
||||
}
|
||||
ops
|
||||
} else {
|
||||
serde_json::from_str(&s)?
|
||||
if self.custom_yaml {
|
||||
serde_yaml_ng::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
|
||||
} else {
|
||||
serde_json::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
|
||||
}
|
||||
};
|
||||
if self.decrypted {
|
||||
let mut writer = MemWriter::new();
|
||||
|
||||
@@ -112,6 +112,7 @@ pub struct ScnScript {
|
||||
export_comumode: bool,
|
||||
filename: String,
|
||||
comumode_json: Option<Arc<HashMap<String, String>>>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl ScnScript {
|
||||
@@ -145,6 +146,7 @@ impl ScnScript {
|
||||
export_comumode: config.kirikiri_export_comumode,
|
||||
filename: filename.to_string(),
|
||||
comumode_json: config.kirikiri_comumode_json.clone(),
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -163,7 +165,7 @@ impl Script for ScnScript {
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
"json"
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
@@ -615,7 +617,12 @@ impl Script for ScnScript {
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &Path, encoding: Encoding) -> Result<()> {
|
||||
let s = json::stringify_pretty(self.psb.to_json(), 2);
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&self.psb)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
|
||||
} else {
|
||||
json::stringify_pretty(self.psb.to_json(), 2)
|
||||
};
|
||||
let mut f = crate::utils::files::write_file(filename)?;
|
||||
let b = encode_string(encoding, &s, false)?;
|
||||
f.write_all(&b)?;
|
||||
@@ -631,10 +638,18 @@ impl Script for ScnScript {
|
||||
) -> Result<()> {
|
||||
let data = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &data, true)?;
|
||||
let json = json::parse(&s)?;
|
||||
let mut psb = self.psb.clone();
|
||||
psb.from_json(&json)?;
|
||||
let psb = psb.to_psb();
|
||||
let psb = if self.custom_yaml {
|
||||
let data: VirtualPsbFixedData = serde_yaml_ng::from_str(&s)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to deserialize YAML: {}", e))?;
|
||||
let mut psb = self.psb.clone();
|
||||
psb.set_data(data);
|
||||
psb.to_psb()
|
||||
} else {
|
||||
let json = json::parse(&s)?;
|
||||
let mut psb = self.psb.clone();
|
||||
psb.from_json(&json)?;
|
||||
psb.to_psb()
|
||||
};
|
||||
let writer = PsbWriter::new(psb, file);
|
||||
writer.finish().map_err(|e| {
|
||||
anyhow::anyhow!("Failed to write PSB to file {}: {:?}", self.filename, e)
|
||||
|
||||
@@ -323,6 +323,8 @@ pub struct ExtraConfig {
|
||||
#[cfg(feature = "circus-img")]
|
||||
/// Draw Circus CRX images on canvas (if canvas width and height are specified in file)
|
||||
pub circus_crx_canvas: bool,
|
||||
/// Try use YAML format instead of JSON when custom exporting.
|
||||
pub custom_yaml: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
||||
Reference in New Issue
Block a user