Skip to content

Commit 90538b7

Browse files
committed
Add a command-line tool to calculate CRC params
1 parent 97d8d51 commit 90538b7

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed

src/bin/get-custom-params.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
//! This is a simple program to get custom CRC parameters from the command line.
2+
3+
use std::env;
4+
use std::process::ExitCode;
5+
6+
#[derive(Debug)]
7+
struct Config {
8+
width: Option<u32>,
9+
polynomial: Option<u64>,
10+
init: Option<u64>,
11+
reflected: Option<bool>,
12+
xorout: Option<u64>,
13+
check: Option<u64>,
14+
name: Option<String>,
15+
}
16+
17+
impl Config {
18+
fn new() -> Self {
19+
Config {
20+
width: None,
21+
polynomial: None,
22+
init: None,
23+
reflected: None,
24+
xorout: None,
25+
check: None,
26+
name: None,
27+
}
28+
}
29+
30+
fn is_complete(&self) -> bool {
31+
self.width.is_some()
32+
&& self.polynomial.is_some()
33+
&& self.init.is_some()
34+
&& self.reflected.is_some()
35+
&& self.xorout.is_some()
36+
&& self.check.is_some()
37+
&& self.name.is_some()
38+
}
39+
}
40+
41+
fn parse_hex_or_decimal(s: &str) -> Result<u64, String> {
42+
if s.starts_with("0x") || s.starts_with("0X") {
43+
u64::from_str_radix(&s[2..], 16).map_err(|_| format!("Invalid hexadecimal value: {}", s))
44+
} else {
45+
s.parse::<u64>()
46+
.map_err(|_| format!("Invalid decimal value: {}", s))
47+
}
48+
}
49+
50+
fn parse_bool(s: &str) -> Result<bool, String> {
51+
match s.to_lowercase().as_str() {
52+
"true" | "1" | "yes" | "on" => Ok(true),
53+
"false" | "0" | "no" | "off" => Ok(false),
54+
_ => Err(format!("Invalid boolean value: {} (use true/false)", s)),
55+
}
56+
}
57+
58+
fn parse_args(args: &[String]) -> Result<Config, String> {
59+
let mut config = Config::new();
60+
let mut i = 1; // Skip program name
61+
62+
while i < args.len() {
63+
match args[i].as_str() {
64+
"-n" => {
65+
if i + 1 >= args.len() {
66+
return Err("Missing value for -n (name)".to_string());
67+
}
68+
config.name = Some(args[i + 1].clone());
69+
i += 2;
70+
}
71+
"-w" => {
72+
if i + 1 >= args.len() {
73+
return Err("Missing value for -w (width)".to_string());
74+
}
75+
config.width = Some(
76+
args[i + 1]
77+
.parse::<u32>()
78+
.map_err(|_| format!("Invalid width value: {}", args[i + 1]))?,
79+
);
80+
i += 2;
81+
}
82+
"-p" => {
83+
if i + 1 >= args.len() {
84+
return Err("Missing value for -p (polynomial)".to_string());
85+
}
86+
config.polynomial = Some(parse_hex_or_decimal(&args[i + 1])?);
87+
i += 2;
88+
}
89+
"-i" => {
90+
if i + 1 >= args.len() {
91+
return Err("Missing value for -i (init)".to_string());
92+
}
93+
config.init = Some(parse_hex_or_decimal(&args[i + 1])?);
94+
i += 2;
95+
}
96+
"-r" => {
97+
if i + 1 >= args.len() {
98+
return Err("Missing value for -r (reflected)".to_string());
99+
}
100+
config.reflected = Some(parse_bool(&args[i + 1])?);
101+
i += 2;
102+
}
103+
"-x" => {
104+
if i + 1 >= args.len() {
105+
return Err("Missing value for -x (xorout)".to_string());
106+
}
107+
config.xorout = Some(parse_hex_or_decimal(&args[i + 1])?);
108+
i += 2;
109+
}
110+
"-c" => {
111+
if i + 1 >= args.len() {
112+
return Err("Missing value for -c (check)".to_string());
113+
}
114+
config.check = Some(parse_hex_or_decimal(&args[i + 1])?);
115+
i += 2;
116+
}
117+
arg => {
118+
return Err(format!("Unknown argument: {}", arg));
119+
}
120+
}
121+
}
122+
123+
Ok(config)
124+
}
125+
126+
fn print_usage() {
127+
println!("Usage: get-custom-params -n <name> -w <width> -p <polynomial> -i <init> -r <reflected> -x <xorout> -c <check>");
128+
println!();
129+
println!("Example: get-custom-params -n CRC-32/ISCSI -w 32 -p 0x1edc6f41 -i 0xFFFFFFFF -r true -x 0xFFFFFFFF -c 0xe3069283");
130+
println!("Example: get-custom-params -n CRC-64/NVME -w 64 -p 0xad93d23594c93659 -i 0xffffffffffffffff -r true -x 0xffffffffffffffff -c 0xae8b14860a799888");
131+
println!();
132+
println!("Arguments:");
133+
println!(" -n <name> Name of the CRC algorithm (e.g., CRC-32/ISCSI)");
134+
println!(" -w <width> CRC width (number of bits)");
135+
println!(" -p <polynomial> CRC polynomial (hex or decimal)");
136+
println!(" -i <init> Initial value (hex or decimal)");
137+
println!(" -r <reflected> Reflected input/output (true/false)");
138+
println!(" -x <xorout> XOR output value (hex or decimal)");
139+
println!(" -c <check> Check value (hex or decimal)");
140+
}
141+
142+
fn main() -> ExitCode {
143+
let args: Vec<String> = env::args().collect();
144+
145+
if args.len() == 1 {
146+
print_usage();
147+
return ExitCode::from(1);
148+
}
149+
150+
let config = match parse_args(&args) {
151+
Ok(config) => config,
152+
Err(error) => {
153+
eprintln!("Error: {}", error);
154+
println!();
155+
print_usage();
156+
return ExitCode::from(1);
157+
}
158+
};
159+
160+
// Check if all required arguments are provided
161+
if !config.is_complete() {
162+
eprintln!("Error: All arguments are required");
163+
println!();
164+
print_usage();
165+
return ExitCode::from(1);
166+
}
167+
168+
let static_name: &'static str = Box::leak(config.name.unwrap().into_boxed_str());
169+
170+
let params = crc_fast::get_custom_params(
171+
static_name,
172+
config.width.unwrap() as u8,
173+
config.polynomial.unwrap(),
174+
config.init.unwrap(),
175+
config.reflected.unwrap(),
176+
config.xorout.unwrap(),
177+
config.check.unwrap(),
178+
);
179+
180+
println!();
181+
println!("{:#x?}", params);
182+
println!();
183+
184+
ExitCode::from(0)
185+
}

0 commit comments

Comments
 (0)