1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
//! CLI to print details about the 2 Byte zlib header, as defined in
//! [RFC 1950](https://datatracker.ietf.org/doc/html/rfc1950).
//! This was initially written to reverse-engineer more details about Blizzard's proprietary MPQ
//! archive format, which uses zlib streams to store data.
//! ```
//! Usage: zlib-header-cli [OPTIONS] [HEX4CHAR]
//!
//! Arguments:
//! [HEX4CHAR] A four-character hex string representing the ZlibHeader (Big Endian)
//!
//! Options:
//! -e, --explain Explain the ZlibHeader struct and abbreviations
//! -h, --help Print help
//! ```
//! ```
//! drfrugal@karazhan:~$ zlib-header-cli 789C
//! CM 8 (DEFLATE)
//! CINFO 7 (Window: 32768 Bytes)
//! FCHECK 28 (valid)
//! FDICT false (Preset Dictionary not used)
//! FLEVEL 2 (default)
//! ```
//! ```
//! drfrugal@karazhan:~$ zlib-header-cli --explain
//! 2 Byte zlib header according to https://datatracker.ietf.org/doc/html/rfc1950
//! 1st Byte - CMF (Compression Method and Flags)
//! 0000_1111 CM Compression Method 8, _ (DEFLATE, UNDEFINED)
//! 1111_0000 CINFO Compression Info window size is 2.pow(CINFO + 8)
//! 2nd Byte - FLG (Flags)
//! 0001_1111 FCHECK Checksum Adjustment valid if (CMF * 256 + FLG) % 31 == 0
//! 0010_0000 FDICT Preset Dictionary a preset dictionary was used
//! 1100_0000 FLEVEL Compression Level 0, 1, 2, 3 (fastest, fast, default, best)
//! ```
use clap::Parser;
use zlib_header::ZlibHeader;
#[derive(Debug, Parser)]
pub struct Cli {
/// Explain the ZlibHeader struct and abbreviations
#[arg(short, long)]
explain: bool,
/// A four-character hex string representing the ZlibHeader (Big Endian)
#[arg(required_unless_present = "explain")]
hex4char: Option<String>,
}
pub fn main() {
let args = Cli::parse();
if args.explain {
explain();
}
let header = match args.hex4char {
Some(hex) => match ZlibHeader::from_hex(&hex) {
Ok(header) => header,
Err(err) => {
eprintln!("{}", err);
return;
}
},
None => {
return;
}
};
if args.explain {
println!();
}
let cm = header.get_cm();
let algorithm = header.get_cm_str();
let cinfo = header.get_cinfo();
let window = header.get_window_size();
let fcheck = header.get_fcheck();
let valid = if header.is_valid() {
"valid"
} else {
"not valid"
};
let fdict = header.get_fdict();
let dict = if fdict { "used" } else { "not used" };
let flevel = header.get_flevel();
let level = header.get_flevel_str();
println!("CM {} ({})", cm, algorithm);
println!("CINFO {} (Window: {} Bytes)", cinfo, window);
println!("FCHECK {} ({})", fcheck, valid);
println!("FDICT {} (Preset Dictionary {})", fdict, dict);
println!("FLEVEL {} ({})", flevel, level);
}
/// Prints a few lines in order to explain the ZlibHeader struct.
pub fn explain() {
println!("2 Byte zlib header as defined in https://datatracker.ietf.org/doc/html/rfc1950");
println!("1st Byte - CMF (Compression Method and Flags)");
println!(" 0000_1111 CM Compression Method 8, _ (DEFLATE, UNDEFINED)");
println!(" 1111_0000 CINFO Compression Info window size is 2.pow(CINFO + 8)");
println!("2nd Byte - FLG (Flags)");
println!(" 0001_1111 FCHECK Checksum Adjustment valid if (CMF * 256 + FLG) % 31 == 0");
println!(" 0010_0000 FDICT Preset Dictionary a preset dictionary was used");
println!(" 1100_0000 FLEVEL Compression Level 0, 1, 2, 3 (fastest, fast, default, best)");
}
|