fix(cli): preserve unsigned fast-level parsing
The C command-line parser accepts short-form levels through an unsigned 32-bit conversion before storing them in the signed compression-level field. The Rust parser used signed parsing for both ordinary levels and --fast, rejecting 4294967295 even though it represents the valid fast level -1. Mirror the conversion and retain the fast-level clamp for the attached form. Test Plan: - cargo test --manifest-path rust/cli/Cargo.toml --all-features - cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - make -C programs zstd - ./programs/zstd --fast -4294967295 tests/playTests.sh -o /tmp/zstd-fast-test - ./programs/zstd --fast=4294967295 tests/playTests.sh -o /tmp/zstd-fast-test Refs: tests/playTests.sh maximum fast-level cases
This commit is contained in:
+24
-5
@@ -516,6 +516,14 @@ fn parse_i32(value: &str, name: &str) -> Result<i32, String> {
|
||||
.map_err(|_| format!("invalid {name}: {value:?}"))
|
||||
}
|
||||
|
||||
fn parse_compression_level(value: &str) -> Result<i32, String> {
|
||||
/* The C CLI reads short-form levels as U32 before storing them in its
|
||||
* signed level field. Preserve that conversion for values such as
|
||||
* 4294967295, which represents -1 on the supported two's-complement
|
||||
* targets and is a valid fast-compression level. */
|
||||
Ok(parse_u32(value, "compression level")? as i32)
|
||||
}
|
||||
|
||||
fn parse_worker_count(value: &str) -> Result<i32, String> {
|
||||
let workers = parse_i32(value, "thread count")?;
|
||||
if workers < 0 {
|
||||
@@ -803,14 +811,14 @@ fn parse_long_option(
|
||||
}
|
||||
"--fast" => {
|
||||
let mut level = match attached {
|
||||
Some(value) => parse_i32(value, "fast level")?,
|
||||
Some(value) => parse_u32(value, "fast level")?,
|
||||
None => 1,
|
||||
};
|
||||
if level <= 0 {
|
||||
if level == 0 {
|
||||
return Err("fast level must be positive".to_owned());
|
||||
}
|
||||
level = level.min(MAX_FAST_ACCELERATION);
|
||||
cli.level = -level;
|
||||
level = level.min(MAX_FAST_ACCELERATION as u32);
|
||||
cli.level = -(level as i32);
|
||||
Ok(None)
|
||||
}
|
||||
"--long" => {
|
||||
@@ -939,7 +947,7 @@ fn parse_short_options(
|
||||
while digits_end < bytes.len() && bytes[digits_end].is_ascii_digit() {
|
||||
digits_end += 1;
|
||||
}
|
||||
cli.level = parse_i32(&value[offset..digits_end], "compression level")?;
|
||||
cli.level = parse_compression_level(&value[offset..digits_end])?;
|
||||
offset = digits_end;
|
||||
continue;
|
||||
}
|
||||
@@ -1598,6 +1606,17 @@ mod tests {
|
||||
assert_eq!(cli.display_level, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fast_levels_preserve_the_unsigned_32_bit_conversion() {
|
||||
let cli = parse(&["zstd", "--fast", "-4294967295", "input"]);
|
||||
|
||||
assert_eq!(cli.level, -1);
|
||||
|
||||
let cli = parse(&["zstd", "--fast=4294967295", "input"]);
|
||||
|
||||
assert_eq!(cli.level, -MAX_FAST_ACCELERATION);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_option_equals_form_is_accepted() {
|
||||
let cli = parse(&["zstd", "-T=2", "-M=64M", "-B=1M", "input"]);
|
||||
|
||||
Reference in New Issue
Block a user