#game-cube #wii #yaz0 #file-format #yay0

szs

轻量级的用于 Nintendo GameCube/Wii 游戏中 SZS ("Yaz0") 压缩/解压缩的 crate。该库提供了 C、C++ 和 C# 绑定。也支持 YAY0 ("SZP")。

22 个不稳定版本 (3 个重大变更)

1.1.0 2023 年 10 月 17 日
0.3.7 2024 年 7 月 20 日
0.3.4 2023 年 11 月 16 日

#13 in 游戏

Download history 1/week @ 2024-05-29 130/week @ 2024-06-05 16/week @ 2024-06-12 6/week @ 2024-07-03 109/week @ 2024-07-17 41/week @ 2024-07-24 16/week @ 2024-07-31

每月下载量 166

MIT 许可证

465KB
2.5K SLoC

Rust 1.5K SLoC // 0.0% comments C++ 784 SLoC // 0.0% comments Python 145 SLoC // 0.1% comments C# 133 SLoC // 0.1% comments Visual Studio Solution 31 SLoC

包含 (Windows DLL, 170KB) py/szs.dll, (Windows DLL, 170KB) c#/bindings/szs.dll

crates.io docs.rs

szs

用于 Nintendo GameCube/Wii 游戏中 SZS ("Yaz0") 压缩/解压缩的轻量级 crate。该库提供了 CC++C#Python(工作进展中) 绑定。也支持 YAY0 ("SZP")。

Rust

以下代码示例展示了如何使用 Rust 将文件压缩为 SZS 格式

let src_data: Vec<u8> = "Hello, World!".as_bytes().to_vec();

match szs::encode(&src_data, szs::EncodeAlgo::Nintendo) {
    Ok(encoded_data) => {
        println!("Encoded into {} bytes", encoded_data.len());
    }
    Err(err) => {
        println!("Encoding failed: {}", err);
    }
}

同样,解压缩

match szs::decode(&encoded_data) {
    Ok(decoded_data) => {
        println!("Decoded {} bytes", decoded_data.len());
    }
    Err(err) => {
        println!("Decoding failed: {}", err);
    }
}

C# 绑定

以下 C# 绑定提供如下

public static void Main(string[] args)
{
    byte[] data = ...;
    szs.CompressionAlgorithm algorithm = szs.CompressionAlgorithm.Nintendo;
    try
    {
        byte[] encodedData = szs.Encode(data, algorithm);
        Console.WriteLine($"Encoded {encodedData.Length} bytes.");
    }
    catch (Exception e)
    {
        Console.WriteLine("Failed to compress: " + e.Message);
    }
}
警告:szs 部分是用 C 实现的,这带来了自己的安全考虑。

算法

算法 用例 描述
EncodeAlgo::Nintendo 匹配解压缩项目 这是从 Mario Kart Wii 中反向工程得到的压缩算法。在实践中,它是一个带有第二意见机制的 Boyer-moore-horspool 搜索。
EncodeAlgo::Mk8 通用 FAST 预设。 这是从 Mario Kart 8 中反向工程得到的压缩算法。在实践中,它是一个滑动蒙特卡洛哈希表。(感谢 @aboood40091、@KillZGaming)
EncodeAlgo::MkwSp MKW-SP
EncodeAlgo::CTGP CTGP 工作 CTGP(反向工程。1:1 匹配)
EncodeAlgo::最坏情况编码 INSTANT 预设。 最坏情况
EncodeAlgo::Haroohie Haroohie(感谢 @Gericom,改编自 MarioKartToolbox)
EncodeAlgo::CTLib CTLib(感谢 @narahiero,改编自 CTLib)
EncodeAlgo::LibYaz0 ULTRA 预设。 libyaz0(基于 wszst。感谢 @aboood40091)

通常情况下,mk8 算法以最快的速度获得可接受的压缩效果。对于文件大小至关重要的场景,lib-yaz0wszst ultra 在最小的文件大小上并列,但速度约快 25%。

与其他库的比较

  1. yaz0-rs

    • 性能:EncodeAlgo::LibYaz0 提供了更优的压缩效果,并且在参考数据上的速度比 yaz0-rs 快约 6 倍。
    • 注意:szs 部分实现为 C 语言,这带来了自己的安全考虑。
  2. oead

    • 性能:EncodeAlgo::MK8oead 的压缩和速度相匹配。
    • 大小:szs 是一个轻量级的几KB MIT 许可证的依赖项,而 oead 是一个更大的多MB GPL 许可证的包。
  3. Wiimm 的 SZS 工具

    • 性能
      • EncodeAlgo::LibYaz0 提供与 wszst ultra 相等的压缩效果,但速度约快 30%,且不受 GPL 许可证的限制。
      • EncodeAlgo::MK8 在压缩方面优于 wszst fast,并且速度快 4-5 倍。

特殊功能:在列出的库中,只有 szs 提供了对 YAZ0YAZ1YAY0 流格式的全面支持。

基准测试

大文件比较

NSMBU 8-43(解压后 63.9 MB)

