style(core): dedupe Hello::decode trailing-field offset math

The four trailing single-byte fields (video_caps, audio_channels, video_codecs,
preferred_codec) each recomputed the name/launch offset chain from scratch —
four copies of the same three-line walk, each a chance to diverge when the next
trailing field lands. Compute name_len/launch_off/tail once and index from
there; name/launch decode from the same bindings. Wire behaviour pinned by the
existing roundtrip + back-compat tests (all green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 14:55:51 +02:00
parent dd73ae2469
commit 204577c7ce
+32 -58
View File
@@ -841,6 +841,14 @@ impl Hello {
return Err(PunktfunkError::InvalidArg("bad Hello")); return Err(PunktfunkError::InvalidArg("bad Hello"));
} }
let u32at = |o: usize| u32::from_le_bytes([b[o], b[o + 1], b[o + 2], b[o + 3]]); let u32at = |o: usize| u32::from_le_bytes([b[o], b[o + 1], b[o + 2], b[o + 3]]);
// Locate the trailing single-byte fields once. name (26) and launch are `len u8 || UTF-8`
// blocks; their RAW length bytes (even when zero placeholders, or oversized garbage)
// determine where the tail starts, so a corrupt name never panics — it just pushes the
// later offsets out of range and those fields decode to their defaults.
let name_len = b.get(26).copied().unwrap_or(0) as usize;
let launch_off = 27 + name_len; // launch's length byte
let launch_len = b.get(launch_off).copied().unwrap_or(0) as usize;
let tail = launch_off + 1 + launch_len; // first trailing byte: video_caps
Ok(Hello { Ok(Hello {
abi_version: u32at(4), abi_version: u32at(4),
mode: Mode { mode: Mode {
@@ -864,64 +872,30 @@ impl Hello {
.unwrap_or(0), .unwrap_or(0),
// Optional trailing device name: len u8 || UTF-8. Absent / oversized / non-UTF-8 → // Optional trailing device name: len u8 || UTF-8. Absent / oversized / non-UTF-8 →
// `None` (never fail the handshake over a label). // `None` (never fail the handshake over a label).
name: b.get(26).and_then(|&len| { name: (name_len > 0 && name_len <= HELLO_NAME_MAX)
let len = len as usize; .then(|| {
if len == 0 || len > HELLO_NAME_MAX { b.get(27..27 + name_len)
return None; .and_then(|s| std::str::from_utf8(s).ok())
} .map(String::from)
b.get(27..27 + len) })
.and_then(|s| std::str::from_utf8(s).ok()) .flatten(),
.map(String::from) // Optional trailing launch id, right after name's block (same len/UTF-8 discipline).
}), launch: (launch_len > 0 && launch_len <= HELLO_LAUNCH_MAX)
// Optional trailing launch id, positioned right after name's `len u8 || UTF-8` block. .then(|| {
// The raw name-length byte (even when oversized/zero) determines where launch starts, b.get(launch_off + 1..launch_off + 1 + launch_len)
// so a corrupt name never panics — it just pushes the launch offset out of range → None. .and_then(|s| std::str::from_utf8(s).ok())
launch: b.get(26).and_then(|&name_len| { .map(String::from)
let off = 27 + name_len as usize; // start of launch's length byte })
let len = *b.get(off)? as usize; .flatten(),
if len == 0 || len > HELLO_LAUNCH_MAX { // The trailing single bytes, in wire order from `tail` (see the encode-side layout).
return None; // Each is absent on an older client and decodes to its documented default.
} video_caps: b.get(tail).copied().unwrap_or(0),
b.get(off + 1..off + 1 + len) // Normalized so a corrupt/unsupported channel count can't build a bad decoder.
.and_then(|s| std::str::from_utf8(s).ok()) audio_channels: crate::audio::normalize_channels(b.get(tail + 1).copied().unwrap_or(2)),
.map(String::from) // `0` = an older client (which `resolve_codec` treats as HEVC-only).
}), video_codecs: b.get(tail + 2).copied().unwrap_or(0),
// Optional trailing video-caps byte, positioned right after launch's `len u8 || bytes` // `0` = no preference; the host decides by precedence.
// block. Uses the raw (possibly zero/placeholder) name/launch length bytes to locate it, preferred_codec: b.get(tail + 3).copied().unwrap_or(0),
// so it's robust to absent name/launch; absent entirely on an older client → `0`.
video_caps: {
let name_len = b.get(26).copied().unwrap_or(0) as usize;
let launch_off = 27 + name_len; // launch's length byte
let launch_len = b.get(launch_off).copied().unwrap_or(0) as usize;
b.get(launch_off + 1 + launch_len).copied().unwrap_or(0)
},
// Optional trailing audio-channel byte, one past video_caps. Absent on an older client
// → stereo. Normalized so a corrupt/unsupported value can't build a bad decoder.
audio_channels: {
let name_len = b.get(26).copied().unwrap_or(0) as usize;
let launch_off = 27 + name_len;
let launch_len = b.get(launch_off).copied().unwrap_or(0) as usize;
let video_caps_off = launch_off + 1 + launch_len;
crate::audio::normalize_channels(b.get(video_caps_off + 1).copied().unwrap_or(2))
},
// Optional trailing video-codecs byte, one past audio_channels. Absent on an older client
// → `0` (which `resolve_codec` treats as HEVC-only).
video_codecs: {
let name_len = b.get(26).copied().unwrap_or(0) as usize;
let launch_off = 27 + name_len;
let launch_len = b.get(launch_off).copied().unwrap_or(0) as usize;
let video_caps_off = launch_off + 1 + launch_len;
b.get(video_caps_off + 2).copied().unwrap_or(0)
},
// Optional trailing preferred-codec byte, one past video_codecs. Absent on an older
// client → `0` (no preference; the host decides by precedence).
preferred_codec: {
let name_len = b.get(26).copied().unwrap_or(0) as usize;
let launch_off = 27 + name_len;
let launch_len = b.get(launch_off).copied().unwrap_or(0) as usize;
let video_caps_off = launch_off + 1 + launch_len;
b.get(video_caps_off + 3).copied().unwrap_or(0)
},
}) })
} }
} }