mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-08 05:48:46 +08:00
Use custom json serde method to import/export psb
This commit is contained in:
134
src/ext/psb.rs
134
src/ext/psb.rs
@@ -5,6 +5,8 @@ use emote_psb::types::number::*;
|
||||
use emote_psb::types::reference::*;
|
||||
use emote_psb::types::string::*;
|
||||
use emote_psb::types::*;
|
||||
#[cfg(feature = "json")]
|
||||
use json::JsonValue;
|
||||
use std::cmp::PartialEq;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::{Index, IndexMut};
|
||||
@@ -163,6 +165,89 @@ impl PsbValueFixed {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn to_json(&self) -> Option<JsonValue> {
|
||||
match self {
|
||||
PsbValueFixed::Null => Some(JsonValue::Null),
|
||||
PsbValueFixed::Bool(b) => Some(JsonValue::Boolean(*b)),
|
||||
PsbValueFixed::Number(n) => match n {
|
||||
PsbNumber::Integer(i) => Some(JsonValue::Number((*i).into())),
|
||||
PsbNumber::Float(f) => Some(JsonValue::Number((*f).into())),
|
||||
PsbNumber::Double(d) => Some(JsonValue::Number((*d).into())),
|
||||
},
|
||||
PsbValueFixed::String(s) => Some(JsonValue::String(s.string().to_owned())),
|
||||
PsbValueFixed::Resource(s) => {
|
||||
Some(JsonValue::String(format!("resource#{}", s.resource_ref)))
|
||||
}
|
||||
PsbValueFixed::ExtraResource(s) => Some(JsonValue::String(format!(
|
||||
"extra_resource#{}",
|
||||
s.extra_resource_ref
|
||||
))),
|
||||
PsbValueFixed::IntArray(arr) => Some(JsonValue::Array(
|
||||
arr.iter().map(|n| JsonValue::Number((*n).into())).collect(),
|
||||
)),
|
||||
PsbValueFixed::List(l) => Some(l.to_json()),
|
||||
PsbValueFixed::Object(o) => Some(o.to_json()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn from_json(obj: &JsonValue) -> Self {
|
||||
match obj {
|
||||
JsonValue::Null => PsbValueFixed::Null,
|
||||
JsonValue::Boolean(b) => PsbValueFixed::Bool(*b),
|
||||
JsonValue::Number(n) => {
|
||||
let data: f64 = (*n).into();
|
||||
if data.fract() == 0.0 {
|
||||
PsbValueFixed::Number(PsbNumber::Integer(data as i64))
|
||||
} else {
|
||||
PsbValueFixed::Number(PsbNumber::Float(data as f32))
|
||||
}
|
||||
}
|
||||
JsonValue::String(s) => {
|
||||
if s.starts_with("resource#") {
|
||||
if let Ok(id) = s[9..].parse::<u64>() {
|
||||
return PsbValueFixed::Resource(PsbResourceRef { resource_ref: id });
|
||||
}
|
||||
} else if s.starts_with("extra_resource#") {
|
||||
if let Ok(id) = s[16..].parse::<u64>() {
|
||||
return PsbValueFixed::ExtraResource(PsbExtraRef {
|
||||
extra_resource_ref: id,
|
||||
});
|
||||
}
|
||||
}
|
||||
PsbValueFixed::String(PsbString::from(s.clone()))
|
||||
}
|
||||
JsonValue::Array(arr) => {
|
||||
let values: Vec<PsbValueFixed> = arr.iter().map(PsbValueFixed::from_json).collect();
|
||||
PsbValueFixed::List(PsbListFixed { values })
|
||||
}
|
||||
JsonValue::Object(obj) => {
|
||||
let mut values = HashMap::new();
|
||||
for (key, value) in obj.iter() {
|
||||
values.insert(key.to_owned(), PsbValueFixed::from_json(value));
|
||||
}
|
||||
PsbValueFixed::Object(PsbObjectFixed { values })
|
||||
}
|
||||
JsonValue::Short(n) => {
|
||||
let s = n.as_str();
|
||||
if s.starts_with("resource#") {
|
||||
if let Ok(id) = s[9..].parse::<u64>() {
|
||||
return PsbValueFixed::Resource(PsbResourceRef { resource_ref: id });
|
||||
}
|
||||
} else if s.starts_with("extra_resource#") {
|
||||
if let Ok(id) = s[16..].parse::<u64>() {
|
||||
return PsbValueFixed::ExtraResource(PsbExtraRef {
|
||||
extra_resource_ref: id,
|
||||
});
|
||||
}
|
||||
}
|
||||
PsbValueFixed::String(PsbString::from(s.to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for PsbValueFixed {
|
||||
@@ -351,6 +436,12 @@ impl PsbListFixed {
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
let data: Vec<_> = self.values.iter().filter_map(|v| v.to_json()).collect();
|
||||
JsonValue::Array(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for PsbListFixed {
|
||||
@@ -484,6 +575,26 @@ impl PsbObjectFixed {
|
||||
inner: self.values.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
let mut obj = json::object::Object::new();
|
||||
for (key, value) in &self.values {
|
||||
if let Some(json_value) = value.to_json() {
|
||||
obj.insert(key, json_value);
|
||||
}
|
||||
}
|
||||
JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn from_json(obj: &JsonValue) -> Self {
|
||||
let mut values = HashMap::new();
|
||||
for (key, value) in obj.entries() {
|
||||
values.insert(key.to_owned(), PsbValueFixed::from_json(value));
|
||||
}
|
||||
PsbObjectFixed { values }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Index<&'a str> for PsbObjectFixed {
|
||||
@@ -658,6 +769,29 @@ impl VirtualPsbFixed {
|
||||
let (header, resources, extra, root) = self.unwrap();
|
||||
VirtualPsb::new(header, resources, extra, root.to_psb())
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn from_json(&mut self, obj: &JsonValue) -> Result<(), anyhow::Error> {
|
||||
let version = obj["version"]
|
||||
.as_u16()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid PSB version"))?;
|
||||
let encryption = obj["encryption"]
|
||||
.as_u16()
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid PSB encryption"))?;
|
||||
self.header.version = version;
|
||||
self.header.encryption = encryption;
|
||||
self.root = PsbObjectFixed::from_json(&obj["data"]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "json")]
|
||||
pub fn to_json(&self) -> JsonValue {
|
||||
json::object! {
|
||||
"version": self.header.version,
|
||||
"encryption": self.header.encryption,
|
||||
"data": self.root.to_json(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VirtualPsbExt {
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::ext::io::*;
|
||||
use crate::ext::psb::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use anyhow::Result;
|
||||
use emote_psb::{PsbReader, PsbWriter};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -131,6 +132,10 @@ impl Script for ScnScript {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn is_output_supported(&self, _: OutputScriptType) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
let mut messages = Vec::new();
|
||||
let root = self.psb.root();
|
||||
@@ -566,6 +571,34 @@ impl Script for ScnScript {
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &Path, encoding: Encoding) -> Result<()> {
|
||||
let s = 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)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_import<'a>(
|
||||
&'a self,
|
||||
custom_filename: &'a str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
let data = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &data)?;
|
||||
let json = json::parse(&s)?;
|
||||
let mut psb = self.psb.clone();
|
||||
psb.from_json(&json)?;
|
||||
let psb = 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)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
Reference in New Issue
Block a user