mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-16 18:14:19 +08:00
Add zopfli support for xp3 pack
This commit is contained in:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -184,6 +184,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.9"
|
||||
@@ -1371,6 +1377,7 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"xml5ever",
|
||||
"xp3",
|
||||
"zopfli",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
@@ -2538,6 +2545,18 @@ dependencies = [
|
||||
"syn 2.0.111",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"log",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
|
||||
@@ -54,6 +54,7 @@ utf16string = "0.2"
|
||||
webp = { version = "0.3", default-features = false, optional = true }
|
||||
xml5ever = { version = "0.36", optional = true }
|
||||
xp3 = { version = "0.3", optional = true}
|
||||
zopfli = { version = "0.8", optional = true }
|
||||
zstd = { version = "0.13", optional = true }
|
||||
|
||||
[features]
|
||||
@@ -88,7 +89,7 @@ hexen-haus = ["memchr", "utils-str"]
|
||||
hexen-haus-arc = ["hexen-haus"]
|
||||
hexen-haus-img = ["hexen-haus", "image"]
|
||||
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
||||
kirikiri-arc = ["kirikiri", "adler", "fastcdc", "flate2", "parse-size", "sha2", "xp3", "zstd"]
|
||||
kirikiri-arc = ["kirikiri", "adler", "fastcdc", "flate2", "parse-size", "sha2", "xp3", "zopfli", "zstd"]
|
||||
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
||||
musica = []
|
||||
musica-arc = ["musica", "crc32fast", "flate2", "include-flate", "utils-blowfish", "utils-rc4", "utils-serde-base64bytes", "utils-xored-stream"]
|
||||
|
||||
23
src/args.rs
23
src/args.rs
@@ -106,6 +106,7 @@ pub fn get_musica_game_title_value_parser() -> Vec<clap::builder::PossibleValue>
|
||||
group = ArgGroup::new("webp_qualityg").multiple(false),
|
||||
group = ArgGroup::new("cat_system_int_encrypt_passwordg").multiple(false),
|
||||
group = ArgGroup::new("kirikiri_chat_jsong").multiple(false),
|
||||
group = ArgGroup::new("xp3-compression").multiple(false),
|
||||
)]
|
||||
#[command(
|
||||
version,
|
||||
@@ -539,10 +540,14 @@ pub struct Arg {
|
||||
/// Workers count for compress files in Kirikiri XP3 archive when creating in parallel.
|
||||
pub xp3_compress_workers: usize,
|
||||
#[cfg(feature = "kirikiri-arc")]
|
||||
#[arg(long, global = true)]
|
||||
#[arg(long, global = true, group = "xp3-compression")]
|
||||
/// 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")]
|
||||
#[arg(long, global = true, group = "xp3-compression")]
|
||||
/// Use zopfli compression for files in Kirikiri XP3 archive when creating. This is very slow.
|
||||
pub xp3_zopfli: bool,
|
||||
#[cfg(feature = "kirikiri-arc")]
|
||||
#[arg(
|
||||
long,
|
||||
global = true,
|
||||
@@ -587,6 +592,22 @@ pub struct Arg {
|
||||
/// 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 = "zopfli")]
|
||||
#[arg(long, global = true, default_value_t = std::num::NonZeroU64::new(15).unwrap(), visible_alias = "zp-ic")]
|
||||
/// 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")]
|
||||
#[arg(long, global = true, default_value_t = std::num::NonZeroU64::new(u64::MAX).unwrap(), visible_alias = "zp-iwi")]
|
||||
/// 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")]
|
||||
#[arg(long, global = true, default_value_t = 15, visible_alias = "zp-mbs")]
|
||||
/// 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,
|
||||
#[command(subcommand)]
|
||||
/// Command
|
||||
pub command: Command,
|
||||
|
||||
@@ -3280,6 +3280,8 @@ fn main() {
|
||||
#[cfg(feature = "kirikiri-arc")]
|
||||
xp3_zstd: arg.xp3_zstd,
|
||||
#[cfg(feature = "kirikiri-arc")]
|
||||
xp3_zopfli: arg.xp3_zopfli,
|
||||
#[cfg(feature = "kirikiri-arc")]
|
||||
xp3_pack_workers: arg.xp3_pack_workers,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_language_insert: arg.kirikiri_language_insert,
|
||||
@@ -3295,6 +3297,12 @@ fn main() {
|
||||
bgi_add_space: arg.bgi_add_space,
|
||||
#[cfg(feature = "escude")]
|
||||
escude_op: arg.escude_op,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iteration_count: arg.zopfli_iteration_count,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iterations_without_improvement: arg.zopfli_iterations_without_improvement,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_maximum_block_splits: arg.zopfli_maximum_block_splits,
|
||||
});
|
||||
match &arg.command {
|
||||
args::Command::Export { input, output } => {
|
||||
|
||||
@@ -76,6 +76,14 @@ pub struct Xp3ArchiveWriter<T: Write + Seek> {
|
||||
use_zstd: bool,
|
||||
zstd_compression_level: i32,
|
||||
no_adler: bool,
|
||||
#[cfg(feature = "zopfli")]
|
||||
use_zopfli: bool,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iteration_count: std::num::NonZeroU64,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iterations_without_improvement: std::num::NonZeroU64,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_maximum_block_splits: u16,
|
||||
}
|
||||
|
||||
impl Xp3ArchiveWriter<std::io::BufWriter<std::fs::File>> {
|
||||
@@ -119,6 +127,14 @@ impl Xp3ArchiveWriter<std::io::BufWriter<std::fs::File>> {
|
||||
use_zstd: config.xp3_zstd,
|
||||
zstd_compression_level: config.zstd_compression_level,
|
||||
no_adler: config.xp3_no_adler,
|
||||
#[cfg(feature = "zopfli")]
|
||||
use_zopfli: config.xp3_zopfli,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iteration_count: config.zopfli_iteration_count,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_iterations_without_improvement: config.zopfli_iterations_without_improvement,
|
||||
#[cfg(feature = "zopfli")]
|
||||
zopfli_maximum_block_splits: config.zopfli_maximum_block_splits,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -219,6 +235,14 @@ impl<T: Write + Seek + Sync + Send + 'static> Archive for Xp3ArchiveWriter<T> {
|
||||
};
|
||||
let processiong_segments = self.processing_segments.clone();
|
||||
let use_zstd = self.use_zstd;
|
||||
#[cfg(feature = "zopfli")]
|
||||
let use_zopfli = self.use_zopfli;
|
||||
#[cfg(feature = "zopfli")]
|
||||
let zopfli_iteration_count = self.zopfli_iteration_count;
|
||||
#[cfg(feature = "zopfli")]
|
||||
let zopfli_iterations_without_improvement = self.zopfli_iterations_without_improvement;
|
||||
#[cfg(feature = "zopfli")]
|
||||
let zopfli_maximum_block_splits = self.zopfli_maximum_block_splits;
|
||||
let zstd_compression_level = self.zstd_compression_level;
|
||||
self.runner.execute(
|
||||
move |_| {
|
||||
@@ -260,7 +284,18 @@ impl<T: Write + Seek + Sync + Send + 'static> Archive for Xp3ArchiveWriter<T> {
|
||||
workers.execute(
|
||||
move |_| {
|
||||
let data = {
|
||||
if use_zstd {
|
||||
if use_zopfli {
|
||||
let option = zopfli::Options {
|
||||
iteration_count: zopfli_iteration_count,
|
||||
iterations_without_improvement:
|
||||
zopfli_iterations_without_improvement,
|
||||
maximum_block_splits:
|
||||
zopfli_maximum_block_splits,
|
||||
};
|
||||
let mut e = zopfli::ZlibEncoder::new(option, zopfli::BlockType::Dynamic, Vec::new())?;
|
||||
e.write_all(&seg)?;
|
||||
e.finish()?
|
||||
} else if use_zstd {
|
||||
let mut e = zstd::stream::Encoder::new(
|
||||
Vec::new(),
|
||||
zstd_compression_level,
|
||||
@@ -410,7 +445,19 @@ impl<T: Write + Seek + Sync + Send + 'static> Archive for Xp3ArchiveWriter<T> {
|
||||
let start = file.seek(std::io::SeekFrom::End(0))?;
|
||||
let size = {
|
||||
let mut writer = if is_compressed {
|
||||
if use_zstd {
|
||||
if use_zopfli {
|
||||
let e = zopfli::ZlibEncoder::new(
|
||||
zopfli::Options {
|
||||
iteration_count: zopfli_iteration_count,
|
||||
iterations_without_improvement:
|
||||
zopfli_iterations_without_improvement,
|
||||
maximum_block_splits: zopfli_maximum_block_splits,
|
||||
},
|
||||
zopfli::BlockType::Dynamic,
|
||||
&mut *file,
|
||||
)?;
|
||||
Box::new(e) as Box<dyn Write>
|
||||
} else if use_zstd {
|
||||
let e = zstd::stream::Encoder::new(
|
||||
&mut *file,
|
||||
zstd_compression_level,
|
||||
@@ -521,7 +568,17 @@ impl<T: Write + Seek + Sync + Send + 'static> Archive for Xp3ArchiveWriter<T> {
|
||||
}
|
||||
let index_data = index_data.into_inner();
|
||||
if self.compress_index {
|
||||
let compressed_index = if self.use_zstd {
|
||||
let compressed_index = if self.use_zopfli {
|
||||
let option = zopfli::Options {
|
||||
iteration_count: self.zopfli_iteration_count,
|
||||
iterations_without_improvement: self.zopfli_iterations_without_improvement,
|
||||
maximum_block_splits: self.zopfli_maximum_block_splits,
|
||||
};
|
||||
let mut e =
|
||||
zopfli::ZlibEncoder::new(option, zopfli::BlockType::Dynamic, Vec::new())?;
|
||||
e.write_all(&index_data)?;
|
||||
e.finish()?
|
||||
} else if self.use_zstd {
|
||||
let mut e = zstd::stream::Encoder::new(Vec::new(), self.zstd_compression_level)?;
|
||||
e.write_all(&index_data)?;
|
||||
e.finish()?
|
||||
|
||||
19
src/types.rs
19
src/types.rs
@@ -511,6 +511,9 @@ pub struct ExtraConfig {
|
||||
/// 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.
|
||||
@@ -538,6 +541,22 @@ pub struct ExtraConfig {
|
||||
#[cfg(feature = "escude")]
|
||||
/// Escude game title
|
||||
pub escude_op: Option<crate::scripts::escude::script::EscudeOp>,
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
||||
Reference in New Issue
Block a user