Skip to main content

dvb_ci/
length.rs

1//! The EN 50221 `length_field` — the ASN.1-style length used by every PDU at
2//! the Transport, Session and Application layers — ETSI EN 50221 §7, Table 1
3//! (PDF p. 11).
4//!
5//! Coding:
6//! - the first (MSB) bit is the `size_indicator`;
7//! - `size_indicator == 0`: the data-field length is the remaining 7 bits — any
8//!   length `0..=127` fits in one byte;
9//! - `size_indicator == 1`: the remaining 7 bits (`length_field_size`) code how
10//!   many subsequent bytes carry the length, MSB-first. The spec caps any length
11//!   at 65535, i.e. at most three length bytes.
12//!
13//! The indefinite-length ASN.1 form is NOT used.
14
15use crate::error::{Error, Result};
16
17/// The `size_indicator` bit (the MSB of the first `length_field` byte): set when
18/// the field is the multi-byte form.
19pub const SIZE_INDICATOR_MASK: u8 = 0x80;
20
21/// Widest long form accepted on the wire: `length_field_size` of 4 (one
22/// size-indicator byte + four length octets). Anything wider is not a length
23/// this codec can carry (values are capped at [`MAX_LENGTH`]).
24pub const MAX_LENGTH_OCTETS: u8 = 4;
25
26/// The largest value a `length_field` may carry (EN 50221 Table 1: "any length
27/// up to 65535").
28pub const MAX_LENGTH: usize = 0xFFFF;
29
30/// How a `length_field` is — or is to be — coded on the wire.
31///
32/// A CAM may code a length in a longer form than necessary (`82 00 09` for the
33/// value 9, captured raw on hardware, dvb-ci-runtime #337). `parse` is tolerant
34/// and records the coding here; `serialize` re-emits exactly that coding, so a
35/// parsed APDU/SPDU/TPDU round-trips byte-for-byte. A value built by hand uses
36/// [`LengthForm::Minimal`] (the [`Default`]): the shortest legal form.
37///
38/// `parse` only ever produces [`LengthForm::Long`] for a *non-minimal* coding,
39/// so a parsed object equals the same object built with the default form
40/// whenever the wire used the minimal coding.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize))]
43#[non_exhaustive]
44pub enum LengthForm {
45    /// The shortest legal coding for the value: the 1-byte short form for
46    /// `0..=127`, otherwise the long form with the fewest length octets.
47    #[default]
48    Minimal,
49    /// A non-minimal long form (`size_indicator = 1`) with exactly `octets`
50    /// length octets (`1..=`[`MAX_LENGTH_OCTETS`]), e.g. `82 00 09`.
51    Long {
52        /// `length_field_size`: the number of length octets that follow the
53        /// size-indicator byte.
54        octets: u8,
55    },
56}
57
58impl LengthForm {
59    /// `true` for [`LengthForm::Minimal`] (used to skip the field in serde).
60    #[must_use]
61    pub const fn is_minimal(&self) -> bool {
62        matches!(self, Self::Minimal)
63    }
64
65    /// Short label (issue #204 convention).
66    #[must_use]
67    pub fn name(&self) -> &'static str {
68        match self {
69            Self::Minimal => "minimal",
70            Self::Long { .. } => "long",
71        }
72    }
73}
74broadcast_common::impl_spec_display!(LengthForm);
75
76/// Decode a `length_field` from the front of `bytes`.
77///
78/// Returns `(length_value, header_len)` where `header_len` is the number of
79/// bytes the `length_field` itself occupied (so the body starts at
80/// `bytes[header_len..]`). Use [`decode_form`] to also learn how it was coded.
81pub fn decode(bytes: &[u8]) -> Result<(usize, usize)> {
82    let (value, hdr, _) = decode_form(bytes)?;
83    Ok((value, hdr))
84}
85
86/// Like [`decode`], also returning the [`LengthForm`] the field was coded in
87/// (so a serializer can reproduce it).
88///
89/// Accepts the short form and any long form of 1 to [`MAX_LENGTH_OCTETS`]
90/// length octets whose value is at most [`MAX_LENGTH`], including non-minimal
91/// ones (real CAMs send them). Rejects the indefinite form (`0x80`), a
92/// `length_field_size` above [`MAX_LENGTH_OCTETS`], a value above
93/// [`MAX_LENGTH`], and a truncated field.
94pub fn decode_form(bytes: &[u8]) -> Result<(usize, usize, LengthForm)> {
95    let first = *bytes
96        .first()
97        .ok_or(Error::InvalidLength("empty length_field"))?;
98    if first & SIZE_INDICATOR_MASK == 0 {
99        // Short form: 7-bit length in this byte.
100        return Ok(((first & 0x7F) as usize, 1, LengthForm::Minimal));
101    }
102    // Long form: low 7 bits = number of subsequent length bytes.
103    let n = (first & 0x7F) as usize;
104    if n == 0 {
105        // size_indicator==1 with zero following bytes is the indefinite form,
106        // which the spec forbids.
107        return Err(Error::InvalidLength("indefinite length form not allowed"));
108    }
109    if n > MAX_LENGTH_OCTETS as usize {
110        return Err(Error::InvalidLength(
111            "length_field_size exceeds 4 length octets",
112        ));
113    }
114    if bytes.len() < 1 + n {
115        return Err(Error::BufferTooShort {
116            need: 1 + n,
117            have: bytes.len(),
118            what: "length_field (long form)",
119        });
120    }
121    let mut value = 0usize;
122    for &b in &bytes[1..1 + n] {
123        value = (value << 8) | b as usize;
124    }
125    if value > MAX_LENGTH {
126        return Err(Error::LengthTooLarge(value));
127    }
128    // Record the coding only when it is NOT the minimal one, so a parsed object
129    // compares equal to one built with the default form whenever the wire used
130    // the shortest legal coding.
131    let form = if n == minimal_octets(value) && value >= 0x80 {
132        LengthForm::Minimal
133    } else {
134        LengthForm::Long { octets: n as u8 }
135    };
136    Ok((value, 1 + n, form))
137}
138
139/// Length octets of the minimal long form of `value` (`value >= 0x80`).
140const fn minimal_octets(value: usize) -> usize {
141    if value <= 0xFF { 1 } else { 2 }
142}
143
144/// Number of bytes [`encode_into`] will write for `value`.
145#[must_use]
146pub fn encoded_len(value: usize) -> usize {
147    if value < 0x80 {
148        1
149    } else if value <= 0xFF {
150        2
151    } else if value <= 0xFFFF {
152        3
153    } else {
154        // >65535: caller is expected to reject via encode_into; report the
155        // widest legal form so serialized_len stays an upper bound.
156        4
157    }
158}
159
160/// Number of bytes a `length_field` for `value` occupies when coded in `form`.
161///
162/// A [`LengthForm::Long`] whose octets cannot hold `value` (or exceed
163/// [`MAX_LENGTH_OCTETS`]) is an error at encode time; here it reports the
164/// requested size so `serialized_len` stays consistent with what a successful
165/// serialize writes.
166#[must_use]
167pub fn encoded_len_with(value: usize, form: LengthForm) -> usize {
168    match form {
169        LengthForm::Minimal => encoded_len(value),
170        LengthForm::Long { octets } => 1 + octets as usize,
171    }
172}
173
174/// Encode `value` as a `length_field` coded in `form`, returning the bytes
175/// written. [`LengthForm::Minimal`] is exactly [`encode_into`]; a
176/// [`LengthForm::Long`] writes the size-indicator byte and `octets` big-endian
177/// length octets (so a parsed non-minimal field is reproduced byte-for-byte).
178///
179/// Errors with [`Error::LengthTooLarge`] when `value > `[`MAX_LENGTH`] and with
180/// [`Error::InvalidLength`] when `octets` is `0`, above [`MAX_LENGTH_OCTETS`],
181/// too few to hold `value`, or exactly the minimal count for `value >= 0x80`
182/// (that coding is [`LengthForm::Minimal`]; accepting it would make a
183/// hand-built value serialize to bytes that parse back as a different value).
184pub fn encode_with(value: usize, form: LengthForm, buf: &mut [u8]) -> Result<usize> {
185    let LengthForm::Long { octets } = form else {
186        return encode_into(value, buf);
187    };
188    if value > MAX_LENGTH {
189        return Err(Error::LengthTooLarge(value));
190    }
191    if octets == 0 || octets > MAX_LENGTH_OCTETS {
192        return Err(Error::InvalidLength("length_field_size must be 1..=4"));
193    }
194    let n = octets as usize;
195    if n < 4 && value >> (8 * n) != 0 {
196        return Err(Error::InvalidLength(
197            "length value does not fit the recorded length_field_size",
198        ));
199    }
200    // `Long` records only a NON-minimal coding (that is what `decode_form`
201    // returns). A `Long` whose octets are the minimal ones for `value`
202    // (`81 80` for 128, `82 01 00` for 256) is the same bytes as `Minimal`, so
203    // it would parse back as `Minimal` and `serialize -> parse` would change
204    // the value; refuse the alias instead of writing it.
205    if value >= 0x80 && n == minimal_octets(value) {
206        return Err(Error::InvalidLength(
207            "Long form with the minimal number of octets is LengthForm::Minimal",
208        ));
209    }
210    let need = 1 + n;
211    if buf.len() < need {
212        return Err(Error::OutputBufferTooSmall {
213            need,
214            have: buf.len(),
215        });
216    }
217    buf[0] = SIZE_INDICATOR_MASK | octets;
218    for (i, slot) in buf[1..need].iter_mut().enumerate() {
219        let shift = 8 * (n - 1 - i);
220        *slot = (value >> shift) as u8;
221    }
222    Ok(need)
223}
224
225/// Encode `value` as a `length_field` into `buf`, returning the bytes written.
226///
227/// Uses the short form for `0..=127`, otherwise the minimal long form. Values
228/// above 65535 are rejected ([`Error::LengthTooLarge`]) per the spec cap.
229pub fn encode_into(value: usize, buf: &mut [u8]) -> Result<usize> {
230    let need = encoded_len(value);
231    if value > 0xFFFF {
232        return Err(Error::LengthTooLarge(value));
233    }
234    if buf.len() < need {
235        return Err(Error::OutputBufferTooSmall {
236            need,
237            have: buf.len(),
238        });
239    }
240    if value < 0x80 {
241        buf[0] = value as u8;
242    } else if value <= 0xFF {
243        buf[0] = SIZE_INDICATOR_MASK | 1;
244        buf[1] = value as u8;
245    } else {
246        buf[0] = SIZE_INDICATOR_MASK | 2;
247        buf[1] = (value >> 8) as u8;
248        buf[2] = value as u8;
249    }
250    Ok(need)
251}
252
253#[cfg(test)]
254mod tests {
255    use super::*;
256
257    #[test]
258    fn short_form_round_trip() {
259        for v in [0usize, 1, 0x7F] {
260            let mut buf = [0u8; 4];
261            let n = encode_into(v, &mut buf).unwrap();
262            assert_eq!(n, 1);
263            assert_eq!(encoded_len(v), 1);
264            let (decoded, hdr) = decode(&buf).unwrap();
265            assert_eq!((decoded, hdr), (v, 1));
266        }
267    }
268
269    #[test]
270    fn two_byte_form_round_trip() {
271        for v in [0x80usize, 0xFF] {
272            let mut buf = [0u8; 4];
273            let n = encode_into(v, &mut buf).unwrap();
274            assert_eq!(n, 2);
275            assert_eq!(buf[0], SIZE_INDICATOR_MASK | 1);
276            let (decoded, hdr) = decode(&buf).unwrap();
277            assert_eq!((decoded, hdr), (v, 2));
278        }
279    }
280
281    #[test]
282    fn three_byte_form_round_trip() {
283        for v in [0x100usize, 0x1234, 0xFFFF] {
284            let mut buf = [0u8; 4];
285            let n = encode_into(v, &mut buf).unwrap();
286            assert_eq!(n, 3);
287            assert_eq!(buf[0], SIZE_INDICATOR_MASK | 2);
288            let (decoded, hdr) = decode(&buf).unwrap();
289            assert_eq!((decoded, hdr), (v, 3));
290        }
291    }
292
293    #[test]
294    fn rejects_oversize() {
295        let mut buf = [0u8; 4];
296        assert!(matches!(
297            encode_into(0x1_0000, &mut buf),
298            Err(Error::LengthTooLarge(0x1_0000))
299        ));
300    }
301
302    #[test]
303    fn rejects_indefinite_and_wide() {
304        assert!(decode(&[0x80]).is_err()); // indefinite form
305        assert!(decode(&[0x85, 0, 0, 0, 0, 0]).is_err()); // 5 length bytes
306        assert!(decode(&[]).is_err());
307        assert!(decode(&[0x82, 0x12]).is_err()); // truncated long form
308    }
309
310    /// r10-W-4: every wire form of a `length_field` is captured by
311    /// `decode_form` and reproduced byte-for-byte by `encode_with`: the
312    /// 1-octet short form, `0x81`, `0x82` (minimal and non-minimal) and
313    /// `0x83`/`0x84` (always non-minimal for a value capped at `0xFFFF`).
314    #[test]
315    fn every_form_round_trips_byte_exactly() {
316        let cases: &[(&[u8], usize, LengthForm)] = &[
317            (&[0x05], 5, LengthForm::Minimal),
318            (&[0x7F], 127, LengthForm::Minimal),
319            (&[0x81, 0x80], 0x80, LengthForm::Minimal),
320            (&[0x81, 0xFF], 0xFF, LengthForm::Minimal),
321            (&[0x82, 0x01, 0x00], 0x100, LengthForm::Minimal),
322            (&[0x82, 0xFF, 0xFF], 0xFFFF, LengthForm::Minimal),
323            // Non-minimal: recorded and reproduced.
324            (&[0x81, 0x05], 5, LengthForm::Long { octets: 1 }),
325            (&[0x81, 0x00], 0, LengthForm::Long { octets: 1 }),
326            // dvb-ci-runtime #337, captured raw on hardware.
327            (&[0x82, 0x00, 0x09], 9, LengthForm::Long { octets: 2 }),
328            (&[0x82, 0x00, 0x80], 0x80, LengthForm::Long { octets: 2 }),
329            (
330                &[0x83, 0x00, 0x01, 0x00],
331                0x100,
332                LengthForm::Long { octets: 3 },
333            ),
334            (&[0x83, 0x00, 0x00, 0x09], 9, LengthForm::Long { octets: 3 }),
335            (
336                &[0x84, 0x00, 0x00, 0x00, 0x09],
337                9,
338                LengthForm::Long { octets: 4 },
339            ),
340        ];
341        for &(wire, value, form) in cases {
342            let (v, hdr, f) = decode_form(wire).unwrap();
343            assert_eq!((v, hdr, f), (value, wire.len(), form), "{wire:02X?}");
344            let mut buf = [0u8; 8];
345            let n = encode_with(value, form, &mut buf).unwrap();
346            assert_eq!(&buf[..n], wire, "re-encode {wire:02X?}");
347            assert_eq!(encoded_len_with(value, form), wire.len());
348        }
349    }
350
351    /// The default form is the minimal coding (what `encode_into` writes).
352    #[test]
353    fn minimal_form_matches_encode_into() {
354        for v in [0usize, 1, 0x7F, 0x80, 0xFF, 0x100, 0x1234, 0xFFFF] {
355            let (mut a, mut b) = ([0u8; 4], [0u8; 4]);
356            let na = encode_into(v, &mut a).unwrap();
357            let nb = encode_with(v, LengthForm::default(), &mut b).unwrap();
358            assert_eq!(a[..na], b[..nb]);
359        }
360    }
361
362    #[test]
363    fn encode_with_rejects_a_form_that_cannot_hold_the_value() {
364        let mut buf = [0u8; 8];
365        // 0x100 needs 2 octets.
366        assert!(encode_with(0x100, LengthForm::Long { octets: 1 }, &mut buf).is_err());
367        // The minimal coding spelled as `Long` is an alias of `Minimal`: refused.
368        assert!(encode_with(0x80, LengthForm::Long { octets: 1 }, &mut buf).is_err());
369        assert!(encode_with(0xFF, LengthForm::Long { octets: 1 }, &mut buf).is_err());
370        assert!(encode_with(0x100, LengthForm::Long { octets: 2 }, &mut buf).is_err());
371        assert!(encode_with(0xFFFF, LengthForm::Long { octets: 2 }, &mut buf).is_err());
372        // Non-minimal long forms stay legal.
373        assert!(encode_with(0x7F, LengthForm::Long { octets: 1 }, &mut buf).is_ok());
374        assert!(encode_with(0x80, LengthForm::Long { octets: 2 }, &mut buf).is_ok());
375        assert!(encode_with(0x100, LengthForm::Long { octets: 3 }, &mut buf).is_ok());
376        assert!(encode_with(5, LengthForm::Long { octets: 0 }, &mut buf).is_err());
377        assert!(encode_with(5, LengthForm::Long { octets: 5 }, &mut buf).is_err());
378        assert!(encode_with(0x1_0000, LengthForm::Long { octets: 4 }, &mut buf).is_err());
379    }
380
381    #[test]
382    fn rejects_a_value_above_the_spec_cap() {
383        // 83 01 00 00 = 0x10000 > 65535.
384        assert!(matches!(
385            decode_form(&[0x83, 0x01, 0x00, 0x00]),
386            Err(Error::LengthTooLarge(0x1_0000))
387        ));
388    }
389
390    #[test]
391    fn mutating_a_byte_changes_decode() {
392        let mut buf = [0u8; 4];
393        encode_into(0x1234, &mut buf).unwrap();
394        let (a, _) = decode(&buf).unwrap();
395        buf[2] ^= 0xFF;
396        let (b, _) = decode(&buf).unwrap();
397        assert_ne!(a, b);
398    }
399}