Add new argument --custom-yaml to support custom export as yaml format

This commit is contained in:
2025-08-11 11:25:10 +08:00
parent 79657bdb1c
commit a26498e381
12 changed files with 235 additions and 49 deletions

View File

@@ -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 {

View File

@@ -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, &section_name, false)?;

View File

@@ -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,
)
}
}

View File

@@ -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,
)
}
}

View File

@@ -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();

View File

@@ -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)