//! Basic types use clap::ValueEnum; use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Copy, Clone, Serialize, Deserialize, Debug)] #[serde(untagged, rename_all = "camelCase")] /// Text Encoding pub enum Encoding { /// Automatically detect encoding Auto, /// UTF-8 encoding Utf8, /// Shift-JIS encoding Cp932, /// GB2312 encoding Gb2312, /// UTF-16 Little Endian encoding Utf16LE, /// UTF-16 Big Endian encoding Utf16BE, /// Code page encoding (Windows only) #[cfg(windows)] CodePage(u32), } impl Default for Encoding { fn default() -> Self { Encoding::Utf8 } } impl Encoding { /// Returns true if the encoding is Shift-JIS (CP932). pub fn is_jis(&self) -> bool { match self { Self::Cp932 => true, #[cfg(windows)] Self::CodePage(code_page) => *code_page == 932, _ => false, } } /// Returns true if the encoding is UTF-16LE. pub fn is_utf16le(&self) -> bool { match self { Self::Utf16LE => true, #[cfg(windows)] Self::CodePage(code_page) => *code_page == 1200, _ => false, } } /// Returns true if the encoding is UTF-16BE. pub fn is_utf16be(&self) -> bool { match self { Self::Utf16BE => true, #[cfg(windows)] Self::CodePage(code_page) => *code_page == 1201, _ => false, } } /// Returns true if the encoding is UTF8. pub fn is_utf8(&self) -> bool { match self { Self::Utf8 => true, #[cfg(windows)] Self::CodePage(code_page) => *code_page == 65001, _ => false, } } /// Returns the charset name pub fn charset(&self) -> Option<&'static str> { match self { Self::Auto => None, Self::Utf8 => Some("UTF-8"), Self::Cp932 => Some("shift_jis"), Self::Gb2312 => Some("gbk"), Self::Utf16LE => Some("utf-16le"), Self::Utf16BE => Some("utf-16be"), #[cfg(windows)] Self::CodePage(code_page) => match *code_page { 932 => Some("shift_jis"), 65001 => Some("utf-8"), 1200 => Some("utf-16le"), 936 => Some("gbk"), _ => None, }, } } } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Text Encoding (for CLI) pub enum TextEncoding { /// Use script's default encoding Default, /// Automatically detect encoding Auto, /// UTF-8 encoding Utf8, #[value(alias("jis"))] /// Shift-JIS encoding Cp932, #[value(alias("gbk"))] /// GB2312 encoding Gb2312, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Script type pub enum OutputScriptType { /// Text script M3t, /// Same as M3t, buf different extension M3ta, /// Same as M3t, buf different extension M3tTxt, /// JSON which can be used for GalTransl Json, /// YAML (same as JSON, but with YAML syntax) Yaml, /// Gettext .pot file Pot, /// Gettext .po file Po, /// Custom output Custom, } impl OutputScriptType { /// Returns true if the script type is custom. pub fn is_custom(&self) -> bool { matches!(self, OutputScriptType::Custom) } /// Returns true if the script type is M3t/M3ta/M3tTxt. pub fn is_m3t(&self) -> bool { matches!( self, OutputScriptType::M3t | OutputScriptType::M3ta | OutputScriptType::M3tTxt ) } /// Returns true if the script type supports source messages. pub fn is_src_supported(&self) -> bool { matches!( self, OutputScriptType::M3t | OutputScriptType::M3ta | OutputScriptType::M3tTxt | OutputScriptType::Po | OutputScriptType::Pot ) } } impl AsRef for OutputScriptType { /// Returns the extension for the script type. fn as_ref(&self) -> &str { match self { OutputScriptType::M3t => "m3t", OutputScriptType::M3ta => "m3ta", OutputScriptType::M3tTxt => "txt", OutputScriptType::Json => "json", OutputScriptType::Yaml => "yaml", OutputScriptType::Pot => "pot", OutputScriptType::Po => "po", OutputScriptType::Custom => "", } } } #[cfg(feature = "circus")] #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Circus MES game pub enum CircusMesType { /// fortissimo//Akkord:Bsusvier Ffexa, /// fortissimo EXS//Akkord:nächsten Phase Ffexs, /// Eternal Fantasy Ef, /// D.C.〜ダ・カーポ〜 温泉編 Dcos, /// ことり Love Ex P Ktlep, /// D.C.WhiteSeason Dcws, /// D.C. Summer Vacation Dcsv, /// D.C.P.C.(Vista) Dcpc, /// D.C.〜ダ・カーポ〜 MEMORIES DISC Dcmems, /// D.C. Dream X’mas Dcdx, /// D.C.A.S. 〜ダ・カーポ〜アフターシーズンズ Dcas, /// D.C.II 春風のアルティメットバトル! Dcbs, /// D.C.II Fall in Love Dc2fl, /// D.C.II 春風のアルティメットバトル! Dc2bs, /// D.C.II Dearest Marriage Dc2dm, /// D.C.II 〜featuring Yun2〜 Dc2fy, /// D.C.II C.C. 月島小恋のらぶらぶバスルーム Dc2cckko, /// D.C.II C.C. 音姫先生のどきどき特別授業 Dc2ccotm, /// D.C.II Spring Celebration Dc2sc, /// D.C.II To You Dc2ty, /// D.C.II P.C. Dc2pc, /// D.C.III RX-rated Dc3rx, /// D.C.III P.P.~ダ・カーポIII プラチナパートナー~ Dc3pp, /// D.C.III WithYou Dc3wy, /// D.C.III DreamDays Dc3dd, /// D.C.4 ~ダ・カーポ4~ Dc4, /// D.C.4 Plus Harmony 〜ダ・カーポ4〜 プラスハーモニー Dc4ph, /// D.S. -Dal Segno- Ds, /// D.S.i.F. -Dal Segno- in Future Dsif, /// てんぷれ! Tmpl, /// 百花百狼/Hyakka Hyakurou Nightshade, } #[cfg(feature = "circus")] impl AsRef for CircusMesType { /// Returns the name. fn as_ref(&self) -> &str { match self { CircusMesType::Ffexa => "ffexa", CircusMesType::Ffexs => "ffexs", CircusMesType::Ef => "ef", CircusMesType::Dcos => "dcos", CircusMesType::Ktlep => "ktlep", CircusMesType::Dcws => "dcws", CircusMesType::Dcsv => "dcsv", CircusMesType::Dcpc => "dcpc", CircusMesType::Dcmems => "dcmems", CircusMesType::Dcdx => "dcdx", CircusMesType::Dcas => "dcas", CircusMesType::Dcbs => "dcbs", CircusMesType::Dc2fl => "dc2fl", CircusMesType::Dc2bs => "dc2bs", CircusMesType::Dc2dm => "dc2dm", CircusMesType::Dc2fy => "dc2fy", CircusMesType::Dc2cckko => "dc2cckko", CircusMesType::Dc2ccotm => "dc2ccotm", CircusMesType::Dc2sc => "dc2sc", CircusMesType::Dc2ty => "dc2ty", CircusMesType::Dc2pc => "dc2pc", CircusMesType::Dc3rx => "dc3rx", CircusMesType::Dc3pp => "dc3pp", CircusMesType::Dc3wy => "dc3wy", CircusMesType::Dc3dd => "dc3dd", CircusMesType::Dc4 => "dc4", CircusMesType::Dc4ph => "dc4ph", CircusMesType::Ds => "ds", CircusMesType::Dsif => "dsif", CircusMesType::Tmpl => "tmpl", CircusMesType::Nightshade => "nightshade", } } } /// Extra configuration options for the script. #[derive(Debug, Clone, msg_tool_macro::Default)] pub struct ExtraConfig { #[cfg(feature = "circus")] /// Circus Game for circus MES script. pub circus_mes_type: Option, #[cfg(feature = "escude-arc")] /// Whether to use fake compression for Escude archive pub escude_fake_compress: bool, #[cfg(feature = "escude")] /// The path to the Escude enum script file (enum_scr.bin) pub escude_enum_scr: Option, #[cfg(feature = "bgi")] /// Duplicate same strings when importing into BGI scripts. /// Enable this will cause BGI scripts to become very large. pub bgi_import_duplicate: bool, #[cfg(feature = "bgi")] /// Disable appending new strings to the end of BGI scripts. /// Disable may cause BGI scripts broken. pub bgi_disable_append: bool, #[cfg(feature = "image")] /// Output image type pub image_type: Option, #[cfg(all(feature = "bgi-arc", feature = "bgi-img"))] /// Detect all files in BGI archive as SysGrp Images. By default, only files which name is `sysgrp.arc` will enabled this. pub bgi_is_sysgrp_arc: Option, #[cfg(feature = "bgi-img")] /// Whether to create scrambled SysGrp images. When in import mode, the default value depends on the original image. /// When in creation mode, it is not enabled by default. pub bgi_img_scramble: Option, #[cfg(feature = "cat-system-arc")] /// CatSystem2 engine int archive password pub cat_system_int_encrypt_password: Option, #[cfg(feature = "cat-system-img")] /// Draw CatSystem2 image on canvas (if canvas width and height are specified in file) pub cat_system_image_canvas: bool, #[cfg(feature = "kirikiri")] /// Kirikiri language index in script. If not specified, the first language will be used. pub kirikiri_language_index: Option, #[cfg(feature = "kirikiri")] /// Export chat message to extra json file. (for Kirikiri SCN script.) /// For example, CIRCUS's comu message. Yuzusoft's phone chat message. pub kirikiri_export_chat: bool, #[cfg(feature = "kirikiri")] /// Kirikiri chat message key. For example, CIRCUS's key is "comumode". Yuzusoft's key is "phonechat". /// If not specified, "comumode" will be used. pub kirikiri_chat_key: Option>, #[cfg(feature = "kirikiri")] /// Kirikiri chat message translation. The outter object's key is filename(`global` is a special key). /// The inner object: key is original text, value is (translated text, original text count). pub kirikiri_chat_json: Option>>>, #[cfg(feature = "kirikiri")] /// Kirikiri language list. First language code is code for language index 1. pub kirikiri_languages: Option>>, #[cfg(feature = "kirikiri")] /// Remove empty lines in Kirikiri KS script. pub kirikiri_remove_empty_lines: bool, #[cfg(feature = "kirikiri")] /// Kirikiri name commands, used to extract names from ks script. pub kirikiri_name_commands: std::sync::Arc>, #[cfg(feature = "kirikiri")] /// Kirikiri message commands, used to extract more message from ks script. pub kirikiri_message_commands: std::sync::Arc>, #[cfg(feature = "bgi-arc")] /// Whether to compress files in BGI archive when packing BGI archive. pub bgi_compress_file: bool, #[cfg(feature = "bgi-arc")] #[default(9)] /// Compress level for BGI Dsc file. 0 means store, 9 mean best compression. pub bgi_compress_level: u8, #[cfg(feature = "emote-img")] /// Whether to overlay PIMG images. (By default, true if all layers are not group layers.) pub emote_pimg_overlay: Option, #[cfg(feature = "artemis-arc")] /// Disable Artemis archive (.pfs) XOR encryption when packing. pub artemis_arc_disable_xor: bool, #[cfg(feature = "artemis")] /// Artemis script indent size, used to format Artemis script. /// Default is 4 spaces. pub artemis_indent: Option, #[cfg(feature = "artemis")] /// Disable Artemis script indent, used to format Artemis script. pub artemis_no_indent: bool, #[cfg(feature = "artemis")] #[default(100)] /// Max line width in Artemis script, used to format Artemis script. pub artemis_max_line_width: usize, #[cfg(feature = "artemis")] /// Specify the language of Artemis AST script. /// If not specified, the first language will be used. pub artemis_ast_lang: Option, #[cfg(feature = "cat-system")] /// CatSystem2 CSTL script language, used to extract messages from CSTL script. /// If not specified, the first language will be used. pub cat_system_cstl_lang: Option, #[cfg(feature = "flate2")] #[default(6)] /// Zlib compression level. 0 means no compression, 9 means best compression. pub zlib_compression_level: u32, #[cfg(feature = "image")] /// PNG compression level. pub png_compression_level: PngCompressionLevel, #[cfg(feature = "circus-img")] /// Keep original BPP when importing Circus CRX images. pub circus_crx_keep_original_bpp: bool, #[cfg(feature = "circus-img")] /// Use zstd compression for Circus CRX images. (CIRCUS Engine don't support this. Hook is required.) pub circus_crx_zstd: bool, #[cfg(feature = "zstd")] #[default(3)] /// Zstd compression level. 0 means default compression level (3), 22 means best compression. pub zstd_compression_level: i32, #[cfg(feature = "circus-img")] /// Circus CRX image row type mode pub circus_crx_mode: crate::scripts::circus::image::crx::CircusCrxMode, #[cfg(feature = "ex-hibit")] /// ExHibit xor key for rld script. /// Use [ReExHIBIT](https://github.com/ZQF-ReVN/RxExHIBIT) to find the key. pub ex_hibit_rld_xor_key: Option, #[cfg(feature = "ex-hibit")] /// ExHibit def.rld xor key. pub ex_hibit_rld_def_xor_key: Option, #[cfg(feature = "ex-hibit")] /// ExHibit rld xor keys. pub ex_hibit_rld_keys: Option>, #[cfg(feature = "ex-hibit")] /// ExHibit def.rld xor keys. pub ex_hibit_rld_def_keys: Option>, #[cfg(feature = "mozjpeg")] #[default(80)] /// JPEG quality for output images, 0-100. 100 means best quality. pub jpeg_quality: u8, #[cfg(feature = "webp")] /// Use WebP lossless compression for output images. pub webp_lossless: bool, #[cfg(feature = "webp")] #[default(80)] /// WebP quality for output images, 0-100. 100 means best quality. pub webp_quality: u8, #[cfg(feature = "circus-img")] /// Draw Circus CRX images on canvas (if canvas width and height are specified in file) pub circus_crx_canvas: bool, /// Try use YAML format instead of JSON when custom exporting. pub custom_yaml: bool, #[cfg(feature = "entis-gls")] /// Entis GLS srcxml script language, used to extract messages from srcxml script. /// If not specified, the first language will be used. pub entis_gls_srcxml_lang: Option, #[cfg(feature = "will-plus")] /// Disable disassembly for WillPlus ws2 script. /// Use another parser to parse the script. /// Should only be used when the default parser not works well. pub will_plus_ws2_no_disasm: bool, #[cfg(feature = "artemis-panmimisoft")] /// Artemis Engine blacklist tag names for TXT script. /// This is used to ignore these tags when finding names in Artemis TXT (ぱんみみそふと) script. pub artemis_panmimisoft_txt_blacklist_names: std::sync::Arc>, #[cfg(feature = "artemis-panmimisoft")] /// Specify the language of Artemis TXT (ぱんみみそふと) script. /// If not specified, the first language will be used. pub artemis_panmimisoft_txt_lang: Option, #[cfg(feature = "artemis-panmimisoft")] /// Enable multiple language support for single language Artemis TXT (ぱんみみそふと) script. /// artemis_panmimisoft_txt_lang must be set when enabling this. pub artemis_panmimisoft_txt_multi_lang: bool, #[cfg(feature = "lossless-audio")] /// Audio format for output lossless audio files. pub lossless_audio_fmt: LosslessAudioFormat, #[cfg(feature = "audio-flac")] #[default(5)] /// FLAC compression level for output FLAC audio files. 0 means fastest compression, 8 means best compression. Default level is 5. pub flac_compression_level: u32, #[cfg(feature = "artemis")] #[default(true)] /// Format lua code in Artemis ASB script(.asb/.iet) when exporting. pub artemis_asb_format_lua: bool, #[cfg(feature = "kirikiri")] /// Whether to handle title in Kirikiri SCN script. pub kirikiri_title: bool, #[cfg(feature = "favorite")] #[default(true)] /// Whether to filter ascii strings in Favorite HCB script. pub favorite_hcb_filter_ascii: bool, #[cfg(feature = "bgi-img")] #[default(get_default_threads())] /// Workers count for decode BGI compressed images v2 in parallel. Default is half of CPU cores. /// Set this to 1 to disable parallel decoding. 0 means same as 1. pub bgi_img_workers: usize, #[cfg(feature = "image-jxl")] #[default(true)] /// Use JXL lossless compression for output images. Enabled by default. pub jxl_lossless: bool, #[cfg(feature = "image-jxl")] #[default(1.0)] /// JXL distance for output images. 0 means mathematically lossless compression. 1.0 means visually lossless compression. /// Allowed range is 0.0-25.0. Recommended range is 0.5-3.0. Default value is 1.0. pub jxl_distance: f32, #[cfg(feature = "image-jxl")] #[default(1)] /// Workers count for encode JXL images in parallel. Default is 1. /// Set this to 1 to disable parallel encoding. 0 means same as 1 pub jxl_workers: usize, #[cfg(feature = "emote-img")] #[default(true)] /// Process tlg images. pub psb_process_tlg: bool, #[cfg(feature = "softpal-img")] #[default(true)] /// Whether to use fake compression for Softpal Pgd images. Enabled by default. /// WARN: Compress may cause image broken. pub pgd_fake_compress: bool, #[cfg(feature = "softpal")] /// Whether to add message index to Softpal src script when exporting. pub softpal_add_message_index: bool, #[cfg(feature = "kirikiri")] #[default(true)] /// Enable multi-language support for Kirikiri chat messages. Default is true. /// Note: This requires [Self::kirikiri_language_index] and [Self::kirikiri_languages] to be set correctly. pub kirikiri_chat_multilang: bool, #[cfg(feature = "kirikiri-arc")] #[default(true)] /// Decrypt SimpleCrypt files in Kirikiri XP3 archive when extracting. Default is true. pub xp3_simple_crypt: bool, #[cfg(feature = "kirikiri-arc")] #[default(true)] /// Decompress mdf files in Kirikiri XP3 archive when extracting. Default is true. pub xp3_mdf_decompress: bool, #[cfg(feature = "kirikiri-arc")] /// Configuration for Kirikiri XP3 segmenter when creating XP3 archive. pub xp3_segmenter: crate::scripts::kirikiri::archive::xp3::SegmenterConfig, #[cfg(feature = "kirikiri-arc")] #[default(true)] /// Compress files in Kirikiri XP3 archive when creating. Default is true. pub xp3_compress_files: bool, #[cfg(feature = "kirikiri-arc")] #[default(true)] /// Compress index in Kirikiri XP3 archive when creating. Default is true. pub xp3_compress_index: bool, #[cfg(feature = "kirikiri-arc")] #[default(num_cpus::get())] /// Workers count for compress files in Kirikiri XP3 archive when creating in parallel. Default is CPU cores count. pub xp3_compress_workers: usize, #[cfg(feature = "kirikiri-arc")] /// Use zstd compression for files in Kirikiri XP3 archive when creating. (Warning: Kirikiri engine don't support this. Hook is required.) pub xp3_zstd: bool, #[cfg(feature = "kirikiri-arc")] /// Use zopfli compression for files in Kirikiri XP3 archive when creating. This is very slow. pub xp3_zopfli: bool, #[cfg(feature = "kirikiri-arc")] #[default(1)] /// Workers count for packing file in Kirikiri XP3 archive in parallel. Default is 1. /// This not works when segment is disabled. pub xp3_pack_workers: usize, #[cfg(feature = "kirikiri-arc")] /// Disable adler32 checksum for Kirikiri XP3 archive when creating. /// This will keep compatibility with https://github.com/arcusmaximus/KirikiriTools tool. pub xp3_no_adler: bool, #[cfg(feature = "kirikiri")] /// Insert new language at the specified index in Kirikiri SCN script. If index is out of bounds, this flags will be ignored. pub kirikiri_language_insert: bool, #[cfg(feature = "musica-arc")] /// Musica game title for paz archive. pub musica_game_title: Option, #[cfg(feature = "musica-arc")] /// Musica xor key for paz archive. pub musica_xor_key: Option, #[cfg(feature = "musica-arc")] /// Whether to compress files in Musica paz archive when packing paz archive. pub musica_compress: bool, #[cfg(feature = "bgi")] /// Add an additional space at the end of message in BGI scripts when importing. /// This may help BGI engine to display the message correctly in save/load screen for some games. pub bgi_add_space: bool, #[cfg(feature = "escude")] /// Escude game title pub escude_op: Option, #[cfg(feature = "zopfli")] #[default(std::num::NonZeroU64::new(15).unwrap())] /// Maximum amount of times to rerun forward and backward pass to optimize LZ77 compression cost. /// Good values: 10, 15 for small files, 5 for files over several MB in size or it will be too slow. /// Default is 15. pub zopfli_iteration_count: std::num::NonZeroU64, #[cfg(feature = "zopfli")] #[default(std::num::NonZeroU64::new(u64::MAX).unwrap())] /// Stop after rerunning forward and backward pass this many times without finding a smaller representation of the block. /// Default value: practically infinite (maximum u64 value) pub zopfli_iterations_without_improvement: std::num::NonZeroU64, #[cfg(feature = "zopfli")] #[default(15)] /// Maximum amount of blocks to split into (0 for unlimited, but this can give extreme results that hurt compression on some files). /// Default value: 15. pub zopfli_maximum_block_splits: u16, #[cfg(feature = "entis-gls")] /// Whether to disassemble Entis GLS csx script when exporting in custom mode. pub entis_gls_csx_disasm: bool, #[cfg(feature = "entis-gls")] #[default(String::from("/"))] /// The line feed character used in Entis GLS csx script. pub entis_gls_csx_lf: String, #[cfg(feature = "entis-gls")] /// Entis GLS csx script version. /// If not specified. Will try use lower version first. pub entis_gls_csx_ver: Option, #[cfg(feature = "entis-gls")] /// Entis GLS csx script version2 full version. /// If not specified. Will try use higher version first. pub entis_gls_csx_v2_ver: Option, #[cfg(feature = "entis-gls")] /// Disable part labels in Entis GLS csx script when exporting. pub entis_gls_csx_no_part_label: bool, #[cfg(feature = "qlie-img")] #[default(true)] /// Whether to process ABMP10 images in ABMP10 images. pub qlie_abmp10_process_abmp10: bool, #[cfg(feature = "qlie-arc")] /// Path to qlie pack archive key file (pack_keyfile_kfueheish15538fa9or.key) pub qlie_pack_keyfile: Option, #[cfg(feature = "qlie-arc")] /// Whether to compress files in Qlie pack archive. pub qlie_pack_compress_files: bool, #[cfg(feature = "qlie-img")] /// Whether to use PNG file directly for Qlie DPNG images when importing. /// Enable this will disable reencoding PNG files. Useful when the PNG files are already optimized by other tools. pub qlie_dpng_use_raw_png: bool, #[cfg(feature = "qlie-img")] /// Export Qlie DPNG images as PSD files. pub qlie_dpng_psd: bool, #[cfg(feature = "utils-psd")] #[default(true)] /// Whether to use compression for image data in PSD files. pub psd_compress: bool, #[cfg(feature = "emote-img")] /// Export Emote PIMG images as PSD files. pub emote_pimg_psd: bool, #[cfg(feature = "kirikiri")] /// Whether to only extract message between Talk and Hitret command in Kirikiri KS script. Auto detect if not specified. pub kirikiri_ks_hitret: Option, #[cfg(feature = "kirikiri")] /// The line feed character used in Kirikiri KS script. pub kirikiri_ks_lf: Option, #[cfg(feature = "kirikiri")] /// Kirikiri message tags, used to extract more message from ks script. pub kirikiri_message_tags: std::sync::Arc>, #[cfg(feature = "kirikiri")] /// Specifiy BOM type when creating new Kirikiri ks script. If not specified, detect from original script. pub kirikiri_ks_bom: Option, #[cfg(feature = "emote-img")] /// BC7 compress configuration pub bc7: crate::scripts::emote::psb::BC7Config, #[cfg(feature = "artemis")] #[default(default_artemis_asb_end_tags())] /// A list of Artemis ASB script end tags, used to determine a dialogue block in script. pub artemis_asb_end_tags: std::sync::Arc>, #[cfg(feature = "kirikiri-arc")] /// Game title for Kirikiri XP3 archive. This is used to decrypt file in archives. pub xp3_game_title: Option, #[cfg(feature = "kirikiri-arc")] /// Print debug information for Kirikiri XP3 archive when extracting archive to stdout. /// This is used to find correct configuration for unknown XP3 archives. pub xp3_debug_archive: bool, #[cfg(feature = "kirikiri-arc")] /// Force extract encrypted files in Kirikiri XP3 archive without decryption. pub xp3_force_extract: bool, #[cfg(feature = "kirikiri-arc")] /// Force decrypt files in Kirikiri xp3 archive even when flags are not set. /// Some encrypted files in Kirikiri XP3 archive may not set encryption flag, but still encrypted. Enable this to force decrypt these files. pub xp3_force_decrypt: bool, #[cfg(feature = "emote-img")] /// Disable diff handle when exporting Emote PIMG images to PSD files. /// If enabled, no group layers will be crated if both layer don't have diff_id and group_layer_id attribute. pub emote_pimg_psd_no_diff: bool, #[cfg(feature = "kirikiri-arc")] /// The path to the file list for Kirikiri XP3 archive. This is used to recover file names from hashed values. /// Only works with some encyrption methods. pub xp3_file_list_path: Option, #[cfg(feature = "kirikiri-arc")] /// Control the behavior to how to extract files from Cxdec3/4(Hxv4) protected archives. pub xp3_cxdec_file_hash: crate::scripts::kirikiri::archive::xp3::FileHashOption, #[cfg(feature = "kirikiri-arc")] /// Control the behavior to how to append path name to files from Cxdec3/4(Hxv4) protected archives. pub xp3_cxdec_path_hash: crate::scripts::kirikiri::archive::xp3::PathHashOption, } #[cfg(feature = "artemis")] fn default_artemis_asb_end_tags() -> std::sync::Arc> { std::sync::Arc::new( ["click", "hcls", "rpx"] .into_iter() .map(String::from) .collect(), ) } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] /// Script type pub enum ScriptType { #[cfg(feature = "artemis")] /// Artemis Engine AST script Artemis, #[cfg(feature = "artemis")] /// Artemis Engine ASB script ArtemisAsb, #[cfg(feature = "artemis")] /// Artemis Engine TXT (General) script ArtemisTxt, #[cfg(feature = "artemis-panmimisoft")] /// Artemis Engine TXT (ぱんみみそふと) script ArtemisPanmimisoftTxt, #[cfg(feature = "artemis-arc")] #[value(alias("pfs"))] /// Artemis archive (pfs) ArtemisArc, #[cfg(feature = "artemis-arc")] #[value(alias("pf2"))] /// Artemis archive (pf2) (.pfs) ArtemisPf2, #[cfg(feature = "bgi")] #[value(alias("ethornell"))] /// Buriko General Interpreter/Ethornell Script BGI, #[cfg(feature = "bgi")] #[value(alias("ethornell-bsi"))] /// Buriko General Interpreter/Ethornell bsi script (._bsi) BGIBsi, #[cfg(feature = "bgi")] #[value(alias("ethornell-bp"))] /// Buriko General Interpreter/Ethornell bp script (._bp) BGIBp, #[cfg(feature = "bgi-arc")] #[value(alias = "ethornell-arc-v1")] /// Buriko General Interpreter/Ethornell archive v1 BGIArcV1, #[cfg(feature = "bgi-arc")] #[value(alias = "ethornell-arc-v2", alias = "bgi-arc", alias = "ethornell-arc")] /// Buriko General Interpreter/Ethornell archive v2 BGIArcV2, #[cfg(feature = "bgi-arc")] #[value(alias("ethornell-dsc"))] /// Buriko General Interpreter/Ethornell compressed file (DSC) BGIDsc, #[cfg(feature = "bgi-audio")] #[value(alias("ethornell-audio"))] /// Buriko General Interpreter/Ethornell audio file (Ogg/Vorbis) BGIAudio, #[cfg(feature = "bgi-img")] #[value(alias("ethornell-img"))] /// Buriko General Interpreter/Ethornell image (Image files in sysgrp.arc) BGIImg, #[cfg(feature = "bgi-img")] #[value(alias("ethornell-cbg"))] /// Buriko General Interpreter/Ethornell Compressed Background image (CBG) BGICbg, #[cfg(feature = "cat-system")] /// CatSystem2 engine scene script CatSystem, #[cfg(feature = "cat-system")] /// CatSystem2 engine CSTL script CatSystemCstl, #[cfg(feature = "cat-system-arc")] /// CatSystem2 engine archive CatSystemInt, #[cfg(feature = "cat-system-img")] /// CatSystem2 engine image CatSystemHg3, #[cfg(feature = "circus")] /// Circus MES script Circus, #[cfg(feature = "circus-arc")] /// Circus Image archive CircusCrm, #[cfg(feature = "circus-arc")] /// Circus DAT archive CircusDat, #[cfg(feature = "circus-arc")] /// Circus PCK archive CircusPck, #[cfg(feature = "circus-audio")] /// Circus PCM audio CircusPcm, #[cfg(feature = "circus-img")] /// Circus CRX Image CircusCrx, #[cfg(feature = "circus-img")] /// Circus Differential Image CircusCrxd, #[cfg(feature = "emote-img")] #[value(alias("psb"))] /// Emote PSB (basic handle) EmotePsb, #[cfg(feature = "emote-img")] #[value(alias("pimg"))] /// Emote PIMG image EmotePimg, #[cfg(feature = "emote-img")] #[value(alias("dref"))] /// Emote DREF(DPAK-referenced) image EmoteDref, #[cfg(feature = "entis-gls")] /// Entis GLS srcxml Script EntisGls, #[cfg(feature = "entis-gls")] /// Entis GLS csx script EntisGlsCsx, #[cfg(feature = "escude-arc")] /// Escude bin archive EscudeArc, #[cfg(feature = "escude")] /// Escude bin script Escude, #[cfg(feature = "escude")] /// Escude list script EscudeList, #[cfg(feature = "ex-hibit")] /// ExHibit rld script ExHibit, #[cfg(feature = "ex-hibit-arc")] /// ExHibit GRP archive ExHibitGrp, #[cfg(feature = "favorite")] /// Favorite hcb script Favorite, #[cfg(feature = "hexen-haus")] /// HexenHaus bin script HexenHaus, #[cfg(feature = "hexen-haus-arc")] /// HexenHaus Arcc archive HexenHausArcc, #[cfg(feature = "hexen-haus-arc")] /// HexenHaus Audio archive HexenHausOdio, #[cfg(feature = "hexen-haus-arc")] /// HexenHaus WAG archive HexenHausWag, #[cfg(feature = "hexen-haus-img")] /// HexenHaus PNG image HexenHausPng, #[cfg(feature = "kirikiri")] #[value(alias("kr-scn"))] /// Kirikiri SCN script KirikiriScn, #[cfg(feature = "kirikiri")] #[value(alias("kr-simple-crypt"))] /// Kirikiri SimpleCrypt's text file KirikiriSimpleCrypt, #[cfg(feature = "kirikiri")] #[value(alias = "kr", alias = "kr-ks", alias = "kirikiri-ks")] /// Kirikiri script Kirikiri, #[cfg(feature = "kirikiri-arc")] #[value(alias = "kr-xp3", alias = "xp3")] /// Kirikiri XP3 archive KirikiriXp3, #[cfg(feature = "kirikiri-img")] #[value(alias("kr-tlg"))] /// Kirikiri TLG image KirikiriTlg, #[cfg(feature = "kirikiri")] #[value(alias("kr-mdf"))] /// Kirikiri MDF (zlib compressed) file KirikiriMdf, #[cfg(feature = "kirikiri")] #[value(alias("kr-tjs2"))] /// Kirikiri compiled TJS2 script KirikiriTjs2, #[cfg(feature = "kirikiri")] #[value(alias("kr-tjs-ns0"))] /// Kirikiri TJS NS0 binary encoded script KirikiriTjsNs0, #[cfg(feature = "musica")] /// Musica Script (.sc) Musica, #[cfg(feature = "musica-arc")] /// Musica Engine Resource Archive (.paz) MusicaPaz, #[cfg(feature = "qlie")] /// Qlie Engine Scenario script (.s) Qlie, #[cfg(feature = "qlie-arc")] /// Qlie Pack Archive (.pack) QliePack, #[cfg(feature = "qlie-img")] /// Qlie tiled PNG image (.png) QlieDpng, #[cfg(feature = "qlie-img")] #[value(alias = "qlie-abmp11", alias = "qlie-abmp12")] /// Qlie Abmp10/11/12 image (.b) QlieAbmp10, #[cfg(feature = "silky")] /// Silky Engine Mes script Silky, #[cfg(feature = "silky")] /// Silky Engine Map script SilkyMap, #[cfg(feature = "softpal")] /// Softpal src script Softpal, #[cfg(feature = "softpal-arc")] /// Softpal Pac archive SoftpalPac, #[cfg(feature = "softpal-arc")] /// Softpal Pac/AMUSE archive SoftpalPacAmuse, #[cfg(feature = "softpal-img")] #[value(alias = "pgd-ge", alias = "pgd")] /// Softpal Pgd Ge image SoftpalPgdGe, #[cfg(feature = "softpal-img")] #[value(alias = "softpal-pgd2", alias = "pgd3", alias = "pgd2")] /// Softpal Pgd Differential image SoftpalPgd3, #[cfg(feature = "will-plus")] #[value(alias("adv-hd-ws2"))] /// WillPlus ws2 script WillPlusWs2, #[cfg(feature = "will-plus-img")] #[value(alias("adv-hd-wip"))] /// WillPlus WIP Image WillPlusWip, #[cfg(feature = "yaneurao-itufuru")] #[value(alias("itufuru"))] /// Yaneurao Itufuru script YaneuraoItufuru, #[cfg(feature = "yaneurao-itufuru")] #[value(alias("itufuru-arc"))] /// Yaneurao Itufuru script archive YaneuraoItufuruArc, #[cfg(feature = "yuris")] /// Yu-Ris YSCM(opcodes metadata) file (.ybn) YurisYSCM, #[cfg(feature = "yuris")] /// Yu-Ris YSER(error message) file (.ybn) YurisYSER, #[cfg(feature = "yuris")] /// Yu-Ris YSCFG(config) file (.ybn) YurisYSCFG, } #[derive(Clone, Debug, Serialize, Deserialize)] /// Message structure for scripts pub struct Message { #[serde(skip_serializing_if = "Option::is_none")] /// Optional name for the message, used in some scripts. pub name: Option, /// The actual message content. pub message: String, } impl Message { /// Creates a new `Message` instance. pub fn new(message: String, name: Option) -> Self { Message { message, name } } } #[derive(Clone, Debug)] /// Extended message structure for scripts pub struct ExtendedMessage { /// Optional name for the message, used in some scripts. pub name: Option, /// Original source text. pub source: String, /// Translated text. pub translated: String, /// Optional LLM translated text. pub llm: Option, } /// Result of script operation. pub enum ScriptResult { /// Operation completed successfully. Ok, /// Operation completed without any changes. /// For example, no messages found in the script. Ignored, /// Operation not completed. /// This will not count in statistics. Uncount, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Format type (for CLI) pub enum FormatType { /// Wrap line with fixed length Fixed, /// Do not wrap line None, } #[derive(Clone)] /// Format options pub enum FormatOptions { /// Wrap line with fixed length Fixed { /// Fixed length length: usize, /// Whether to keep original line breaks keep_original: bool, /// Whether to break words(ASCII only) at the end of the line break_words: bool, /// Whether to insert a full-width space after a line break when a sentence starts with a full-width quotation mark. insert_fullwidth_space_at_line_start: bool, /// If a line break occurs in the middle of some symbols, bring the sentence to next line break_with_sentence: bool, #[cfg(feature = "jieba")] /// Whether to break Chinese words at the end of the line. break_chinese_words: bool, #[cfg(feature = "jieba")] /// Path to custom jieba dictionary jieba_dict: Option, /// Do not remove space at the start of the line no_remove_space_at_line_start: bool, }, /// Do not wrap line None, } #[derive(Debug, Serialize, Deserialize)] /// Name table cell pub struct NameTableCell { #[serde(rename = "JP_Name")] /// Original name pub jp_name: String, #[serde(rename = "CN_Name")] /// Translated name pub cn_name: String, #[serde(rename = "Count")] /// Number of times this name appears in the script pub count: usize, } #[derive(Debug, Serialize, Deserialize)] /// Replacement table for string replacements pub struct ReplacementTable { #[serde(flatten)] /// Map of original strings to their replacements pub map: HashMap, } #[cfg(feature = "image")] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] /// Image color type pub enum ImageColorType { /// Grayscale image Grayscale, /// RGB image Rgb, /// RGBA image Rgba, /// BGR image Bgr, /// BGRA image Bgra, } #[cfg(feature = "image")] impl ImageColorType { /// Returns the number of bytes per pixel for the color type and depth. pub fn bpp(&self, depth: u8) -> u16 { match self { ImageColorType::Grayscale => depth as u16, ImageColorType::Rgb => depth as u16 * 3, ImageColorType::Rgba => depth as u16 * 4, ImageColorType::Bgr => depth as u16 * 3, ImageColorType::Bgra => depth as u16 * 4, } } } #[cfg(feature = "image")] #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Image output type pub enum ImageOutputType { /// PNG image Png, #[cfg(feature = "image-jpg")] /// JPEG image Jpg, #[cfg(feature = "image-webp")] /// WebP image Webp, #[cfg(feature = "image-jxl")] /// JPEG XL image Jxl, } #[cfg(feature = "image")] impl TryFrom<&str> for ImageOutputType { type Error = anyhow::Error; /// Try to convert a extension string to an `ImageOutputType`. /// Extensions are case-insensitive. fn try_from(value: &str) -> Result { match value.to_ascii_lowercase().as_str() { "png" => Ok(ImageOutputType::Png), #[cfg(feature = "image-jpg")] "jpg" => Ok(ImageOutputType::Jpg), #[cfg(feature = "image-jpg")] "jpeg" => Ok(ImageOutputType::Jpg), #[cfg(feature = "image-webp")] "webp" => Ok(ImageOutputType::Webp), #[cfg(feature = "image-jxl")] "jxl" => Ok(ImageOutputType::Jxl), _ => Err(anyhow::anyhow!("Unsupported image output type: {}", value)), } } } #[cfg(feature = "image")] impl TryFrom<&std::path::Path> for ImageOutputType { type Error = anyhow::Error; fn try_from(value: &std::path::Path) -> Result { if let Some(ext) = value.extension() { Self::try_from(ext.to_string_lossy().as_ref()) } else { Err(anyhow::anyhow!("No extension found in path")) } } } #[cfg(feature = "image")] impl AsRef for ImageOutputType { /// Returns the extension for the image output type. fn as_ref(&self) -> &str { match self { ImageOutputType::Png => "png", #[cfg(feature = "image-jpg")] ImageOutputType::Jpg => "jpg", #[cfg(feature = "image-webp")] ImageOutputType::Webp => "webp", #[cfg(feature = "image-jxl")] ImageOutputType::Jxl => "jxl", } } } #[cfg(feature = "image")] #[derive(Clone, Debug)] /// Image data pub struct ImageData { /// Image width in pixels pub width: u32, /// Image height in pixels pub height: u32, /// Image color type pub color_type: ImageColorType, /// Image depth in bits per channel pub depth: u8, /// Image data pub data: Vec, } #[cfg(feature = "image")] #[derive(Clone, Debug)] /// Image data with name pub struct ImageDataWithName { /// Image name pub name: String, /// Image data pub data: ImageData, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// BOM type pub enum BomType { /// No BOM None, /// UTF-8 BOM Utf8, /// UTF-16 Little Endian BOM Utf16LE, /// UTF-16 Big Endian BOM Utf16BE, } impl BomType { /// Returns the byte sequence for the BOM type. pub fn as_bytes(&self) -> &'static [u8] { match self { BomType::None => &[], BomType::Utf8 => b"\xEF\xBB\xBF", BomType::Utf16LE => b"\xFF\xFE", BomType::Utf16BE => b"\xFE\xFF", } } } #[cfg(feature = "image")] #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// PNG compression level pub enum PngCompressionLevel { #[value(alias = "n")] /// No compression whatsoever. Fastest, but results in large files. NoCompression, #[value(alias = "d")] /// Default level (usually balanced) Default, /// Extremely fast but light compression. /// /// Note: When used in streaming mode, this compression level can actually result in files /// *larger* than would be produced by `NoCompression` on incompressible data because /// it doesn't do any buffering of the output stream to detect whether the data is being compressed or not. Fastest, #[value(alias = "f")] /// Fast minimal compression Fast, #[value(alias = "b")] /// Higher compression level. Same as high Best, #[value(alias = "h")] /// Spend much more time to produce a slightly smaller file than with `Balanced`. High, } #[cfg(feature = "image")] impl Default for PngCompressionLevel { fn default() -> Self { PngCompressionLevel::Default } } #[cfg(feature = "image")] impl PngCompressionLevel { /// Converts the [PngCompressionLevel] to a [png::Compression] enum. pub fn to_compression(&self) -> png::Compression { match self { PngCompressionLevel::NoCompression => png::Compression::NoCompression, PngCompressionLevel::Fastest => png::Compression::Fastest, PngCompressionLevel::Default => png::Compression::Balanced, PngCompressionLevel::Fast => png::Compression::Fast, PngCompressionLevel::Best => png::Compression::High, PngCompressionLevel::High => png::Compression::High, } } } #[cfg(feature = "lossless-audio")] #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] /// Lossless audio format pub enum LosslessAudioFormat { /// Wav Wav, #[cfg(feature = "audio-flac")] /// FLAC Format Flac, } #[cfg(feature = "lossless-audio")] impl Default for LosslessAudioFormat { fn default() -> Self { LosslessAudioFormat::Wav } } #[cfg(feature = "lossless-audio")] impl TryFrom<&str> for LosslessAudioFormat { type Error = anyhow::Error; /// Try to convert a extension string to an `LosslessAudioFormat`. /// Extensions are case-insensitive. fn try_from(value: &str) -> Result { match value.to_ascii_lowercase().as_str() { "wav" => Ok(LosslessAudioFormat::Wav), #[cfg(feature = "audio-flac")] "flac" => Ok(LosslessAudioFormat::Flac), _ => Err(anyhow::anyhow!( "Unsupported lossless audio format: {}", value )), } } } #[cfg(feature = "lossless-audio")] impl TryFrom<&std::path::Path> for LosslessAudioFormat { type Error = anyhow::Error; fn try_from(value: &std::path::Path) -> Result { if let Some(ext) = value.extension() { Self::try_from(ext.to_string_lossy().as_ref()) } else { Err(anyhow::anyhow!("No extension found in path")) } } } #[cfg(feature = "lossless-audio")] impl AsRef for LosslessAudioFormat { /// Returns the extension for the lossless audio format. fn as_ref(&self) -> &str { match self { LosslessAudioFormat::Wav => "wav", #[cfg(feature = "audio-flac")] LosslessAudioFormat::Flac => "flac", } } } #[allow(unused)] pub(crate) fn get_default_threads() -> usize { num_cpus::get().max(2) / 2 }