1use clap::ValueEnum;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Copy, Clone, Serialize, Deserialize, Debug)]
7#[serde(rename_all = "camelCase")]
8pub enum Encoding {
10 Auto,
12 Utf8,
14 Cp932,
16 Gb2312,
18 Utf16LE,
20 Utf16BE,
22 #[cfg(windows)]
24 CodePage(u32),
25}
26
27impl Default for Encoding {
28 fn default() -> Self {
29 Encoding::Utf8
30 }
31}
32
33impl Encoding {
34 pub fn is_jis(&self) -> bool {
36 match self {
37 Self::Cp932 => true,
38 #[cfg(windows)]
39 Self::CodePage(code_page) => *code_page == 932,
40 _ => false,
41 }
42 }
43
44 pub fn is_utf16le(&self) -> bool {
46 match self {
47 Self::Utf16LE => true,
48 #[cfg(windows)]
49 Self::CodePage(code_page) => *code_page == 1200,
50 _ => false,
51 }
52 }
53
54 pub fn is_utf16be(&self) -> bool {
56 match self {
57 Self::Utf16BE => true,
58 #[cfg(windows)]
59 Self::CodePage(code_page) => *code_page == 1201,
60 _ => false,
61 }
62 }
63
64 pub fn is_utf8(&self) -> bool {
66 match self {
67 Self::Utf8 => true,
68 #[cfg(windows)]
69 Self::CodePage(code_page) => *code_page == 65001,
70 _ => false,
71 }
72 }
73
74 pub fn charset(&self) -> Option<&'static str> {
76 match self {
77 Self::Auto => None,
78 Self::Utf8 => Some("UTF-8"),
79 Self::Cp932 => Some("shift_jis"),
80 Self::Gb2312 => Some("gbk"),
81 Self::Utf16LE => Some("utf-16le"),
82 Self::Utf16BE => Some("utf-16be"),
83 #[cfg(windows)]
84 Self::CodePage(code_page) => match *code_page {
85 932 => Some("shift_jis"),
86 65001 => Some("utf-8"),
87 1200 => Some("utf-16le"),
88 936 => Some("gbk"),
89 _ => None,
90 },
91 }
92 }
93}
94
95#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
96pub enum TextEncoding {
98 Default,
100 Auto,
102 Utf8,
104 #[value(alias("jis"))]
105 Cp932,
107 #[value(alias("gbk"))]
108 Gb2312,
110}
111
112#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
113pub enum OutputScriptType {
115 M3t,
117 M3ta,
119 M3tTxt,
121 Json,
123 Yaml,
125 Pot,
127 Po,
129 Custom,
131}
132
133impl OutputScriptType {
134 pub fn is_custom(&self) -> bool {
136 matches!(self, OutputScriptType::Custom)
137 }
138
139 pub fn is_m3t(&self) -> bool {
141 matches!(
142 self,
143 OutputScriptType::M3t | OutputScriptType::M3ta | OutputScriptType::M3tTxt
144 )
145 }
146
147 pub fn is_src_supported(&self) -> bool {
149 matches!(
150 self,
151 OutputScriptType::M3t
152 | OutputScriptType::M3ta
153 | OutputScriptType::M3tTxt
154 | OutputScriptType::Po
155 | OutputScriptType::Pot
156 )
157 }
158}
159
160impl AsRef<str> for OutputScriptType {
161 fn as_ref(&self) -> &str {
163 match self {
164 OutputScriptType::M3t => "m3t",
165 OutputScriptType::M3ta => "m3ta",
166 OutputScriptType::M3tTxt => "txt",
167 OutputScriptType::Json => "json",
168 OutputScriptType::Yaml => "yaml",
169 OutputScriptType::Pot => "pot",
170 OutputScriptType::Po => "po",
171 OutputScriptType::Custom => "",
172 }
173 }
174}
175
176#[cfg(feature = "circus")]
177#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
178pub enum CircusMesType {
180 Ffexa,
182 Ffexs,
184 Ef,
186 Dcos,
188 Ktlep,
190 Dcws,
192 Dcsv,
194 Dcpc,
196 Dcmems,
198 Dcdx,
200 Dcas,
202 Dcbs,
204 Dc2fl,
206 Dc2bs,
208 Dc2dm,
210 Dc2fy,
212 Dc2cckko,
214 Dc2ccotm,
216 Dc2sc,
218 Dc2ty,
220 Dc2pc,
222 Dc3rx,
224 Dc3pp,
226 Dc3wy,
228 Dc3dd,
230 Dc4,
232 Dc4ph,
234 Ds,
236 Dsif,
238 Tmpl,
240 Nightshade,
242}
243
244#[cfg(feature = "circus")]
245impl AsRef<str> for CircusMesType {
246 fn as_ref(&self) -> &str {
248 match self {
249 CircusMesType::Ffexa => "ffexa",
250 CircusMesType::Ffexs => "ffexs",
251 CircusMesType::Ef => "ef",
252 CircusMesType::Dcos => "dcos",
253 CircusMesType::Ktlep => "ktlep",
254 CircusMesType::Dcws => "dcws",
255 CircusMesType::Dcsv => "dcsv",
256 CircusMesType::Dcpc => "dcpc",
257 CircusMesType::Dcmems => "dcmems",
258 CircusMesType::Dcdx => "dcdx",
259 CircusMesType::Dcas => "dcas",
260 CircusMesType::Dcbs => "dcbs",
261 CircusMesType::Dc2fl => "dc2fl",
262 CircusMesType::Dc2bs => "dc2bs",
263 CircusMesType::Dc2dm => "dc2dm",
264 CircusMesType::Dc2fy => "dc2fy",
265 CircusMesType::Dc2cckko => "dc2cckko",
266 CircusMesType::Dc2ccotm => "dc2ccotm",
267 CircusMesType::Dc2sc => "dc2sc",
268 CircusMesType::Dc2ty => "dc2ty",
269 CircusMesType::Dc2pc => "dc2pc",
270 CircusMesType::Dc3rx => "dc3rx",
271 CircusMesType::Dc3pp => "dc3pp",
272 CircusMesType::Dc3wy => "dc3wy",
273 CircusMesType::Dc3dd => "dc3dd",
274 CircusMesType::Dc4 => "dc4",
275 CircusMesType::Dc4ph => "dc4ph",
276 CircusMesType::Ds => "ds",
277 CircusMesType::Dsif => "dsif",
278 CircusMesType::Tmpl => "tmpl",
279 CircusMesType::Nightshade => "nightshade",
280 }
281 }
282}
283
284#[derive(Debug, Clone, msg_tool_macro::Default)]
286pub struct ExtraConfig {
287 #[cfg(feature = "circus")]
288 pub circus_mes_type: Option<CircusMesType>,
290 #[cfg(feature = "escude-arc")]
291 pub escude_fake_compress: bool,
293 #[cfg(feature = "escude")]
294 pub escude_enum_scr: Option<String>,
296 #[cfg(feature = "bgi")]
297 pub bgi_import_duplicate: bool,
300 #[cfg(feature = "bgi")]
301 pub bgi_disable_append: bool,
304 #[cfg(feature = "image")]
305 pub image_type: Option<ImageOutputType>,
307 #[cfg(all(feature = "bgi-arc", feature = "bgi-img"))]
308 pub bgi_is_sysgrp_arc: Option<bool>,
310 #[cfg(feature = "bgi-img")]
311 pub bgi_img_scramble: Option<bool>,
314 #[cfg(feature = "cat-system-arc")]
315 pub cat_system_int_encrypt_password: Option<String>,
317 #[cfg(feature = "cat-system-img")]
318 pub cat_system_image_canvas: bool,
320 #[cfg(feature = "kirikiri")]
321 pub kirikiri_language_index: Option<usize>,
323 #[cfg(feature = "kirikiri")]
324 pub kirikiri_export_chat: bool,
327 #[cfg(feature = "kirikiri")]
328 pub kirikiri_chat_key: Option<Vec<String>>,
331 #[cfg(feature = "kirikiri")]
332 pub kirikiri_chat_json:
335 Option<std::sync::Arc<HashMap<String, HashMap<String, (String, usize)>>>>,
336 #[cfg(feature = "kirikiri")]
337 pub kirikiri_languages: Option<std::sync::Arc<Vec<String>>>,
339 #[cfg(feature = "kirikiri")]
340 pub kirikiri_remove_empty_lines: bool,
342 #[cfg(feature = "kirikiri")]
343 pub kirikiri_name_commands: std::sync::Arc<std::collections::HashSet<String>>,
345 #[cfg(feature = "kirikiri")]
346 pub kirikiri_message_commands: std::sync::Arc<std::collections::HashSet<String>>,
348 #[cfg(feature = "bgi-arc")]
349 pub bgi_compress_file: bool,
351 #[cfg(feature = "bgi-arc")]
352 #[default(9)]
353 pub bgi_compress_level: u8,
356 #[cfg(feature = "emote-img")]
357 pub emote_pimg_overlay: Option<bool>,
359 #[cfg(feature = "artemis-arc")]
360 pub artemis_arc_disable_xor: bool,
362 #[cfg(feature = "artemis")]
363 pub artemis_indent: Option<usize>,
366 #[cfg(feature = "artemis")]
367 pub artemis_no_indent: bool,
369 #[cfg(feature = "artemis")]
370 #[default(100)]
371 pub artemis_max_line_width: usize,
373 #[cfg(feature = "artemis")]
374 pub artemis_ast_lang: Option<String>,
377 #[cfg(feature = "cat-system")]
378 pub cat_system_cstl_lang: Option<String>,
381 #[cfg(feature = "flate2")]
382 #[default(6)]
383 pub zlib_compression_level: u32,
385 #[cfg(feature = "image")]
386 pub png_compression_level: PngCompressionLevel,
388 #[cfg(feature = "circus-img")]
389 pub circus_crx_keep_original_bpp: bool,
391 #[cfg(feature = "circus-img")]
392 pub circus_crx_zstd: bool,
394 #[cfg(feature = "zstd")]
395 #[default(3)]
396 pub zstd_compression_level: i32,
398 #[cfg(feature = "circus-img")]
399 pub circus_crx_mode: crate::scripts::circus::image::crx::CircusCrxMode,
401 #[cfg(feature = "ex-hibit")]
402 pub ex_hibit_rld_xor_key: Option<u32>,
405 #[cfg(feature = "ex-hibit")]
406 pub ex_hibit_rld_def_xor_key: Option<u32>,
408 #[cfg(feature = "ex-hibit")]
409 pub ex_hibit_rld_keys: Option<Box<[u32; 0x100]>>,
411 #[cfg(feature = "ex-hibit")]
412 pub ex_hibit_rld_def_keys: Option<Box<[u32; 0x100]>>,
414 #[cfg(feature = "mozjpeg")]
415 #[default(80)]
416 pub jpeg_quality: u8,
418 #[cfg(feature = "webp")]
419 pub webp_lossless: bool,
421 #[cfg(feature = "webp")]
422 #[default(80)]
423 pub webp_quality: u8,
425 #[cfg(feature = "circus-img")]
426 pub circus_crx_canvas: bool,
428 pub custom_yaml: bool,
430 #[cfg(feature = "entis-gls")]
431 pub entis_gls_srcxml_lang: Option<String>,
434 #[cfg(feature = "will-plus")]
435 pub will_plus_ws2_no_disasm: bool,
439 #[cfg(feature = "artemis-panmimisoft")]
440 pub artemis_panmimisoft_txt_blacklist_names: std::sync::Arc<std::collections::HashSet<String>>,
443 #[cfg(feature = "artemis-panmimisoft")]
444 pub artemis_panmimisoft_txt_lang: Option<String>,
447 #[cfg(feature = "artemis-panmimisoft")]
448 pub artemis_panmimisoft_txt_multi_lang: bool,
451 #[cfg(feature = "lossless-audio")]
452 pub lossless_audio_fmt: LosslessAudioFormat,
454 #[cfg(feature = "audio-flac")]
455 #[default(5)]
456 pub flac_compression_level: u32,
458 #[cfg(feature = "artemis")]
459 #[default(true)]
460 pub artemis_asb_format_lua: bool,
462 #[cfg(feature = "kirikiri")]
463 pub kirikiri_title: bool,
465 #[cfg(feature = "favorite")]
466 #[default(true)]
467 pub favorite_hcb_filter_ascii: bool,
469 #[cfg(feature = "bgi-img")]
470 #[default(get_default_threads())]
471 pub bgi_img_workers: usize,
474 #[cfg(feature = "image-jxl")]
475 #[default(true)]
476 pub jxl_lossless: bool,
478 #[cfg(feature = "image-jxl")]
479 #[default(1.0)]
480 pub jxl_distance: f32,
483 #[cfg(feature = "image-jxl")]
484 #[default(1)]
485 pub jxl_workers: usize,
488 #[cfg(feature = "emote-img")]
489 #[default(true)]
490 pub psb_process_tlg: bool,
492 #[cfg(feature = "softpal-img")]
493 #[default(true)]
494 pub pgd_fake_compress: bool,
497 #[cfg(feature = "softpal")]
498 pub softpal_add_message_index: bool,
500 #[cfg(feature = "kirikiri")]
501 #[default(true)]
502 pub kirikiri_chat_multilang: bool,
505 #[cfg(feature = "kirikiri-arc")]
506 #[default(true)]
507 pub xp3_simple_crypt: bool,
509 #[cfg(feature = "kirikiri-arc")]
510 #[default(true)]
511 pub xp3_mdf_decompress: bool,
513 #[cfg(feature = "kirikiri-arc")]
514 pub xp3_segmenter: crate::scripts::kirikiri::archive::xp3::SegmenterConfig,
516 #[cfg(feature = "kirikiri-arc")]
517 #[default(true)]
518 pub xp3_compress_files: bool,
520 #[cfg(feature = "kirikiri-arc")]
521 #[default(true)]
522 pub xp3_compress_index: bool,
524 #[cfg(feature = "kirikiri-arc")]
525 #[default(num_cpus::get())]
526 pub xp3_compress_workers: usize,
528 #[cfg(feature = "kirikiri-arc")]
529 pub xp3_zstd: bool,
531 #[cfg(feature = "kirikiri-arc")]
532 pub xp3_zopfli: bool,
534 #[cfg(feature = "kirikiri-arc")]
535 #[default(1)]
536 pub xp3_pack_workers: usize,
539 #[cfg(feature = "kirikiri-arc")]
540 pub xp3_no_adler: bool,
543 #[cfg(feature = "kirikiri")]
544 pub kirikiri_language_insert: bool,
546 #[cfg(feature = "musica-arc")]
547 pub musica_game_title: Option<String>,
549 #[cfg(feature = "musica-arc")]
550 pub musica_xor_key: Option<u8>,
552 #[cfg(feature = "musica-arc")]
553 pub musica_compress: bool,
555 #[cfg(feature = "bgi")]
556 pub bgi_add_space: bool,
559 #[cfg(feature = "escude")]
560 pub escude_op: Option<crate::scripts::escude::script::EscudeOp>,
562 #[cfg(feature = "zopfli")]
563 #[default(std::num::NonZeroU64::new(15).unwrap())]
564 pub zopfli_iteration_count: std::num::NonZeroU64,
568 #[cfg(feature = "zopfli")]
569 #[default(std::num::NonZeroU64::new(u64::MAX).unwrap())]
570 pub zopfli_iterations_without_improvement: std::num::NonZeroU64,
573 #[cfg(feature = "zopfli")]
574 #[default(15)]
575 pub zopfli_maximum_block_splits: u16,
578 #[cfg(feature = "entis-gls")]
579 pub entis_gls_csx_disasm: bool,
581 #[cfg(feature = "entis-gls")]
582 #[default(String::from("/"))]
583 pub entis_gls_csx_lf: String,
585 #[cfg(feature = "entis-gls")]
586 pub entis_gls_csx_ver: Option<crate::scripts::entis_gls::csx::CSXScriptVersion>,
589 #[cfg(feature = "entis-gls")]
590 pub entis_gls_csx_v2_ver: Option<crate::scripts::entis_gls::csx::CSXScriptV2FullVer>,
593 #[cfg(feature = "entis-gls")]
594 pub entis_gls_csx_no_part_label: bool,
596 #[cfg(feature = "qlie-img")]
597 #[default(true)]
598 pub qlie_abmp10_process_abmp10: bool,
600 #[cfg(feature = "qlie-arc")]
601 pub qlie_pack_keyfile: Option<String>,
603 #[cfg(feature = "qlie-arc")]
604 pub qlie_pack_compress_files: bool,
606 #[cfg(feature = "qlie-img")]
607 pub qlie_dpng_use_raw_png: bool,
610 #[cfg(feature = "qlie-img")]
611 pub qlie_dpng_psd: bool,
613 #[cfg(feature = "utils-psd")]
614 #[default(true)]
615 pub psd_compress: bool,
617 #[cfg(feature = "emote-img")]
618 pub emote_pimg_psd: bool,
620 #[cfg(feature = "kirikiri")]
621 pub kirikiri_ks_hitret: Option<bool>,
623 #[cfg(feature = "kirikiri")]
624 pub kirikiri_ks_lf: Option<String>,
626 #[cfg(feature = "kirikiri")]
627 pub kirikiri_message_tags: std::sync::Arc<std::collections::HashSet<String>>,
629 #[cfg(feature = "kirikiri")]
630 pub kirikiri_ks_bom: Option<BomType>,
632 #[cfg(feature = "emote-img")]
633 pub bc7: crate::scripts::emote::psb::BC7Config,
635 #[cfg(feature = "artemis")]
636 #[default(default_artemis_asb_end_tags())]
637 pub artemis_asb_end_tags: std::sync::Arc<std::collections::HashSet<String>>,
639 #[cfg(feature = "kirikiri-arc")]
640 pub xp3_game_title: Option<String>,
642 #[cfg(feature = "kirikiri-arc")]
643 pub xp3_debug_archive: bool,
646 #[cfg(feature = "kirikiri-arc")]
647 pub xp3_force_extract: bool,
649 #[cfg(feature = "kirikiri-arc")]
650 pub xp3_force_decrypt: bool,
653 #[cfg(feature = "emote-img")]
654 pub emote_pimg_psd_no_diff: bool,
657 #[cfg(feature = "kirikiri-arc")]
658 pub xp3_file_list_path: Option<String>,
661 #[cfg(feature = "kirikiri-arc")]
662 pub xp3_cxdec_file_hash: crate::scripts::kirikiri::archive::xp3::FileHashOption,
664 #[cfg(feature = "kirikiri-arc")]
665 pub xp3_cxdec_path_hash: crate::scripts::kirikiri::archive::xp3::PathHashOption,
667 #[cfg(feature = "yuris")]
668 pub yuris_ysc_path: Option<String>,
670 #[cfg(feature = "yuris")]
671 pub yuris_ysl_path: Option<String>,
673 #[cfg(feature = "yuris")]
674 pub yuris_ystb_disasm: bool,
676 #[cfg(feature = "yuris")]
677 pub yuris_tips_map: Option<std::sync::Arc<std::collections::HashMap<String, String>>>,
679 #[cfg(feature = "bgi-arc")]
680 #[default(num_cpus::get())]
681 pub bgi_arc_workers: usize,
683 #[cfg(feature = "yuris-arc")]
684 pub yuris_name_hash_type: crate::scripts::yuris::arc::ypf::NameHashType,
686 #[cfg(feature = "yuris-arc")]
687 pub yuris_data_hash_type: crate::scripts::yuris::arc::ypf::DataHashType,
689 #[cfg(feature = "yuris-arc")]
690 pub yuris_check_hash: bool,
692 #[cfg(feature = "yuris-arc")]
693 pub yuris_debug_archive: bool,
696 #[cfg(feature = "yuris-arc")]
697 pub yuris_ypf_version: Option<u32>,
699 #[cfg(feature = "yuris-arc")]
700 #[default(true)]
701 pub yuris_ypf_compress_file: bool,
703 #[cfg(feature = "yuris-arc")]
704 pub yuris_ypf_zopfli: bool,
706 #[cfg(feature = "yuris-arc")]
707 #[default(num_cpus::get())]
708 pub yuris_ypf_workers: usize,
710 #[cfg(feature = "yuris-arc")]
711 pub yuris_use_new_file_type: bool,
714 #[cfg(feature = "kirikiri-arc")]
715 pub xp3_dump_file_hash_list: Option<String>,
717}
718
719#[cfg(feature = "artemis")]
720fn default_artemis_asb_end_tags() -> std::sync::Arc<std::collections::HashSet<String>> {
721 std::sync::Arc::new(
722 ["click", "hcls", "rpx"]
723 .into_iter()
724 .map(String::from)
725 .collect(),
726 )
727}
728
729#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
730pub enum ScriptType {
732 #[cfg(feature = "artemis")]
733 Artemis,
735 #[cfg(feature = "artemis")]
736 ArtemisAsb,
738 #[cfg(feature = "artemis")]
739 ArtemisTxt,
741 #[cfg(feature = "artemis-panmimisoft")]
742 ArtemisPanmimisoftTxt,
744 #[cfg(feature = "artemis-arc")]
745 #[value(alias("pfs"))]
746 ArtemisArc,
748 #[cfg(feature = "artemis-arc")]
749 #[value(alias("pf2"))]
750 ArtemisPf2,
752 #[cfg(feature = "bgi")]
753 #[value(alias("ethornell"))]
754 BGI,
756 #[cfg(feature = "bgi")]
757 #[value(alias("ethornell-bsi"))]
758 BGIBsi,
760 #[cfg(feature = "bgi")]
761 #[value(alias("ethornell-bp"))]
762 BGIBp,
764 #[cfg(feature = "bgi-arc")]
765 #[value(alias = "ethornell-arc-v1")]
766 BGIArcV1,
768 #[cfg(feature = "bgi-arc")]
769 #[value(alias = "ethornell-arc-v2", alias = "bgi-arc", alias = "ethornell-arc")]
770 BGIArcV2,
772 #[cfg(feature = "bgi-arc")]
773 #[value(alias("ethornell-dsc"))]
774 BGIDsc,
776 #[cfg(feature = "bgi-audio")]
777 #[value(alias("ethornell-audio"))]
778 BGIAudio,
780 #[cfg(feature = "bgi-img")]
781 #[value(alias("ethornell-img"))]
782 BGIImg,
784 #[cfg(feature = "bgi-img")]
785 #[value(alias("ethornell-cbg"))]
786 BGICbg,
788 #[cfg(feature = "cat-system")]
789 CatSystem,
791 #[cfg(feature = "cat-system")]
792 CatSystemCstl,
794 #[cfg(feature = "cat-system-arc")]
795 CatSystemInt,
797 #[cfg(feature = "cat-system-img")]
798 CatSystemHg3,
800 #[cfg(feature = "circus")]
801 Circus,
803 #[cfg(feature = "circus-arc")]
804 CircusCrm,
806 #[cfg(feature = "circus-arc")]
807 CircusDat,
809 #[cfg(feature = "circus-arc")]
810 CircusPck,
812 #[cfg(feature = "circus-audio")]
813 CircusPcm,
815 #[cfg(feature = "circus-img")]
816 CircusCrx,
818 #[cfg(feature = "circus-img")]
819 CircusCrxd,
821 #[cfg(feature = "emote-img")]
822 #[value(alias("psb"))]
823 EmotePsb,
825 #[cfg(feature = "emote-img")]
826 #[value(alias("pimg"))]
827 EmotePimg,
829 #[cfg(feature = "emote-img")]
830 #[value(alias("dref"))]
831 EmoteDref,
833 #[cfg(feature = "entis-gls")]
834 EntisGls,
836 #[cfg(feature = "entis-gls")]
837 EntisGlsCsx,
839 #[cfg(feature = "escude-arc")]
840 EscudeArc,
842 #[cfg(feature = "escude")]
843 Escude,
845 #[cfg(feature = "escude")]
846 EscudeList,
848 #[cfg(feature = "ex-hibit")]
849 ExHibit,
851 #[cfg(feature = "ex-hibit-arc")]
852 ExHibitGrp,
854 #[cfg(feature = "favorite")]
855 Favorite,
857 #[cfg(feature = "hexen-haus")]
858 HexenHaus,
860 #[cfg(feature = "hexen-haus-arc")]
861 HexenHausArcc,
863 #[cfg(feature = "hexen-haus-arc")]
864 HexenHausOdio,
866 #[cfg(feature = "hexen-haus-arc")]
867 HexenHausWag,
869 #[cfg(feature = "hexen-haus-img")]
870 HexenHausPng,
872 #[cfg(feature = "kirikiri")]
873 #[value(alias("kr-scn"))]
874 KirikiriScn,
876 #[cfg(feature = "kirikiri")]
877 #[value(alias("kr-simple-crypt"))]
878 KirikiriSimpleCrypt,
880 #[cfg(feature = "kirikiri")]
881 #[value(alias = "kr", alias = "kr-ks", alias = "kirikiri-ks")]
882 Kirikiri,
884 #[cfg(feature = "kirikiri-arc")]
885 #[value(alias = "kr-xp3", alias = "xp3")]
886 KirikiriXp3,
888 #[cfg(feature = "kirikiri-img")]
889 #[value(alias("kr-tlg"))]
890 KirikiriTlg,
892 #[cfg(feature = "kirikiri")]
893 #[value(alias("kr-mdf"))]
894 KirikiriMdf,
896 #[cfg(feature = "kirikiri")]
897 #[value(alias("kr-tjs2"))]
898 KirikiriTjs2,
900 #[cfg(feature = "kirikiri")]
901 #[value(alias("kr-tjs-ns0"))]
902 KirikiriTjsNs0,
904 #[cfg(feature = "musica")]
905 Musica,
907 #[cfg(feature = "musica-arc")]
908 MusicaPaz,
910 #[cfg(feature = "qlie")]
911 Qlie,
913 #[cfg(feature = "qlie-arc")]
914 QliePack,
916 #[cfg(feature = "qlie-img")]
917 QlieDpng,
919 #[cfg(feature = "qlie-img")]
920 #[value(alias = "qlie-abmp11", alias = "qlie-abmp12")]
921 QlieAbmp10,
923 #[cfg(feature = "silky")]
924 Silky,
926 #[cfg(feature = "silky")]
927 SilkyMap,
929 #[cfg(feature = "softpal")]
930 Softpal,
932 #[cfg(feature = "softpal-arc")]
933 SoftpalPac,
935 #[cfg(feature = "softpal-arc")]
936 SoftpalPacAmuse,
938 #[cfg(feature = "softpal-img")]
939 #[value(alias = "pgd-ge", alias = "pgd")]
940 SoftpalPgdGe,
942 #[cfg(feature = "softpal-img")]
943 #[value(alias = "softpal-pgd2", alias = "pgd3", alias = "pgd2")]
944 SoftpalPgd3,
946 #[cfg(feature = "will-plus")]
947 #[value(alias("adv-hd-ws2"))]
948 WillPlusWs2,
950 #[cfg(feature = "will-plus-img")]
951 #[value(alias("adv-hd-wip"))]
952 WillPlusWip,
954 #[cfg(feature = "yaneurao-itufuru")]
955 #[value(alias("itufuru"))]
956 YaneuraoItufuru,
958 #[cfg(feature = "yaneurao-itufuru")]
959 #[value(alias("itufuru-arc"))]
960 YaneuraoItufuruArc,
962 #[cfg(feature = "yuris")]
963 YurisYSCM,
965 #[cfg(feature = "yuris")]
966 YurisYSER,
968 #[cfg(feature = "yuris")]
969 YurisYSCFG,
971 #[cfg(feature = "yuris")]
972 YurisYSTB,
974 #[cfg(feature = "yuris")]
975 YurisTxt,
977 #[cfg(feature = "yuris")]
978 YurisYSTL,
980 #[cfg(feature = "yuris")]
981 YurisYSLB,
983 #[cfg(feature = "yuris")]
984 YurisYSVR,
986 #[cfg(feature = "yuris")]
987 YurisYSTD,
989 #[cfg(feature = "yuris-arc")]
990 YurisYPF,
992 #[cfg(feature = "yuris-img")]
993 YurisYDG,
995}
996
997#[derive(Clone, Debug, Serialize, Deserialize)]
998pub struct Message {
1000 #[serde(skip_serializing_if = "Option::is_none")]
1001 pub name: Option<String>,
1003 pub message: String,
1005}
1006
1007impl Message {
1008 pub fn new(message: String, name: Option<String>) -> Self {
1010 Message { message, name }
1011 }
1012}
1013
1014#[derive(Clone, Debug)]
1015pub struct ExtendedMessage {
1017 pub name: Option<String>,
1019 pub source: String,
1021 pub translated: String,
1023 pub llm: Option<String>,
1025}
1026
1027pub enum ScriptResult {
1029 Ok,
1031 Ignored,
1034 Uncount,
1037}
1038
1039#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1040pub enum FormatType {
1042 Fixed,
1044 None,
1046}
1047
1048#[derive(Clone)]
1049pub enum FormatOptions {
1051 Fixed {
1053 length: usize,
1055 keep_original: bool,
1057 break_words: bool,
1059 insert_fullwidth_space_at_line_start: bool,
1061 break_with_sentence: bool,
1063 #[cfg(feature = "jieba")]
1064 break_chinese_words: bool,
1066 #[cfg(feature = "jieba")]
1067 jieba_dict: Option<String>,
1069 no_remove_space_at_line_start: bool,
1071 },
1072 None,
1074}
1075
1076#[derive(Debug, Serialize, Deserialize)]
1077pub struct NameTableCell {
1079 #[serde(rename = "JP_Name")]
1080 pub jp_name: String,
1082 #[serde(rename = "CN_Name")]
1083 pub cn_name: String,
1085 #[serde(rename = "Count")]
1086 pub count: usize,
1088}
1089
1090#[derive(Debug, Serialize, Deserialize)]
1091pub struct ReplacementTable {
1093 #[serde(flatten)]
1094 pub map: HashMap<String, String>,
1096}
1097
1098#[cfg(feature = "image")]
1099#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1100pub enum ImageColorType {
1102 Grayscale,
1104 Rgb,
1106 Rgba,
1108 Bgr,
1110 Bgra,
1112}
1113
1114#[cfg(feature = "image")]
1115impl ImageColorType {
1116 pub fn bpp(&self, depth: u8) -> u16 {
1118 match self {
1119 ImageColorType::Grayscale => depth as u16,
1120 ImageColorType::Rgb => depth as u16 * 3,
1121 ImageColorType::Rgba => depth as u16 * 4,
1122 ImageColorType::Bgr => depth as u16 * 3,
1123 ImageColorType::Bgra => depth as u16 * 4,
1124 }
1125 }
1126}
1127
1128#[cfg(feature = "image")]
1129#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1130pub enum ImageOutputType {
1132 Png,
1134 #[cfg(feature = "image-jpg")]
1135 Jpg,
1137 #[cfg(feature = "image-webp")]
1138 Webp,
1140 #[cfg(feature = "image-jxl")]
1141 Jxl,
1143}
1144
1145#[cfg(feature = "image")]
1146impl TryFrom<&str> for ImageOutputType {
1147 type Error = anyhow::Error;
1148
1149 fn try_from(value: &str) -> Result<Self, Self::Error> {
1152 match value.to_ascii_lowercase().as_str() {
1153 "png" => Ok(ImageOutputType::Png),
1154 #[cfg(feature = "image-jpg")]
1155 "jpg" => Ok(ImageOutputType::Jpg),
1156 #[cfg(feature = "image-jpg")]
1157 "jpeg" => Ok(ImageOutputType::Jpg),
1158 #[cfg(feature = "image-webp")]
1159 "webp" => Ok(ImageOutputType::Webp),
1160 #[cfg(feature = "image-jxl")]
1161 "jxl" => Ok(ImageOutputType::Jxl),
1162 _ => Err(anyhow::anyhow!("Unsupported image output type: {}", value)),
1163 }
1164 }
1165}
1166
1167#[cfg(feature = "image")]
1168impl TryFrom<&std::path::Path> for ImageOutputType {
1169 type Error = anyhow::Error;
1170
1171 fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
1172 if let Some(ext) = value.extension() {
1173 Self::try_from(ext.to_string_lossy().as_ref())
1174 } else {
1175 Err(anyhow::anyhow!("No extension found in path"))
1176 }
1177 }
1178}
1179
1180#[cfg(feature = "image")]
1181impl AsRef<str> for ImageOutputType {
1182 fn as_ref(&self) -> &str {
1184 match self {
1185 ImageOutputType::Png => "png",
1186 #[cfg(feature = "image-jpg")]
1187 ImageOutputType::Jpg => "jpg",
1188 #[cfg(feature = "image-webp")]
1189 ImageOutputType::Webp => "webp",
1190 #[cfg(feature = "image-jxl")]
1191 ImageOutputType::Jxl => "jxl",
1192 }
1193 }
1194}
1195
1196#[cfg(feature = "image")]
1197#[derive(Clone, Debug)]
1198pub struct ImageData {
1200 pub width: u32,
1202 pub height: u32,
1204 pub color_type: ImageColorType,
1206 pub depth: u8,
1208 pub data: Vec<u8>,
1210}
1211
1212#[cfg(feature = "image")]
1213#[derive(Clone, Debug)]
1214pub struct ImageDataWithName {
1216 pub name: String,
1218 pub data: ImageData,
1220}
1221
1222#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1223pub enum BomType {
1225 None,
1227 Utf8,
1229 Utf16LE,
1231 Utf16BE,
1233}
1234
1235impl BomType {
1236 pub fn as_bytes(&self) -> &'static [u8] {
1238 match self {
1239 BomType::None => &[],
1240 BomType::Utf8 => b"\xEF\xBB\xBF",
1241 BomType::Utf16LE => b"\xFF\xFE",
1242 BomType::Utf16BE => b"\xFE\xFF",
1243 }
1244 }
1245}
1246
1247#[cfg(feature = "image")]
1248#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1249pub enum PngCompressionLevel {
1251 #[value(alias = "n")]
1252 NoCompression,
1254 #[value(alias = "d")]
1255 Default,
1257 Fastest,
1263 #[value(alias = "f")]
1264 Fast,
1266 #[value(alias = "b")]
1267 Best,
1269 #[value(alias = "h")]
1270 High,
1272}
1273
1274#[cfg(feature = "image")]
1275impl Default for PngCompressionLevel {
1276 fn default() -> Self {
1277 PngCompressionLevel::Default
1278 }
1279}
1280
1281#[cfg(feature = "image")]
1282impl PngCompressionLevel {
1283 pub fn to_compression(&self) -> png::Compression {
1285 match self {
1286 PngCompressionLevel::NoCompression => png::Compression::NoCompression,
1287 PngCompressionLevel::Fastest => png::Compression::Fastest,
1288 PngCompressionLevel::Default => png::Compression::Balanced,
1289 PngCompressionLevel::Fast => png::Compression::Fast,
1290 PngCompressionLevel::Best => png::Compression::High,
1291 PngCompressionLevel::High => png::Compression::High,
1292 }
1293 }
1294}
1295
1296#[cfg(feature = "lossless-audio")]
1297#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
1298pub enum LosslessAudioFormat {
1300 Wav,
1302 #[cfg(feature = "audio-flac")]
1303 Flac,
1305}
1306
1307#[cfg(feature = "lossless-audio")]
1308impl Default for LosslessAudioFormat {
1309 fn default() -> Self {
1310 LosslessAudioFormat::Wav
1311 }
1312}
1313
1314#[cfg(feature = "lossless-audio")]
1315impl TryFrom<&str> for LosslessAudioFormat {
1316 type Error = anyhow::Error;
1317 fn try_from(value: &str) -> Result<Self, Self::Error> {
1320 match value.to_ascii_lowercase().as_str() {
1321 "wav" => Ok(LosslessAudioFormat::Wav),
1322 #[cfg(feature = "audio-flac")]
1323 "flac" => Ok(LosslessAudioFormat::Flac),
1324 _ => Err(anyhow::anyhow!(
1325 "Unsupported lossless audio format: {}",
1326 value
1327 )),
1328 }
1329 }
1330}
1331
1332#[cfg(feature = "lossless-audio")]
1333impl TryFrom<&std::path::Path> for LosslessAudioFormat {
1334 type Error = anyhow::Error;
1335
1336 fn try_from(value: &std::path::Path) -> Result<Self, Self::Error> {
1337 if let Some(ext) = value.extension() {
1338 Self::try_from(ext.to_string_lossy().as_ref())
1339 } else {
1340 Err(anyhow::anyhow!("No extension found in path"))
1341 }
1342 }
1343}
1344
1345#[cfg(feature = "lossless-audio")]
1346impl AsRef<str> for LosslessAudioFormat {
1347 fn as_ref(&self) -> &str {
1349 match self {
1350 LosslessAudioFormat::Wav => "wav",
1351 #[cfg(feature = "audio-flac")]
1352 LosslessAudioFormat::Flac => "flac",
1353 }
1354 }
1355}
1356
1357#[allow(unused)]
1358pub(crate) fn get_default_threads() -> usize {
1359 num_cpus::get().max(2) / 2
1360}