ithmb_core/decoder_helpers.rs
1//! Shared helper functions for decoders.
2//!
3//! This module provides common validation logic extracted from individual decoder
4//! files to eliminate repetitive boilerplate (positive-dimension checks, sign-loss
5//! casts, and buffer-too-short guards).
6
7use crate::error::DecodeError;
8use crate::profile::Profile;
9
10/// Validates that profile dimensions are positive and converts them to `usize`.
11///
12/// When `bpp > 0` the function also checks that `src` is at least
13/// `width × height × bpp` bytes long.
14///
15/// # Arguments
16///
17/// * `src` — Raw input byte slice.
18/// * `profile` — The profile whose `width` and `height` are validated.
19/// * `name` — Label used in the [`DecodeError::InvalidFormat`] message.
20/// * `bpp` — Bytes per pixel. Pass `0` to skip the buffer-length check for
21/// formats that need a more complex expected-size calculation (e.g., `YCbCr420`).
22///
23/// # Returns
24///
25/// `(width, height)` as `usize`.
26///
27/// # Errors
28///
29/// | Variant | Condition |
30/// |---|---|
31/// | `InvalidFormat` | Width or height ≤ 0 |
32/// | `BufferTooShort` | `bpp > 0` and `src.len() < w × h × bpp` |
33#[allow(clippy::cast_sign_loss)]
34pub(crate) fn validate_dimensions(
35 src: &[u8],
36 profile: &Profile,
37 name: &str,
38 bpp: usize,
39) -> Result<(usize, usize), DecodeError> {
40 let w_i32 = profile.width;
41 let h_i32 = profile.height;
42
43 if w_i32 <= 0 || h_i32 <= 0 {
44 return Err(DecodeError::InvalidFormat(name.into()));
45 }
46
47 let w = w_i32 as usize;
48 let h = h_i32 as usize;
49
50 if bpp > 0 {
51 let expected = w * h * bpp;
52 if src.len() < expected {
53 return Err(DecodeError::BufferTooShort {
54 expected,
55 actual: src.len(),
56 });
57 }
58 }
59
60 Ok((w, h))
61}