szs
szs is a WIP crate for compressing and decompressing SZS files (Yaz0 encoding) used in the Nintendo GameCube and Wii games. The library provides C bindings, making it useful in both Rust and C/C++ based projects.
Warning: These algorithms are currently implemented in the C programming language, and not in Rust. While they have been rigorously validated, please use at your own risk. A Rust rewrite is planned.
Stats
Task: Compress N64 Bowser Castle (Source filesize: 2,574,368)
| Method | Time Taken | Compression Rate |
|---|---|---|
| lib-yaz0 | 2.03s | 56.65% |
| nintendo | 5.93s | 56.87% |
| mkw-sp | 3.76s | 57.23% |
| Haroohie | 0.58s | 57.23% |
| CTLib | 0.32s | 57.24% |
| MK8 | 0.09s | 57.59% |
| ctgp | 0.31s | 71.41% |
| worst-case-encoding | 0s | 112.50% |
| Comparison with other libraries: | ||
| Haroohie (C#) | 0.71s | 57.23% |
| wszst (fast) | 0.387s (via shell) | 65.78% |
| wszst (standard) | 1.776s (via shell) | 57.23% |
| wszst (ultra) | 2.727s (via shell) | 56.65% |
| yaz0-rs | 11.34s (via shell) | 56.87% |
* Average of 3 runs; x64 Clang (15, 16) build tested on an Intel i7-9750H on Windows 11
Generally, the mk8 algorithm gets acceptable compression the fastest. For cases where filesize matters, lib-yaz0 ties wszst ultra for the smallest filesizes, while being ~25% faster.
| Algorithm (rszst compress --algorithm form) | Rust form | C bindings | Desc |
|-----------------------------------------------|------|----|
| nintendo | EncodeAlgo::Nintendo | RII_SZS_ENCODE_ALGO_NINTENDO | Boyer-moore-horspool (Reverse engineered. 1:1 matching source files--relevant for decompilation projects)
| mk8 | EncodeAlgo::Mk8 | RII_SZS_ENCODE_ALGO_MK8 | MK8 compressor (Reverse engineered. Credit @aboood40091)
| mkw-sp | EncodeAlgo::MkwSp | RII_SZS_ENCODE_ALGO_MKWSP | MKW-SP
| ctgp | EncodeAlgo::CTGP | RII_SZS_ENCODE_ALGO_CTGP | CTGP (Reverse engineered. 1:1 matching)
| worst-case-encoding | EncodeAlgo::WorstCaseEncoding | RII_SZS_ENCODE_ALGO_WORST_CASE_ENCODING | Worst case
| haroohie | EncodeAlgo::Haroohie | RII_SZS_ENCODE_ALGO_HAROOHIE| Haroohie (credit @Gericom, adapted from MarioKartToolbox)
| ct-lib | EncodeAlgo::CTLib | RII_SZS_ENCODE_ALGO_CTLIB | CTLib (credit @narahiero, adapted from CTLib)
| lib-yaz0 | EncodeAlgo::LibYaz0 | RII_SZS_ENCODE_ALGO_LIBYAZ0 | libyaz0 (Based on wszst. credit @aboood40091)
Large file comparison
NSMBU 8-43 (63.9 MB decompressed)
| Method | Time (Avg 3 runs) | Compression Rate | File Size |
|---|---|---|---|
| lib-yaz0 | 25.97s | 29.32% | 18.74 MB |
| mkw | 78.26s | 29.40% | 18.79 MB |
| mkw-sp | 49.28s | 29.74% | 19.01 MB |
| haroohie | 11.44s | 29.74% | 19.01 MB |
| ct-lib | 5.32s | 29.74% | 19.01 MB |
| mk8 | 1.46s | 30.12% | 19.25 MB |
| ctgp | 12.05s | 40.91% | 26.14 MB |
| worst-case-encoding | 0.07s | 112.50% | 71.90 MB |
Rust
The following snippet demonstrates how to compress a file as a SZS format using Rust:
// Sample source bytes to be encoded.
let src_data: = "Hello, World!".as_bytes.to_vec;
// Calculate the upper bound for encoding.
let max_len = encoded_upper_bound;
// Allocate a buffer based on the calculated upper bound.
let mut dst_data: = vec!;
match encode_algo_fast
Example (C Bindings)
// Calculate the upper bound for encoding.
u32 max_size = ;
// Allocate a buffer based on the calculated upper bound.
void* encoded_buf = ;
if
// Boyer-Moore-horspool variant
u32 algorithm = RII_SZS_ENCODE_ALGO_NINTENDO;
u32 actual_len = 0;
const char* ec = ;
if
;
// Optionally: shrink the dst_data to the actual size.
encoded_buf = ;
C++ Wrapper on top of C Bindings
// Boyer-Moore-horspool variant
szs::Algo algorithm = szs::Algo::Nintendo;
auto encoded = ;
if
;
std::vector<u8> szs_data = *encoded;
;
C# Bindings
The following C# bindings are provided:
using ;
public
License
This library is published under the MIT license.