diff --git a/Cargo.lock b/Cargo.lock index 3163723..9ffab84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,6 @@ dependencies = [ "encoding", "flate2", "itertools", - "serde", ] [[package]] @@ -381,12 +380,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "json" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" - [[package]] name = "lazy_static" version = "1.5.0" @@ -427,7 +420,6 @@ dependencies = [ "encoding_rs", "flate2", "int-enum", - "json", "lazy_static", "msg_tool_macro", "overf", diff --git a/Cargo.toml b/Cargo.toml index 5e17d9e..dc5365b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,10 @@ anyhow = "1" blowfish = { version = "0.9", optional = true } clap = { version = "4.5", features = ["derive"] } csv = "1.3" -emote-psb = { version = "0.5", features = ["serde"], optional = true } +emote-psb = { version = "0.5", optional = true } encoding_rs = "0.8" flate2 = { version = "1.1", optional = true } int-enum = { version = "1.2", optional = true } -json = { version = "0.12", optional = true } lazy_static = "1.5.0" msg_tool_macro = { path = "./msg_tool_macro" } overf = "0.1" @@ -33,7 +32,7 @@ cat-system-img = ["cat-system", "flate2", "image", "utils-bit-stream"] circus = [] escude = ["int-enum"] escude-arc = ["escude", "rand", "utils-bit-stream"] -kirikiri = ["emote-psb", "json"] +kirikiri = ["emote-psb"] yaneurao = [] yaneurao-itufuru = ["yaneurao"] # basic feature diff --git a/src/ext/mod.rs b/src/ext/mod.rs index d4c1155..f5c8574 100644 --- a/src/ext/mod.rs +++ b/src/ext/mod.rs @@ -1,3 +1,5 @@ pub mod atomic; pub mod io; +#[cfg(feature = "emote-psb")] +pub mod psb; pub mod vec; diff --git a/src/ext/psb.rs b/src/ext/psb.rs new file mode 100644 index 0000000..277d89c --- /dev/null +++ b/src/ext/psb.rs @@ -0,0 +1,606 @@ +use emote_psb::VirtualPsb; +use emote_psb::header::PsbHeader; +use emote_psb::types::collection::*; +use emote_psb::types::number::*; +use emote_psb::types::reference::*; +use emote_psb::types::string::*; +use emote_psb::types::*; +use std::collections::HashMap; +use std::ops::{Index, IndexMut}; + +const NONE: PsbValueFixed = PsbValueFixed::None; + +#[derive(Debug)] +pub enum PsbValueFixed { + None, + Null, + Bool(bool), + Number(PsbNumber), + IntArray(PsbUintArray), + String(PsbString), + List(PsbListFixed), + Object(PsbObjectFixed), + Resource(PsbResourceRef), + ExtraResource(PsbExtraRef), + CompilerNumber, + CompilerString, + CompilerResource, + CompilerDecimal, + CompilerArray, + CompilerBool, + CompilerBinaryTree, +} + +impl PsbValueFixed { + pub fn to_psb(self) -> PsbValue { + match self { + PsbValueFixed::None => PsbValue::None, + PsbValueFixed::Null => PsbValue::Null, + PsbValueFixed::Bool(b) => PsbValue::Bool(b), + PsbValueFixed::Number(n) => PsbValue::Number(n), + PsbValueFixed::IntArray(arr) => PsbValue::IntArray(arr), + PsbValueFixed::String(s) => PsbValue::String(s), + PsbValueFixed::List(l) => PsbValue::List(l.to_psb()), + PsbValueFixed::Object(o) => PsbValue::Object(o.to_psb()), + PsbValueFixed::Resource(r) => PsbValue::Resource(r), + PsbValueFixed::ExtraResource(er) => PsbValue::ExtraResource(er), + PsbValueFixed::CompilerNumber => PsbValue::CompilerNumber, + PsbValueFixed::CompilerString => PsbValue::CompilerString, + PsbValueFixed::CompilerResource => PsbValue::CompilerResource, + PsbValueFixed::CompilerDecimal => PsbValue::CompilerDecimal, + PsbValueFixed::CompilerArray => PsbValue::CompilerArray, + PsbValueFixed::CompilerBool => PsbValue::CompilerBool, + PsbValueFixed::CompilerBinaryTree => PsbValue::CompilerBinaryTree, + } + } + + pub fn is_list(&self) -> bool { + matches!(self, PsbValueFixed::List(_)) + } + + pub fn is_object(&self) -> bool { + matches!(self, PsbValueFixed::Object(_)) + } + + pub fn is_string_or_null(&self) -> bool { + self.is_string() || self.is_null() + } + + pub fn is_string(&self) -> bool { + matches!(self, PsbValueFixed::String(_)) + } + + pub fn is_none(&self) -> bool { + matches!(self, PsbValueFixed::None) + } + + pub fn is_null(&self) -> bool { + matches!(self, PsbValueFixed::Null) + } + + pub fn set_str(&mut self, value: &str) { + match self { + PsbValueFixed::String(s) => { + let s = s.string_mut(); + s.clear(); + s.push_str(value); + } + _ => { + *self = PsbValueFixed::String(PsbString::from(value.to_owned())); + } + } + } + + pub fn set_string(&mut self, value: String) { + self.set_str(&value); + } + + pub fn as_str(&self) -> Option<&str> { + match self { + PsbValueFixed::String(s) => Some(s.string()), + _ => None, + } + } + + pub fn len(&self) -> usize { + match self { + PsbValueFixed::List(l) => l.len(), + PsbValueFixed::Object(o) => o.values.len(), + _ => 0, + } + } + + pub fn entries(&self) -> ObjectIter<'_> { + match self { + PsbValueFixed::Object(o) => o.iter(), + _ => ObjectIter::empty(), + } + } + + pub fn entries_mut(&mut self) -> ObjectIterMut<'_> { + match self { + PsbValueFixed::Object(o) => o.iter_mut(), + _ => ObjectIterMut::empty(), + } + } + + pub fn members(&self) -> ListIter<'_> { + match self { + PsbValueFixed::List(l) => l.iter(), + _ => ListIter::empty(), + } + } + + pub fn members_mut(&mut self) -> ListIterMut<'_> { + match self { + PsbValueFixed::List(l) => l.iter_mut(), + _ => ListIterMut::empty(), + } + } +} + +impl Index for PsbValueFixed { + type Output = PsbValueFixed; + + fn index(&self, index: usize) -> &Self::Output { + match self { + PsbValueFixed::List(l) => &l.values[index], + _ => &NONE, + } + } +} + +impl IndexMut for PsbValueFixed { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match self { + PsbValueFixed::List(l) => { + if index < l.values.len() { + &mut l.values[index] + } else { + l.values.push(NONE); + &mut l.values[index] + } + } + _ => { + *self = PsbValueFixed::List(PsbListFixed { values: vec![NONE] }); + self.index_mut(0) + } + } + } +} + +impl<'a> Index<&'a str> for PsbValueFixed { + type Output = PsbValueFixed; + + fn index(&self, index: &'a str) -> &Self::Output { + match self { + PsbValueFixed::Object(o) => &o[index], + _ => &NONE, + } + } +} + +impl<'a> Index<&'a String> for PsbValueFixed { + type Output = PsbValueFixed; + + fn index(&self, index: &'a String) -> &Self::Output { + self.index(index.as_str()) + } +} + +impl Index for PsbValueFixed { + type Output = PsbValueFixed; + + fn index(&self, index: String) -> &Self::Output { + self.index(index.as_str()) + } +} + +impl IndexMut<&str> for PsbValueFixed { + fn index_mut(&mut self, index: &str) -> &mut Self::Output { + match self { + PsbValueFixed::Object(o) => o.index_mut(index), + _ => { + *self = PsbValueFixed::Object(PsbObjectFixed { + values: HashMap::new(), + }); + self.index_mut(index) + } + } + } +} + +impl IndexMut<&String> for PsbValueFixed { + fn index_mut(&mut self, index: &String) -> &mut Self::Output { + self.index_mut(index.as_str()) + } +} + +impl IndexMut for PsbValueFixed { + fn index_mut(&mut self, index: String) -> &mut Self::Output { + self.index_mut(index.as_str()) + } +} + +impl Clone for PsbValueFixed { + fn clone(&self) -> Self { + match self { + PsbValueFixed::None => PsbValueFixed::None, + PsbValueFixed::Null => PsbValueFixed::Null, + PsbValueFixed::Bool(b) => PsbValueFixed::Bool(*b), + PsbValueFixed::Number(n) => PsbValueFixed::Number(n.clone()), + PsbValueFixed::IntArray(arr) => PsbValueFixed::IntArray(arr.clone()), + PsbValueFixed::String(s) => PsbValueFixed::String(PsbString::from(s.string().clone())), + PsbValueFixed::List(l) => PsbValueFixed::List(l.clone()), + PsbValueFixed::Object(o) => PsbValueFixed::Object(o.clone()), + PsbValueFixed::Resource(r) => PsbValueFixed::Resource(r.clone()), + PsbValueFixed::ExtraResource(er) => PsbValueFixed::ExtraResource(er.clone()), + PsbValueFixed::CompilerNumber => PsbValueFixed::CompilerNumber, + PsbValueFixed::CompilerString => PsbValueFixed::CompilerString, + PsbValueFixed::CompilerResource => PsbValueFixed::CompilerResource, + PsbValueFixed::CompilerDecimal => PsbValueFixed::CompilerDecimal, + PsbValueFixed::CompilerArray => PsbValueFixed::CompilerArray, + PsbValueFixed::CompilerBool => PsbValueFixed::CompilerBool, + PsbValueFixed::CompilerBinaryTree => PsbValueFixed::CompilerBinaryTree, + } + } +} + +pub trait PsbValueExt { + fn to_psb_fixed(self) -> PsbValueFixed; +} + +impl PsbValueExt for PsbValue { + fn to_psb_fixed(self) -> PsbValueFixed { + match self { + PsbValue::None => PsbValueFixed::None, + PsbValue::Null => PsbValueFixed::Null, + PsbValue::Bool(b) => PsbValueFixed::Bool(b), + PsbValue::Number(n) => PsbValueFixed::Number(n), + PsbValue::IntArray(arr) => PsbValueFixed::IntArray(arr), + PsbValue::String(s) => PsbValueFixed::String(s), + PsbValue::List(l) => PsbValueFixed::List(PsbList::to_psb_fixed(l)), + PsbValue::Object(o) => PsbValueFixed::Object(PsbObject::to_psb_fixed(o)), + PsbValue::Resource(r) => PsbValueFixed::Resource(r), + PsbValue::ExtraResource(er) => PsbValueFixed::ExtraResource(er), + PsbValue::CompilerNumber => PsbValueFixed::CompilerNumber, + PsbValue::CompilerString => PsbValueFixed::CompilerString, + PsbValue::CompilerResource => PsbValueFixed::CompilerResource, + PsbValue::CompilerDecimal => PsbValueFixed::CompilerDecimal, + PsbValue::CompilerArray => PsbValueFixed::CompilerArray, + PsbValue::CompilerBool => PsbValueFixed::CompilerBool, + PsbValue::CompilerBinaryTree => PsbValueFixed::CompilerBinaryTree, + } + } +} + +#[derive(Clone, Debug)] +pub struct PsbListFixed { + pub values: Vec, +} + +impl PsbListFixed { + pub fn to_psb(self) -> PsbList { + let v: Vec<_> = self.values.into_iter().map(|v| v.to_psb()).collect(); + PsbList::from(v) + } + + pub fn iter(&self) -> ListIter<'_> { + ListIter { + inner: self.values.iter(), + } + } + + pub fn iter_mut(&mut self) -> ListIterMut<'_> { + ListIterMut { + inner: self.values.iter_mut(), + } + } + + pub fn values(&self) -> &Vec { + &self.values + } + + pub fn len(&self) -> usize { + self.values.len() + } +} + +pub struct ListIter<'a> { + inner: std::slice::Iter<'a, PsbValueFixed>, +} + +impl<'a> ListIter<'a> { + pub fn empty() -> Self { + ListIter { + inner: Default::default(), + } + } +} + +impl<'a> Iterator for ListIter<'a> { + type Item = &'a PsbValueFixed; + + #[inline(always)] + fn next(&mut self) -> Option { + self.inner.next() + } +} + +impl<'a> ExactSizeIterator for ListIter<'a> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl<'a> DoubleEndedIterator for ListIter<'a> { + #[inline(always)] + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +pub struct ListIterMut<'a> { + inner: std::slice::IterMut<'a, PsbValueFixed>, +} + +impl<'a> ListIterMut<'a> { + pub fn empty() -> Self { + ListIterMut { + inner: Default::default(), + } + } +} + +impl<'a> Iterator for ListIterMut<'a> { + type Item = &'a mut PsbValueFixed; + + #[inline(always)] + fn next(&mut self) -> Option { + self.inner.next() + } +} + +impl<'a> ExactSizeIterator for ListIterMut<'a> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl<'a> DoubleEndedIterator for ListIterMut<'a> { + #[inline(always)] + fn next_back(&mut self) -> Option { + self.inner.next_back() + } +} + +pub trait PsbListExt { + fn to_psb_fixed(self) -> PsbListFixed; +} + +impl PsbListExt for PsbList { + fn to_psb_fixed(self) -> PsbListFixed { + let values: Vec<_> = self + .unwrap() + .into_iter() + .map(PsbValue::to_psb_fixed) + .collect(); + PsbListFixed { values } + } +} + +#[derive(Clone, Debug)] +pub struct PsbObjectFixed { + pub values: HashMap, +} + +impl PsbObjectFixed { + pub fn to_psb(self) -> PsbObject { + let mut hash_map = HashMap::new(); + for (key, value) in self.values { + hash_map.insert(key, value.to_psb()); + } + PsbObject::from(hash_map) + } + + pub fn get_value(&self, key: &str) -> Option<&PsbValueFixed> { + self.values.get(key) + } + + pub fn iter(&self) -> ObjectIter<'_> { + ObjectIter { + inner: self.values.iter(), + } + } + + pub fn iter_mut(&mut self) -> ObjectIterMut<'_> { + ObjectIterMut { + inner: self.values.iter_mut(), + } + } +} + +impl<'a> Index<&'a str> for PsbObjectFixed { + type Output = PsbValueFixed; + + fn index(&self, index: &'a str) -> &Self::Output { + self.values.get(index).unwrap_or(&NONE) + } +} + +impl<'a> Index<&'a String> for PsbObjectFixed { + type Output = PsbValueFixed; + + fn index(&self, index: &'a String) -> &Self::Output { + self.index(index.as_str()) + } +} + +impl Index for PsbObjectFixed { + type Output = PsbValueFixed; + + fn index(&self, index: String) -> &Self::Output { + self.index(index.as_str()) + } +} + +impl<'a> IndexMut<&'a str> for PsbObjectFixed { + fn index_mut(&mut self, index: &'a str) -> &mut Self::Output { + self.values.entry(index.to_string()).or_insert(NONE) + } +} + +impl<'a> IndexMut<&'a String> for PsbObjectFixed { + fn index_mut(&mut self, index: &'a String) -> &mut Self::Output { + self.index_mut(index.as_str()) + } +} + +impl IndexMut for PsbObjectFixed { + fn index_mut(&mut self, index: String) -> &mut Self::Output { + self.values.entry(index).or_insert(NONE) + } +} + +pub trait PsbObjectExt { + fn to_psb_fixed(self) -> PsbObjectFixed; +} + +impl PsbObjectExt for PsbObject { + fn to_psb_fixed(self) -> PsbObjectFixed { + let mut hash_map = HashMap::new(); + for (key, value) in self.unwrap() { + hash_map.insert(key, PsbValue::to_psb_fixed(value)); + } + PsbObjectFixed { values: hash_map } + } +} + +pub struct ObjectIter<'a> { + inner: std::collections::hash_map::Iter<'a, String, PsbValueFixed>, +} + +impl<'a> ObjectIter<'a> { + pub fn empty() -> Self { + ObjectIter { + inner: Default::default(), + } + } +} + +impl<'a> Iterator for ObjectIter<'a> { + type Item = (&'a String, &'a PsbValueFixed); + + #[inline(always)] + fn next(&mut self) -> Option { + self.inner.next() + } +} +impl<'a> ExactSizeIterator for ObjectIter<'a> { + fn len(&self) -> usize { + self.inner.len() + } +} + +pub struct ObjectIterMut<'a> { + inner: std::collections::hash_map::IterMut<'a, String, PsbValueFixed>, +} + +impl<'a> ObjectIterMut<'a> { + pub fn empty() -> Self { + ObjectIterMut { + inner: Default::default(), + } + } +} + +impl<'a> Iterator for ObjectIterMut<'a> { + type Item = (&'a String, &'a mut PsbValueFixed); + + #[inline(always)] + fn next(&mut self) -> Option { + self.inner.next() + } +} + +impl<'a> ExactSizeIterator for ObjectIterMut<'a> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[derive(Clone, Debug)] +pub struct VirtualPsbFixed { + header: PsbHeader, + resources: Vec>, + extra: Vec>, + root: PsbObjectFixed, +} + +impl VirtualPsbFixed { + pub fn new( + header: PsbHeader, + resources: Vec>, + extra: Vec>, + root: PsbObjectFixed, + ) -> Self { + Self { + header, + resources, + extra, + root, + } + } + + pub fn header(&self) -> PsbHeader { + self.header + } + + pub fn resources(&self) -> &Vec> { + &self.resources + } + + pub fn resources_mut(&mut self) -> &mut Vec> { + &mut self.resources + } + + pub fn extra(&self) -> &Vec> { + &self.extra + } + + pub fn extra_mut(&mut self) -> &mut Vec> { + &mut self.extra + } + + pub fn root(&self) -> &PsbObjectFixed { + &self.root + } + + pub fn root_mut(&mut self) -> &mut PsbObjectFixed { + &mut self.root + } + + pub fn set_root(&mut self, root: PsbObjectFixed) { + self.root = root; + } + + pub fn unwrap(self) -> (PsbHeader, Vec>, Vec>, PsbObjectFixed) { + (self.header, self.resources, self.extra, self.root) + } + + pub fn to_psb(self) -> VirtualPsb { + let (header, resources, extra, root) = self.unwrap(); + VirtualPsb::new(header, resources, extra, root.to_psb()) + } +} + +pub trait VirtualPsbExt { + fn to_psb_fixed(self) -> VirtualPsbFixed; +} + +impl VirtualPsbExt for VirtualPsb { + fn to_psb_fixed(self) -> VirtualPsbFixed { + let (header, resources, extra, root) = self.unwrap(); + VirtualPsbFixed::new(header, resources, extra, root.to_psb_fixed()) + } +} diff --git a/src/scripts/kirikiri/scn.rs b/src/scripts/kirikiri/scn.rs index 3613941..13fed65 100644 --- a/src/scripts/kirikiri/scn.rs +++ b/src/scripts/kirikiri/scn.rs @@ -1,27 +1,13 @@ use crate::ext::io::*; +use crate::ext::psb::*; use crate::scripts::base::*; use crate::types::*; -use crate::utils::encoding::{decode_to_string, encode_string}; use anyhow::Result; -use emote_psb::types::PsbValue; -use emote_psb::types::collection::PsbObject; -use emote_psb::{PsbReader, PsbWriter, VirtualPsb}; -use json::JsonValue; -use serde::{Deserialize, Serialize}; +use emote_psb::{PsbReader, PsbWriter}; use std::collections::HashSet; -use std::io::{Read, Seek, Write}; +use std::io::{Read, Seek}; use std::path::Path; -trait JsonExt { - fn is_valid_str(&self) -> bool; -} - -impl JsonExt for JsonValue { - fn is_valid_str(&self) -> bool { - self.is_string() || self.is_null() - } -} - #[derive(Debug)] pub struct ScnScriptBuilder {} @@ -111,7 +97,7 @@ impl ScriptBuilder for ScnScriptBuilder { #[derive(Debug)] pub struct ScnScript { - psb: VirtualPsb, + psb: VirtualPsbFixed, language_index: usize, export_comumode: bool, filename: String, @@ -125,7 +111,7 @@ impl ScnScript { .load() .map_err(|e| anyhow::anyhow!("Failed to load PSB from {}: {:?}", filename, e))?; Ok(Self { - psb, + psb: psb.to_psb_fixed(), language_index: config.kirikiri_language_index.unwrap_or(0), export_comumode: config.kirikiri_export_comumode, filename: filename.to_string(), @@ -133,40 +119,6 @@ impl ScnScript { } } -#[derive(Debug, Serialize)] -pub struct PsbDataRef<'a> { - pub version: u16, - pub encryption: u16, - pub root: &'a emote_psb::types::collection::PsbObject, -} - -impl<'a> PsbDataRef<'a> { - pub fn new(psb: &'a VirtualPsb) -> Self { - let header = psb.header(); - Self { - version: header.version, - encryption: header.encryption, - root: psb.root(), - } - } -} - -#[derive(Debug, Deserialize)] -pub struct PsbData { - pub version: u16, - pub encryption: u16, - pub root: emote_psb::types::collection::PsbObject, -} - -impl PsbData { - pub fn header(&self) -> emote_psb::header::PsbHeader { - emote_psb::header::PsbHeader { - version: self.version, - encryption: self.encryption, - } - } -} - impl Script for ScnScript { fn default_output_script_type(&self) -> OutputScriptType { OutputScriptType::Json @@ -184,10 +136,10 @@ impl Script for ScnScript { let mut messages = Vec::new(); let root = self.psb.root(); let scenes = root - .get_value("scenes".into()) + .get_value("scenes") .ok_or(anyhow::anyhow!("scenes not found"))?; let scenes = match scenes { - PsbValue::List(list) => list, + PsbValueFixed::List(list) => list, _ => return Err(anyhow::anyhow!("scenes is not a list")), }; let mut comu = if self.export_comumode { @@ -197,26 +149,25 @@ impl Script for ScnScript { }; for (i, oscene) in scenes.iter().enumerate() { let scene = match oscene { - PsbValue::Object(obj) => obj, + PsbValueFixed::Object(obj) => obj, _ => return Err(anyhow::anyhow!("scene at index {} is not an object", i)), }; - if let Some(PsbValue::List(texts)) = scene.get_value("texts".into()) { + if let Some(PsbValueFixed::List(texts)) = scene.get_value("texts") { for (j, text) in texts.iter().enumerate() { - if let PsbValue::List(text) = text { + if let PsbValueFixed::List(text) = text { let values = text.values(); if values.len() <= 1 { continue; // Skip if there are not enough values } let name = &values[0]; let name = match name { - PsbValue::String(s) => Some(s), - PsbValue::Null => None, - PsbValue::None => None, + PsbValueFixed::String(s) => Some(s), + PsbValueFixed::Null => None, _ => return Err(anyhow::anyhow!("name is not a string or null")), }; let mut display_name; let mut message; - if matches!(values[1], PsbValue::List(_)) { + if matches!(values[1], PsbValueFixed::List(_)) { display_name = None; message = &values[1]; } else { @@ -224,9 +175,8 @@ impl Script for ScnScript { continue; // Skip if there is no message } display_name = match &values[1] { - PsbValue::String(s) => Some(s), - PsbValue::Null => None, - PsbValue::None => None, + PsbValueFixed::String(s) => Some(s), + PsbValueFixed::Null => None, _ => { return Err(anyhow::anyhow!( "display name is not a string or null at {i},{j}" @@ -235,19 +185,18 @@ impl Script for ScnScript { }; message = &values[2]; } - if matches!(message, PsbValue::List(_)) { + if matches!(message, PsbValueFixed::List(_)) { let tmp = message; - if let PsbValue::List(list) = tmp { + if let PsbValueFixed::List(list) = tmp { if list.len() > self.language_index { - if let PsbValue::List(data) = + if let PsbValueFixed::List(data) = &list.values()[self.language_index] { if data.len() >= 2 { let data = data.values(); display_name = match &data[0] { - PsbValue::String(s) => Some(s), - PsbValue::Null => None, - PsbValue::None => None, + PsbValueFixed::String(s) => Some(s), + PsbValueFixed::Null => None, _ => { return Err(anyhow::anyhow!( "display name is not a string or null at {i},{j}" @@ -260,7 +209,7 @@ impl Script for ScnScript { } } } - if let PsbValue::String(message) = message { + if let PsbValueFixed::String(message) = message { match name { Some(name) => { let name = match display_name { @@ -285,19 +234,17 @@ impl Script for ScnScript { } } } - if let Some(PsbValue::List(selects)) = scene.get_value("selects".into()) { + if let Some(PsbValueFixed::List(selects)) = scene.get_value("selects") { for select in selects.iter() { - if let PsbValue::Object(select) = select { + if let PsbValueFixed::Object(select) = select { let mut text = None; - if let Some(PsbValue::List(language)) = select.get_value("language".into()) - { + if let Some(PsbValueFixed::List(language)) = select.get_value("language") { if language.len() > self.language_index { let v = &language.values()[self.language_index]; - if let PsbValue::Object(v) = v { - text = match v.get_value("text".into()) { - Some(PsbValue::String(s)) => Some(s), - Some(PsbValue::Null) => None, - Some(PsbValue::None) => None, + if let PsbValueFixed::Object(v) = v { + text = match v.get_value("text") { + Some(PsbValueFixed::String(s)) => Some(s), + Some(PsbValueFixed::Null) => None, None => None, _ => { return Err(anyhow::anyhow!( @@ -309,10 +256,9 @@ impl Script for ScnScript { } } if text.is_none() { - text = match select.get_value("text".into()) { - Some(PsbValue::String(s)) => Some(s), - Some(PsbValue::Null) => None, - Some(PsbValue::None) => None, + text = match select.get_value("text") { + Some(PsbValueFixed::String(s)) => Some(s), + Some(PsbValueFixed::Null) => None, None => None, _ => { return Err(anyhow::anyhow!( @@ -372,11 +318,10 @@ impl Script for ScnScript { ) -> Result<()> { let mut mes = messages.iter(); let mut cur_mes = mes.next(); - // We use json library to process the PSB data, because emote-psb does not support update data. - let t = serde_json::to_string(&self.psb.root())?; - let mut root = json::parse(&t)?; + let mut psb = self.psb.clone(); + let root = psb.root_mut(); let scenes = &mut root["scenes"]; - if !scenes.is_array() { + if !scenes.is_list() { return Err(anyhow::anyhow!("scenes is not an array")); } for (i, scene) in scenes.members_mut().enumerate() { @@ -384,19 +329,19 @@ impl Script for ScnScript { return Err(anyhow::anyhow!("scene at {} is not an object", i)); } for text in scene["texts"].members_mut() { - if text.is_array() { + if text.is_list() { if text.len() <= 1 { continue; // Skip if there are not enough values } if cur_mes.is_none() { cur_mes = mes.next(); } - if !text[0].is_valid_str() { + if !text[0].is_string_or_null() { return Err(anyhow::anyhow!("name is not a string or null")); } let has_name = text[0].is_string(); let mut has_display_name; - if text[1].is_array() { + if text[1].is_list() { if text[1].is_string() { let m = match cur_mes.take() { Some(m) => m, @@ -412,7 +357,7 @@ impl Script for ScnScript { name = name.replace(key, value); } } - text[0] = json::JsonValue::String(name); + text[0].set_string(name); } else { return Err(anyhow::anyhow!("Name is missing for message.")); } @@ -423,13 +368,13 @@ impl Script for ScnScript { message = message.replace(key, value); } } - text[1] = json::JsonValue::String(message.replace("\n", "\\n")); - } else if text[1].is_array() { + text[1].set_string(message.replace("\n", "\\n")); + } else if text[1].is_list() { if text[1].len() > self.language_index - && text[1][self.language_index].is_array() + && text[1][self.language_index].is_list() && text[1][self.language_index].len() >= 2 { - if !text[1][self.language_index][0].is_valid_str() { + if !text[1][self.language_index][0].is_string_or_null() { return Err(anyhow::anyhow!( "display name is not a string or null" )); @@ -451,10 +396,9 @@ impl Script for ScnScript { } } if has_display_name { - text[1][self.language_index][0] = - json::JsonValue::String(name); + text[1][self.language_index][0].set_string(name); } else { - text[0] = json::JsonValue::String(name); + text[0].set_string(name); } } else { return Err(anyhow::anyhow!( @@ -468,8 +412,8 @@ impl Script for ScnScript { message = message.replace(key, value); } } - text[1][self.language_index][1] = - json::JsonValue::String(message.replace("\n", "\\n")); + text[1][self.language_index][1] + .set_string(message.replace("\n", "\\n")); } } } @@ -477,7 +421,7 @@ impl Script for ScnScript { if text.len() <= 2 { continue; // Skip if there is no message } - if !text[1].is_valid_str() { + if !text[1].is_string_or_null() { return Err(anyhow::anyhow!("display name is not a string or null")); } has_display_name = text[1].is_string(); @@ -497,9 +441,9 @@ impl Script for ScnScript { } } if has_display_name { - text[1] = json::JsonValue::String(name); + text[1].set_string(name); } else { - text[0] = json::JsonValue::String(name); + text[0].set_string(name); } } else { return Err(anyhow::anyhow!("Name is missing for message.")); @@ -511,13 +455,13 @@ impl Script for ScnScript { message = message.replace(key, value); } } - text[2] = json::JsonValue::String(message.replace("\n", "\\n")); - } else if text[2].is_array() { + text[2].set_string(message.replace("\n", "\\n")); + } else if text[2].is_list() { if text[2].len() > self.language_index - && text[2][self.language_index].is_array() + && text[2][self.language_index].is_list() && text[2][self.language_index].len() >= 2 { - if !text[2][self.language_index][0].is_valid_str() { + if !text[2][self.language_index][0].is_string_or_null() { return Err(anyhow::anyhow!( "display name is not a string or null" )); @@ -539,10 +483,9 @@ impl Script for ScnScript { } } if has_display_name { - text[2][self.language_index][0] = - json::JsonValue::String(name); + text[2][self.language_index][0].set_string(name); } else { - text[0] = json::JsonValue::String(name); + text[0].set_string(name); } } else { return Err(anyhow::anyhow!( @@ -556,8 +499,8 @@ impl Script for ScnScript { message = message.replace(key, value); } } - text[2][self.language_index][1] = - json::JsonValue::String(message.replace("\n", "\\n")); + text[2][self.language_index][1] + .set_string(message.replace("\n", "\\n")); } } } @@ -569,61 +512,11 @@ impl Script for ScnScript { if cur_mes.is_some() || mes.next().is_some() { return Err(anyhow::anyhow!("Some messages were not processed.")); } - let s = json::stringify(root); - let obj = serde_json::from_str::(&s)?; - let oheader = self.psb.header(); - let header = emote_psb::header::PsbHeader { - version: oheader.version, - encryption: oheader.encryption, - }; - let psb = VirtualPsb::new(header, Vec::new(), Vec::new(), obj); + let psb = psb.to_psb(); let writer = PsbWriter::new(psb, file); - writer - .finish() - .map_err(|e| anyhow::anyhow!("Failed to write PSB: {:?}", e))?; - Ok(()) - } - - fn custom_output_extension(&self) -> &'static str { - "json" - } - - fn custom_export(&self, filename: &Path, encoding: Encoding) -> Result<()> { - if !self.psb.resources().is_empty() { - eprintln!( - "Warning: The PSB contains resources, which may not be fully represented in the JSON output." - ); - crate::COUNTER.inc_warning(); - } - if !self.psb.extra().is_empty() { - eprintln!( - "Warning: The PSB contains extra data, which may not be fully represented in the JSON output." - ); - crate::COUNTER.inc_warning(); - } - let psb_data = PsbDataRef::new(&self.psb); - let str = serde_json::to_string_pretty(&psb_data)?; - let s = encode_string(encoding, &str, false)?; - let mut f = std::fs::File::create(filename)?; - f.write_all(&s)?; - Ok(()) - } - - fn custom_import<'a>( - &'a self, - custom_filename: &'a str, - file: Box, - encoding: Encoding, - _output_encoding: Encoding, - ) -> Result<()> { - let data = crate::utils::files::read_file(custom_filename)?; - let s = decode_to_string(encoding, &data)?; - let psb_data: PsbData = serde_json::from_str(&s)?; - let psb = VirtualPsb::new(psb_data.header(), Vec::new(), Vec::new(), psb_data.root); - let writer = PsbWriter::new(psb, file); - writer - .finish() - .map_err(|e| anyhow::anyhow!("Failed to write PSB: {:?}", e))?; + writer.finish().map_err(|e| { + anyhow::anyhow!("Failed to write PSB to file {}: {:?}", self.filename, e) + })?; Ok(()) } } @@ -640,16 +533,15 @@ impl ExportComuMes { } } - pub fn export(&mut self, value: &PsbValue) { + pub fn export(&mut self, value: &PsbValueFixed) { match value { - PsbValue::Object(obj) => { + PsbValueFixed::Object(obj) => { for (k, v) in obj.iter() { if k == "comumode" { - if let PsbValue::List(list) = v { + if let PsbValueFixed::List(list) = v { for item in list.iter() { - if let PsbValue::Object(obj) = item { - if let Some(PsbValue::String(s)) = obj.get_value("text".into()) - { + if let PsbValueFixed::Object(obj) = item { + if let Some(PsbValueFixed::String(s)) = obj.get_value("text") { self.messages.insert(s.string().replace("\\n", "\n")); } } @@ -660,15 +552,15 @@ impl ExportComuMes { } } } - PsbValue::List(list) => { + PsbValueFixed::List(list) => { let list = list.values(); if list.len() > 1 { - if let PsbValue::String(s) = &list[0] { + if let PsbValueFixed::String(s) = &list[0] { if s.string() == "comumode" { for i in 1..list.len() { - if let PsbValue::String(s) = &list[i - 1] { + if let PsbValueFixed::String(s) = &list[i - 1] { if s.string() == "text" { - if let PsbValue::String(text) = &list[i] { + if let PsbValueFixed::String(text) = &list[i] { self.messages .insert(text.string().replace("\\n", "\n")); }