Add document

This commit is contained in:
2025-08-10 22:35:11 +08:00
parent 964045b07f
commit 6c0b1a1258
25 changed files with 314 additions and 26 deletions

View File

@@ -1,3 +1,4 @@
//! Kirikiri DPAK-referenced Image File (.dref)
use crate::ext::io::*;
use crate::ext::psb::*;
use crate::scripts::base::*;
@@ -12,9 +13,11 @@ use std::path::{Path, PathBuf};
use url::Url;
#[derive(Debug)]
/// Kirikiri DREF Script Builder
pub struct DrefBuilder {}
impl DrefBuilder {
/// Creates a new instance of `DrefBuilder`
pub fn new() -> Self {
Self {}
}
@@ -174,6 +177,7 @@ impl DpakLoader {
}
}
/// Kirikiri DREF Script
pub struct Dref {
urls: Vec<Url>,
dir: PathBuf,
@@ -190,6 +194,13 @@ impl std::fmt::Debug for Dref {
}
impl Dref {
/// Create a new dref script
///
/// * `buf` - The buffer containing the dref script data
/// * `encoding` - The encoding of the script
/// * `filename` - The name of the file
/// * `config` - Extra configuration options
/// * `archive` - Optional archive containing additional resources
pub fn new(
buf: Vec<u8>,
encoding: Encoding,

View File

@@ -1,3 +1,4 @@
//! Kirikiri Images
pub mod dref;
pub mod pimg;
pub mod tlg;

View File

@@ -1,3 +1,4 @@
//! Kirikiri Multiple Image File (.pimg)
use crate::ext::io::*;
use crate::ext::psb::*;
use crate::scripts::base::*;
@@ -12,9 +13,11 @@ use std::io::{Read, Seek};
use std::path::Path;
#[derive(Debug)]
/// Kirikiri PImg Script Builder
pub struct PImgBuilder {}
impl PImgBuilder {
/// Creates a new instance of `PImgBuilder`
pub const fn new() -> Self {
Self {}
}
@@ -94,12 +97,18 @@ impl ScriptBuilder for PImgBuilder {
}
#[derive(Debug)]
/// Kirikiri PImg Script
pub struct PImg {
psb: VirtualPsbFixed,
overlay: Option<bool>,
}
impl PImg {
/// Create a new PImg script
///
/// * `reader` - The reader containing the PImg script data
/// * `filename` - The name of the file
/// * `config` - Extra configuration options
pub fn new<R: Read + Seek>(reader: R, filename: &str, config: &ExtraConfig) -> Result<Self> {
let mut psb = PsbReader::open_psb(reader)
.map_err(|e| anyhow::anyhow!("Failed to open PSB from {}: {:?}", filename, e))?;

View File

@@ -1,3 +1,4 @@
//! Kirikiri TLG Image File (.tlg)
use crate::ext::io::*;
use crate::scripts::base::*;
use crate::types::*;
@@ -6,9 +7,11 @@ use libtlg_rs::*;
use std::io::{Read, Seek};
#[derive(Debug)]
/// Kirikiri TLG Script Builder
pub struct TlgImageBuilder {}
impl TlgImageBuilder {
/// Creates a new instance of `TlgImageBuilder`
pub const fn new() -> Self {
TlgImageBuilder {}
}
@@ -54,11 +57,16 @@ impl ScriptBuilder for TlgImageBuilder {
}
#[derive(Debug)]
/// Kirikiri TLG Script
pub struct TlgImage {
data: Tlg,
}
impl TlgImage {
/// Create a new TLG script
///
/// * `data` - The reader containing the TLG script data
/// * `config` - Extra configuration options
pub fn new<T: Read + Seek>(data: T, _config: &ExtraConfig) -> Result<Self> {
let tlg = load_tlg(data)?;
Ok(TlgImage { data: tlg })

View File

@@ -1,3 +1,4 @@
//! Kirikiri Script File (.ks)
use crate::ext::fancy_regex::*;
use crate::scripts::base::*;
use crate::types::*;
@@ -11,9 +12,11 @@ use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::sync::Arc;
#[derive(Debug)]
/// Kirikiri Script Builder
pub struct KsBuilder {}
impl KsBuilder {
/// Creates a new instance of `KsBuilder`
pub fn new() -> Self {
Self {}
}
@@ -45,12 +48,15 @@ impl ScriptBuilder for KsBuilder {
}
}
trait Node {
/// Kirikiri Script Node Trait
pub trait Node {
/// Serializes the node to ks format
fn serialize(&self) -> String;
}
#[derive(Clone, Debug)]
struct CommentNode(String);
/// Comment Node
pub struct CommentNode(pub String);
impl Node for CommentNode {
fn serialize(&self) -> String {
@@ -59,9 +65,12 @@ impl Node for CommentNode {
}
#[derive(Clone, Debug)]
struct LabelNode {
name: String,
page: Option<String>,
/// Label Node
pub struct LabelNode {
/// The name of the label
pub name: String,
/// The page of the label
pub page: Option<String>,
}
impl Node for LabelNode {
@@ -75,7 +84,8 @@ impl Node for LabelNode {
}
#[derive(Clone, Debug)]
struct TextNode(String);
/// Text Node
pub struct TextNode(pub String);
impl Node for TextNode {
fn serialize(&self) -> String {
@@ -85,7 +95,8 @@ impl Node for TextNode {
}
#[derive(Clone, Debug)]
struct EmptyLineNode;
/// Empty Line Node
pub struct EmptyLineNode;
impl Node for EmptyLineNode {
fn serialize(&self) -> String {
@@ -94,15 +105,21 @@ impl Node for EmptyLineNode {
}
#[derive(Clone, Debug)]
enum TagAttr {
/// Represents a tag attribute's value
pub enum TagAttr {
/// true if no value is specified
True,
/// String value of the attribute
Str(String),
}
#[derive(Clone, Debug)]
struct TagNode {
name: String,
attributes: Vec<(String, TagAttr)>,
/// Tag Node
pub struct TagNode {
/// The name of the tag
pub name: String,
/// The attributes of the tag
pub attributes: Vec<(String, TagAttr)>,
}
impl TagNode {
@@ -140,6 +157,7 @@ impl TagNode {
parts.join(" ")
}
/// Sets an attribute for the tag, replacing it if it already exists.
pub fn set_attr(&mut self, key: &str, value: String) {
if let Some(attr) = self.attributes.iter_mut().find(|(k, _)| k == key) {
attr.1 = TagAttr::Str(value);
@@ -170,8 +188,10 @@ impl Node for TagNode {
}
#[derive(Clone)]
struct CommandNode {
inner: TagNode,
/// Command Node
pub struct CommandNode {
/// Same as TagNode, but used for commands
pub inner: TagNode,
}
impl Deref for CommandNode {
@@ -209,7 +229,8 @@ impl Node for CommandNode {
}
#[derive(Clone, Debug)]
struct ScriptBlockNode(String);
/// Script Block Node
pub struct ScriptBlockNode(pub String);
impl Node for ScriptBlockNode {
fn serialize(&self) -> String {
@@ -218,8 +239,11 @@ impl Node for ScriptBlockNode {
}
#[derive(Clone, Debug)]
enum ParsedLineNode {
/// Parsed Line Node
pub enum ParsedLineNode {
/// Text node containing plain text
Text(TextNode),
/// Tag node
Tag(TagNode),
}
@@ -252,7 +276,8 @@ impl Node for ParsedLineNode {
}
#[derive(Clone, Debug)]
struct ParsedLine(Vec<ParsedLineNode>);
/// Parsed Line
pub struct ParsedLine(pub Vec<ParsedLineNode>);
impl ParsedLine {
fn to_xml(&self) -> String {
@@ -289,20 +314,29 @@ impl Node for ParsedLine {
}
#[derive(Clone, Debug)]
enum ParsedScriptNode {
/// Parsed Script Node
pub enum ParsedScriptNode {
/// Comment node
Comment(CommentNode),
/// Label node
Label(LabelNode),
/// Command node
Command(CommandNode),
/// Script block node
ScriptBlock(ScriptBlockNode),
/// Line
Line(ParsedLine),
/// Empty line node
EmptyLine(EmptyLineNode),
}
impl ParsedScriptNode {
/// Returns true if the node is empty line node
pub fn is_empty(&self) -> bool {
matches!(self, ParsedScriptNode::EmptyLine(_))
}
/// Sets an attribute for the command node, replacing it if it already exists.
pub fn set_attr(&mut self, key: &str, value: String) {
if let ParsedScriptNode::Command(command) = self {
command.set_attr(key, value);
@@ -324,7 +358,8 @@ impl Node for ParsedScriptNode {
}
#[derive(Clone, Debug)]
struct ParsedScript(Vec<ParsedScriptNode>);
/// Parsed ks script
pub struct ParsedScript(pub Vec<ParsedScriptNode>);
impl Deref for ParsedScript {
type Target = Vec<ParsedScriptNode>;
@@ -374,11 +409,15 @@ lazy_static::lazy_static! {
static ref ATTR_RE: Regex = Regex::new("([a-zA-Z0-9_]+)(?:=(\"[^\"]*\"|'[^']*'|[^\\s\\]]+))?").unwrap();
}
struct Parser {
/// Parser for Kirikiri Script (.ks)
pub struct Parser {
lines: Vec<String>,
}
impl Parser {
/// Creates a new parser for the given script
///
/// * `script` - The script to parse
pub fn new(script: &str) -> Self {
let lines = script.lines().map(|s| s.to_string()).collect();
Self { lines }
@@ -422,7 +461,10 @@ impl Parser {
})
}
fn parse(&self, preserve_empty_lines: bool) -> Result<ParsedScript> {
/// Parses the script and returns a `ParsedScript`
///
/// * `preserve_empty_lines` - If true, empty lines will be preserved in the parsed script
pub fn parse(&self, preserve_empty_lines: bool) -> Result<ParsedScript> {
let mut parsed_scripts = Vec::new();
let mut in_script_block = false;
let mut script_buffer = Vec::new();
@@ -657,6 +699,7 @@ impl XMLTextParser {
}
#[derive(Debug)]
/// Kirikiri Script
pub struct KsScript {
bom: BomType,
tree: ParsedScript,
@@ -666,6 +709,11 @@ pub struct KsScript {
}
impl KsScript {
/// Creates a new `KsScript` from the given reader and encoding
///
/// * `reader` - The reader containing the script data
/// * `encoding` - The encoding of the script
/// * `config` - Extra configuration options
pub fn new(reader: Vec<u8>, encoding: Encoding, config: &ExtraConfig) -> Result<Self> {
let (text, bom) = decode_with_bom_detect(encoding, &reader, true)?;
let parser = Parser::new(&text);

View File

@@ -1,3 +1,4 @@
//! Kirikiri Zlib-Compressed File
use crate::ext::io::*;
use crate::scripts::base::*;
use crate::types::*;
@@ -5,9 +6,11 @@ use anyhow::Result;
use std::io::Read;
#[derive(Debug)]
/// Kirikiri MDF Script Builder
pub struct MdfBuilder {}
impl MdfBuilder {
/// Creates a new instance of `MdfBuilder`
pub fn new() -> Self {
Self {}
}
@@ -48,12 +51,17 @@ impl ScriptBuilder for MdfBuilder {
}
#[derive(Debug)]
/// Kirikiri MDF Script
pub struct Mdf {
data: MemReader,
ext: String,
}
impl Mdf {
/// Creates a new `Mdf` script from the given buffer and filename
///
/// * `buf` - The buffer containing the MDF data
/// * `filename` - The name of the file (used for extension detection)
pub fn new(buf: Vec<u8>, filename: &str) -> Result<Self> {
let mut data = MemReader::new(buf);
let mut header = [0u8; 4];
@@ -71,7 +79,7 @@ impl Mdf {
})
}
pub fn unpack(mut data: MemReaderRef) -> Result<Vec<u8>> {
pub(crate) fn unpack(mut data: MemReaderRef) -> Result<Vec<u8>> {
let size = data.read_u32()?;
let mut decoder = flate2::read::ZlibDecoder::new(data);
let mut result = Vec::new();

View File

@@ -1,3 +1,4 @@
//! Kirikiri Scripts
#[cfg(feature = "kirikiri-img")]
pub mod image;
pub mod ks;
@@ -7,6 +8,7 @@ pub mod simple_crypt;
use std::collections::HashMap;
use std::sync::Arc;
/// Read a Kirikiri Comu JSON file. (For CIRCUS games)
pub fn read_kirikiri_comu_json(path: &str) -> anyhow::Result<Arc<HashMap<String, String>>> {
let mut reader = std::fs::File::open(path)?;
let data = serde_json::from_reader(&mut reader)?;

View File

@@ -1,3 +1,4 @@
//! Kirikiri Scene File (.scn)
use super::mdf::Mdf;
use crate::ext::io::*;
use crate::ext::psb::*;
@@ -12,9 +13,11 @@ use std::path::Path;
use std::sync::Arc;
#[derive(Debug)]
/// Kirikiri Scene Script Builder
pub struct ScnScriptBuilder {}
impl ScnScriptBuilder {
/// Creates a new instance of `ScnScriptBuilder`
pub fn new() -> Self {
Self {}
}
@@ -102,6 +105,7 @@ impl ScriptBuilder for ScnScriptBuilder {
}
#[derive(Debug)]
/// Kirikiri Scene Script
pub struct ScnScript {
psb: VirtualPsbFixed,
language_index: usize,
@@ -111,6 +115,11 @@ pub struct ScnScript {
}
impl ScnScript {
/// Creates a new `ScnScript` from the given reader and filename
///
/// * `reader` - The reader containing the PSB or MDF data
/// * `filename` - The name of the file (used for error reporting and extension detection)
/// * `config` - Extra configuration options
pub fn new<R: Read + Seek>(
mut reader: R,
filename: &str,

View File

@@ -1,3 +1,4 @@
//! Kirikiri Simple Crypt Text File
use crate::ext::io::*;
use crate::scripts::base::*;
use crate::types::*;
@@ -6,9 +7,11 @@ use overf::wrapping;
use std::io::Read;
#[derive(Debug)]
/// Kirikiri Simple Crypt Script Builder
pub struct SimpleCryptBuilder {}
impl SimpleCryptBuilder {
/// Creates a new instance of `SimpleCryptBuilder`
pub fn new() -> Self {
Self {}
}
@@ -55,6 +58,7 @@ impl ScriptBuilder for SimpleCryptBuilder {
}
#[derive(Debug)]
/// Kirikiri Simple Crypt Script
pub struct SimpleCrypt {
/// Crypt mode
crypt: u8,
@@ -63,6 +67,10 @@ pub struct SimpleCrypt {
}
impl SimpleCrypt {
/// Creates a new `SimpleCrypt` script from the given buffer and filename
///
/// * `buf` - The buffer containing the SimpleCrypt data
/// * `filename` - The name of the file
pub fn new(buf: Vec<u8>, filename: &str) -> Result<Self> {
let mut reader = MemReader::new(buf);
let mut header = [0u8; 5];
@@ -86,7 +94,7 @@ impl SimpleCrypt {
})
}
pub fn unpack(crypt: u8, data: MemReaderRef) -> Result<Vec<u8>> {
pub(crate) fn unpack(crypt: u8, data: MemReaderRef) -> Result<Vec<u8>> {
match crypt {
0 => Self::unpack_mode0(data),
1 => Self::unpack_mode1(data),