方法 时间(平均 3 次运行) 压缩率 文件大小
最坏情况编码 0.03 秒 112.50% 71.90 MB
mk8 1.37 秒 29.43% 18.81 MB
ct-lib 3.01 秒 29.74% 19.01 MB
haroohie 5.79 秒 29.74% 19.01 MB
ctgp 9.23 秒 40.91% 26.14 MB
lib-yaz0 16.09 秒 29.32% 18.74 MB
mkw-sp 36.77 秒 29.74% 19.01 MB
mkw 55.00 秒 29.40% 18.79 MB
mkw (C++) 63.34 秒 29.40% 18.79 MB
与其他库的比较
oead 默认 0.61 秒 30.09% 19.23 MB
oead 最大级别 0.99 秒 29.96% 19.15 MB
wszst 快速 1.77 秒 35.62% 22.76 MB
wszst 标准 11.95 秒 29.74% 19.01 MB
wszst 超级 25.06 秒 29.32% 18.74 MB

* 平均 3 次运行;在 Windows 11 上的 x64 Clang (17.0.6) 构建进行了测试,测试在 Intel i9-13900KF 上进行

小文件比较

任务:压缩 N64 Bowser Castle(源文件大小:2,574,368)

方法 时间(平均 3 次运行) 压缩率 文件大小
最坏情况编码 0.00 秒 112.50% 2.76 MB
mk8 0.07 秒 56.75% 1.39 MB
ct-lib 0.19 秒 57.24% 1.41 MB
ctgp 0.21 秒 71.41% 1.75 MB
haroohie 0.31 秒 57.23% 1.41 MB
lib-yaz0 1.09 秒 56.65% 1.39 MB
mkw-sp 1.47 秒 57.23% 1.41 MB
mkw 3.91 秒 56.87% 1.40 MB
mkw (C++) 4.27 秒 56.87% 1.40 MB
与其他库的比较
oead 默认 0.03 秒 57.63% 1.41 MB
oead 最大级别 0.05 秒 57.52% 1.41 MB
wszst(快速) 0.197 秒(通过 shell) 65.78% 1.61 MB
wszst(标准) 0.946 秒(通过 shell) 57.23% 1.40 MB
wszst(超级) 1.418 秒(通过 shell) 56.65% 1.38 MB
yaz0-rs 4.88 秒(通过 shell) 56.87% 1.39 MB

* 平均 3 次运行;在 Windows 11 上的 x64 Clang (17.0.6) 构建进行了测试,测试在 Intel i9-13900KF 上进行

通常情况下,mk8 算法以最快的速度获得可接受的压缩效果。对于文件大小至关重要的场景,lib-yaz0wszst ultra 在最小的文件大小上并列,但速度约快 25%。

(Windows)性能比较:Clang 与 MSVC

在 Windows 上,微软的编译器(MSVC)在大多数算法上似乎落后于 Clang,差距相当明显

方法 Clang 时间(秒) MSVC 时间(秒) 性能提升(%)
lib-yaz0 15.24 19.08 -25.20%
mkw 62.04 58.34 5.96%
mkw-sp 26.73 50.01 -87.09%
haroohie 5.84 5.85 -0.17%
ct-lib 2.91 2.81 3.44%
mk8 1.34 1.62 -20.90%
ctgp 5.22 5.88 -12.64%

* 平均 3 次运行;在 Windows 11 上的 x64 MSVC 构建进行了测试,测试在 Intel i9-13900KF 上进行

平均性能提升 -19.51%

建议

根据性能结果,Clang通常更受欢迎。要将Clang设置为szs的编译器,在运行cargo build之前,执行以下命令:

SET CXX=clang

此外,使用兼容的Clang/Rust版本将允许进行跨语言LTO优化。

示例(C绑定)

#include "szs.h"

// Calculate the upper bound for encoding.
u32 max_size = riiszs_encoded_upper_bound(sizeof(data));

// Allocate a buffer based on the calculated upper bound.
void* encoded_buf = malloc(max_size);
if (!buf) {
	fprintf(stderr, "Failed to allocate %u bytes.\n", max_size);
	return -1;
}

// Boyer-Moore-horspool variant
u32 algorithm = RII_SZS_ENCODE_ALGO_NINTENDO;

u32 actual_len = 0;
const char* ec = riiszs_encode_algo_fast(encoded_buf, max_size, data, sizeof(data), &actual_len, algorithm);
if (ec != NULL) {
	fprintf(stderr, "Failed to compress: %s\n", ec);
	riiszs_free_error_message(ec);
	return -1;
}
printf("Encoded %u bytes.\n", actual_len);
// Optionally: shrink the dst_data to the actual size.
encoded_buf = realloc(encoded_buf, actual_len);

C++在C绑定之上封装

还提供了一个CMake示例。

#include `szs.h`

// Boyer-Moore-horspool variant
szs::Algo algorithm = szs::Algo::Nintendo;
auto encoded = szs::encode(data, algorithm);
if (!encoded)
	std::println(stderr, "Failed to compress: {}.", encoded.error()); {
	return -1;
}
std::vector<u8> szs_data = *encoded;
std::println("Encoded {} bytes.", szs_data.size());

许可证

此库根据MIT许可证发布。

依赖项