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