mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-16 18:14:19 +08:00
Add support for Yu-Ris YSTL(file list) file (.ybn)
This commit is contained in:
215
Cargo.lock
generated
215
Cargo.lock
generated
@@ -46,6 +46,15 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
@@ -330,6 +339,20 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.5.1"
|
||||
@@ -474,6 +497,12 @@ dependencies = [
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpubits"
|
||||
version = "0.1.1"
|
||||
@@ -923,6 +952,30 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -1069,6 +1122,30 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.2.0"
|
||||
@@ -1325,6 +1402,18 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json"
|
||||
version = "0.12.4"
|
||||
@@ -1534,6 +1623,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"cbc",
|
||||
"chacha20",
|
||||
"chrono",
|
||||
"clap 4.6.1",
|
||||
"crc32fast",
|
||||
"crossbeam",
|
||||
@@ -1661,6 +1751,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
@@ -1824,6 +1923,12 @@ dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.33"
|
||||
@@ -2051,6 +2156,12 @@ version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.23"
|
||||
@@ -2202,6 +2313,12 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
@@ -2594,6 +2711,51 @@ dependencies = [
|
||||
"wit-bindgen 0.51.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.244.0"
|
||||
@@ -2680,12 +2842,65 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
||||
@@ -18,6 +18,7 @@ byteorder = { version = "1.5", default-features = false, optional = true}
|
||||
bytes = { version = "1.11", optional = true }
|
||||
cbc = { version = "0.2", optional = true }
|
||||
chacha20 = { version = "0.10", optional = true }
|
||||
chrono = { version = "0.4", optional = true, features = ["serde"] }
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
crc32fast = { version = "1.5", optional = true }
|
||||
crossbeam = { version = "0.8", optional = true }
|
||||
@@ -118,7 +119,7 @@ will-plus = ["utils-str"]
|
||||
will-plus-img = ["will-plus", "image"]
|
||||
yaneurao = []
|
||||
yaneurao-itufuru = ["yaneurao", "utils-xored-stream"]
|
||||
yuris = ["dep:hex", "utils-serde-base64bytes", "utils-xored-stream"]
|
||||
yuris = ["dep:chrono", "dep:hex", "utils-serde-base64bytes", "utils-xored-stream"]
|
||||
yuris-img = ["yuris", "image", "qoi", "webp"]
|
||||
# basic feature
|
||||
image = ["dep:png"]
|
||||
|
||||
@@ -271,6 +271,7 @@ msg-tool create -t <script-type> <input> <output>
|
||||
| `yuris-yscfg` | `yuris` | Yu-Ris YSCFG(config) file (.ybn) | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | ✔️ | |
|
||||
| `yuris-ystb` | `yuris` | Yu-Ris YSTB(compiled script) file (.ybn) | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | ❌ | |
|
||||
| `yuris-txt` | `yuris` | Yu-Ris scenario text file (.txt) | ✔️ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | |
|
||||
| `yuris-ystl` | `yuris` | Yu-Ris YSTL(file list) file (.ybn) | ❌ | ❌ | ❌ | ❌ | ✔️ | ✔️ | ✔️ | |
|
||||
|
||||
| Image Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Create | Remarks |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
|
||||
@@ -188,6 +188,8 @@ lazy_static::lazy_static! {
|
||||
Box::new(yuris::txt::YurisTxtBuilder::new()),
|
||||
#[cfg(feature = "yuris-img")]
|
||||
Box::new(yuris::img::ydg::YDGImageBuilder::new()),
|
||||
#[cfg(feature = "yuris")]
|
||||
Box::new(yuris::ystl::YSTLBuilder::new()),
|
||||
];
|
||||
/// A list of all script extensions.
|
||||
pub static ref ALL_EXTS: Vec<String> =
|
||||
|
||||
@@ -7,3 +7,4 @@ pub mod yscfg;
|
||||
pub mod yscm;
|
||||
pub mod yser;
|
||||
pub mod ystb;
|
||||
pub mod ystl;
|
||||
|
||||
347
src/scripts/yuris/ystl.rs
Normal file
347
src/scripts/yuris/ystl.rs
Normal file
@@ -0,0 +1,347 @@
|
||||
//! Yu-Ris YSTL(file list) file (.ybn)
|
||||
use crate::ext::io::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use crate::utils::struct_pack::*;
|
||||
use anyhow::Result;
|
||||
use chrono::TimeZone;
|
||||
use chrono::Timelike;
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
use msg_tool_macro::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct YSTLData {
|
||||
version: u32,
|
||||
entries: Vec<YSTLEntry>,
|
||||
}
|
||||
|
||||
impl StructUnpack for YSTLData {
|
||||
fn unpack<R: Read + Seek>(
|
||||
reader: &mut R,
|
||||
big: bool,
|
||||
encoding: Encoding,
|
||||
info: &Option<Box<dyn Any>>,
|
||||
) -> Result<Self> {
|
||||
let version = u32::unpack(reader, big, encoding, info)?;
|
||||
let ninfo = Box::new(version) as Box<dyn Any>;
|
||||
let count = u32::unpack(reader, big, encoding, info)?;
|
||||
let entries = reader.read_struct_vec(count as usize, big, encoding, &Some(ninfo))?;
|
||||
Ok(Self { version, entries })
|
||||
}
|
||||
}
|
||||
|
||||
impl StructPack for YSTLData {
|
||||
fn pack<W: Write>(
|
||||
&self,
|
||||
writer: &mut W,
|
||||
big: bool,
|
||||
encoding: Encoding,
|
||||
info: &Option<Box<dyn Any>>,
|
||||
) -> Result<()> {
|
||||
self.version.pack(writer, big, encoding, info)?;
|
||||
let ninfo = Box::new(self.version) as Box<dyn Any>;
|
||||
let count = self.entries.len() as u32;
|
||||
count.pack(writer, big, encoding, info)?;
|
||||
let info = &Some(ninfo);
|
||||
for (i, entry) in self.entries.iter().enumerate() {
|
||||
if entry.seq == i as u32 {
|
||||
entry.pack(writer, big, encoding, info)?;
|
||||
} else {
|
||||
let mut entry = entry.clone();
|
||||
entry.seq = i as u32;
|
||||
entry.pack(writer, big, encoding, info)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct FileSystemTime(DateTime<Local>);
|
||||
|
||||
impl Deref for FileSystemTime {
|
||||
type Target = DateTime<Local>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for FileSystemTime {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FileSystemTime {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl StructUnpack for FileSystemTime {
|
||||
fn unpack<R: Read + Seek>(
|
||||
reader: &mut R,
|
||||
big: bool,
|
||||
encoding: Encoding,
|
||||
info: &Option<Box<dyn std::any::Any>>,
|
||||
) -> Result<Self> {
|
||||
let high = u32::unpack(reader, big, encoding, info)?;
|
||||
let low = u32::unpack(reader, big, encoding, info)?;
|
||||
let time = low as u64 | ((high as u64) << 32);
|
||||
const FILETIME_OFFSET: u64 = 116_444_736_000_000_000;
|
||||
if time < FILETIME_OFFSET {
|
||||
anyhow::bail!("Time to small.");
|
||||
}
|
||||
let intervals_since_1970 = time - FILETIME_OFFSET;
|
||||
let seconds = (intervals_since_1970 / 10_000_000) as i64;
|
||||
let nsecs = ((intervals_since_1970 % 10_000_000) * 100) as u32;
|
||||
let time = Utc
|
||||
.timestamp_opt(seconds, nsecs)
|
||||
.single()
|
||||
.ok_or_else(|| anyhow::anyhow!("Time is not existed or ambiguous."))?;
|
||||
let time = time.with_timezone(&Local);
|
||||
Ok(Self(time))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructPack for FileSystemTime {
|
||||
fn pack<W: Write>(
|
||||
&self,
|
||||
writer: &mut W,
|
||||
big: bool,
|
||||
encoding: Encoding,
|
||||
info: &Option<Box<dyn std::any::Any>>,
|
||||
) -> Result<()> {
|
||||
let time = self.0.with_timezone(&Utc);
|
||||
let tseconds = time.timestamp();
|
||||
let nsecs = time.nanosecond() / 100;
|
||||
const FILETIME_OFFSET: u64 = 116_444_736_000_000_000;
|
||||
let seconds = (tseconds as u64)
|
||||
.checked_mul(10_000_000)
|
||||
.ok_or_else(|| anyhow::anyhow!("Too big time"))?
|
||||
.checked_add(nsecs as u64)
|
||||
.ok_or_else(|| anyhow::anyhow!("Too big time"))?
|
||||
.checked_add(FILETIME_OFFSET)
|
||||
.ok_or_else(|| anyhow::anyhow!("Too big time"))?;
|
||||
let high = (seconds >> 32) as u32;
|
||||
let low = seconds as u32;
|
||||
high.pack(writer, big, encoding, info)?;
|
||||
low.pack(writer, big, encoding, info)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, StructUnpack, StructPack)]
|
||||
struct YSTLEntry {
|
||||
seq: u32,
|
||||
#[pstring(u32)]
|
||||
path: String,
|
||||
modification_time: FileSystemTime,
|
||||
num_variables: u32,
|
||||
num_labels: u32,
|
||||
// TODO: version may need more check
|
||||
#[skip_pack_if(get_info_as_version(__info)? < 300)]
|
||||
#[skip_unpack_if(get_info_as_version(__info)? < 300)]
|
||||
num_texts: u32,
|
||||
}
|
||||
|
||||
fn get_info_as_version(info: &Option<Box<dyn Any>>) -> Result<u32> {
|
||||
Ok(*info
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow::anyhow!("info not found"))?
|
||||
.downcast_ref()
|
||||
.ok_or_else(|| anyhow::anyhow!("not YSTBHeader"))?)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct YSTLBuilder {}
|
||||
|
||||
impl YSTLBuilder {
|
||||
/// Creates a new instance of `YSTLBuilder`
|
||||
pub const fn new() -> Self {
|
||||
YSTLBuilder {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptBuilder for YSTLBuilder {
|
||||
fn default_encoding(&self) -> Encoding {
|
||||
Encoding::Cp932
|
||||
}
|
||||
|
||||
fn build_script(
|
||||
&self,
|
||||
buf: Vec<u8>,
|
||||
_filename: &str,
|
||||
encoding: Encoding,
|
||||
_archive_encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
_archive: Option<&Box<dyn Script>>,
|
||||
) -> Result<Box<dyn Script + Send + Sync>> {
|
||||
Ok(Box::new(YSTL::new(MemReader::new(buf), encoding, config)?))
|
||||
}
|
||||
|
||||
fn extensions(&self) -> &'static [&'static str] {
|
||||
&["ybn"]
|
||||
}
|
||||
|
||||
fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||
if buf_len >= 4 && buf.starts_with(b"YSTL") {
|
||||
return Some(20);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn script_type(&self) -> &'static ScriptType {
|
||||
&ScriptType::YurisYSTL
|
||||
}
|
||||
|
||||
fn can_create_file(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn create_file<'a>(
|
||||
&'a self,
|
||||
filename: &'a str,
|
||||
writer: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
file_encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<()> {
|
||||
create_file(
|
||||
filename,
|
||||
writer,
|
||||
encoding,
|
||||
file_encoding,
|
||||
config.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct YSTL {
|
||||
data: YSTLData,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl YSTL {
|
||||
pub fn new<T: Read + Seek>(
|
||||
mut reader: T,
|
||||
encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
) -> Result<Self> {
|
||||
let mut sig = [0; 4];
|
||||
reader.read_exact(&mut sig)?;
|
||||
if &sig != b"YSTL" {
|
||||
anyhow::bail!("Unsupported YSTL file.");
|
||||
}
|
||||
let data = YSTLData::unpack(&mut reader, false, encoding, &None)?;
|
||||
Ok(Self {
|
||||
data,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for YSTL {
|
||||
fn default_output_script_type(&self) -> OutputScriptType {
|
||||
OutputScriptType::Custom
|
||||
}
|
||||
|
||||
fn is_output_supported(&self, output: OutputScriptType) -> bool {
|
||||
matches!(output, OutputScriptType::Custom)
|
||||
}
|
||||
|
||||
fn default_format_type(&self) -> FormatOptions {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn custom_output_extension(&self) -> &'static str {
|
||||
if self.custom_yaml { "yaml" } else { "json" }
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
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_pretty(&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)?;
|
||||
writer.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_import<'a>(
|
||||
&'a self,
|
||||
custom_filename: &'a str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
create_file(
|
||||
custom_filename,
|
||||
file,
|
||||
encoding,
|
||||
output_encoding,
|
||||
self.custom_yaml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_file<'a>(
|
||||
custom_filename: &'a str,
|
||||
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 mut data: YSTLData = 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"YSTL")?;
|
||||
writer.write_u32(data.version)?;
|
||||
writer.write_u32(data.entries.len() as u32)?;
|
||||
let info = Box::new(data.version) as Box<dyn Any>;
|
||||
let info = &Some(info);
|
||||
for (i, entry) in data.entries.iter_mut().enumerate() {
|
||||
entry.seq = i as u32;
|
||||
entry.pack(&mut writer, false, encoding, info)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_unpack_file_system_time() {
|
||||
let mut reader = MemReaderRef::new(b" \x0c\xd8\x01\x00k`\xdd");
|
||||
let ts = FileSystemTime::unpack(&mut reader, false, Encoding::Cp932, &None).unwrap();
|
||||
println!("{}", ts);
|
||||
let utc = ts.to_utc();
|
||||
let t = serde_json::to_string(&utc).unwrap();
|
||||
assert_eq!(t, "\"2022-01-18T04:07:10Z\"");
|
||||
}
|
||||
#[test]
|
||||
fn test_pack_file_system_time() {
|
||||
let ts: FileSystemTime = serde_json::from_str("\"2022-01-18T13:07:10+09:00\"").unwrap();
|
||||
let mut buf = [0; 8];
|
||||
let mut writer = MemWriterRef::new(&mut buf);
|
||||
ts.pack(&mut writer, false, Encoding::Cp932, &None).unwrap();
|
||||
assert_eq!(&buf, b" \x0c\xd8\x01\x00k`\xdd");
|
||||
}
|
||||
}
|
||||
@@ -929,6 +929,8 @@ pub enum ScriptType {
|
||||
#[cfg(feature = "yuris")]
|
||||
/// Yu-Ris scenario text file (.txt)
|
||||
YurisTxt,
|
||||
/// Yu-Ris YSTL(file list) file (.ybn)
|
||||
YurisYSTL,
|
||||
#[cfg(feature = "yuris-img")]
|
||||
/// YU-RIS compressed image file (.ydg)
|
||||
YurisYDG,
|
||||
|
||||
Reference in New Issue
Block a user