Skip to main content

cbor_core/
decode_options.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use crate::{
4    Error, Float, Format, IoResult, Result, SequenceDecoder, SequenceReader, SimpleValue, Strictness, Value,
5    codec::{Argument, Head, HeadOrStop, Major},
6    io::{HexReader, HexSliceReader, MyReader, SliceReader},
7    limits,
8    parse::Parser,
9    tag::{NEG_BIG_INT, POS_BIG_INT},
10    util::{trim_leading_zeros, u64_from_slice},
11};
12
13/// Configuration for CBOR decoding.
14///
15/// `DecodeOptions` controls the input format ([`Binary`](Format::Binary),
16/// [`Hex`](Format::Hex), or [`Diagnostic`](Format::Diagnostic)) and the
17/// limits the decoder enforces against hostile or malformed input.
18/// Construct it with [`DecodeOptions::new`] (or `Default`), adjust
19/// settings with the builder methods, and call [`decode`](Self::decode)
20/// or [`read_from`](Self::read_from) for a single item, or
21/// [`sequence_decoder`](Self::sequence_decoder) / [`sequence_reader`](Self::sequence_reader)
22/// for a CBOR sequence.
23///
24/// The convenience methods on [`Value`] ([`decode`](Value::decode),
25/// [`decode_hex`](Value::decode_hex), [`read_from`](Value::read_from),
26/// [`read_hex_from`](Value::read_hex_from)) all forward to a default
27/// `DecodeOptions`. Use this type directly when you need to decode
28/// diagnostic notation, iterate a sequence, relax a limit for a known
29/// input, or tighten one for untrusted input.
30///
31/// # Options
32///
33/// | Option | Default | Purpose |
34/// |---|---|---|
35/// | [`format`](Self::format) | [`Binary`](Format::Binary) | Input syntax: binary, hex text, or diagnostic notation. |
36/// | [`recursion_limit`](Self::recursion_limit) | 200 | Maximum nesting depth of arrays, maps, and tags. |
37/// | [`length_limit`](Self::length_limit) | 1,000,000,000 | Maximum declared element count of a single array, map, byte string, or text string. |
38/// | [`oom_mitigation`](Self::oom_mitigation) | 100,000,000 | Byte budget for speculative pre-allocation. |
39/// | [`strictness`](Self::strictness) | [`Strictness::STRICT`] | Which non-deterministic encodings the decoder accepts and normalizes. |
40///
41/// ## `recursion_limit`
42///
43/// Each array, map, or tag consumes one unit of recursion budget for
44/// its contents. Exceeding the limit returns [`Error::NestingTooDeep`].
45/// The limit protects against stack overflow on adversarial input and
46/// should be well below the stack a thread has available.
47///
48/// ## `length_limit`
49///
50/// Applies to the length field in the CBOR head of arrays, maps, byte
51/// strings, and text strings. It caps the declared size before any
52/// bytes are read, so a malicious header claiming a petabyte-long
53/// string is rejected immediately with [`Error::LengthTooLarge`]. The
54/// limit does not restrict total input size; a valid document may
55/// contain many items each up to the limit.
56///
57/// ## `oom_mitigation`
58///
59/// CBOR encodes lengths in the head, so a decoder is tempted to
60/// pre-allocate a `Vec` of the declared capacity. On hostile input
61/// that is a trivial amplification attack: a few bytes on the wire
62/// reserve gigabytes of memory. `oom_mitigation` is a byte budget,
63/// shared across the current decode, that caps the total amount of
64/// speculative capacity the decoder may reserve for array backing
65/// storage. Once the budget is exhausted, further arrays start empty
66/// and grow on demand. Decoding still succeeds if the input is
67/// well-formed; only the up-front reservation is bounded.
68///
69/// The budget is consumed, not refilled: a deeply nested structure
70/// with many small arrays can drain it early and decode the tail with
71/// zero pre-allocation. That is the intended behavior.
72///
73/// # Examples
74///
75/// Decode binary CBOR with default limits:
76///
77/// ```
78/// use cbor_core::DecodeOptions;
79///
80/// let v = DecodeOptions::new().decode(&[0x18, 42]).unwrap();
81/// assert_eq!(v.to_u32().unwrap(), 42);
82/// ```
83///
84/// Switch the input format to hex text or diagnostic notation:
85///
86/// ```
87/// use cbor_core::{DecodeOptions, Format};
88///
89/// let v = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
90/// assert_eq!(v.to_u32().unwrap(), 42);
91///
92/// let v = DecodeOptions::new().format(Format::Diagnostic).decode("42").unwrap();
93/// assert_eq!(v.to_u32().unwrap(), 42);
94/// ```
95///
96/// Tighten limits for input from an untrusted source:
97///
98/// ```
99/// use cbor_core::DecodeOptions;
100///
101/// let strict = DecodeOptions::new()
102///     .recursion_limit(16)
103///     .length_limit(4096)
104///     .oom_mitigation(64 * 1024);
105///
106/// assert!(strict.decode(&[0x18, 42]).is_ok());
107/// ```
108#[derive(Debug, Clone)]
109pub struct DecodeOptions {
110    pub(crate) format: Format,
111    pub(crate) recursion_limit: u16,
112    pub(crate) length_limit: u64,
113    pub(crate) oom_mitigation: usize,
114    pub(crate) strictness: Strictness,
115}
116
117impl Default for DecodeOptions {
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl DecodeOptions {
124    /// Create a new set of options with the crate defaults.
125    ///
126    /// ```
127    /// use cbor_core::DecodeOptions;
128    ///
129    /// let opts = DecodeOptions::new();
130    /// let v = opts.decode(&[0x18, 42]).unwrap();
131    /// assert_eq!(v.to_u32().unwrap(), 42);
132    /// ```
133    #[must_use]
134    pub const fn new() -> Self {
135        Self {
136            format: Format::Binary,
137            recursion_limit: limits::RECURSION_LIMIT,
138            length_limit: limits::LENGTH_LIMIT,
139            oom_mitigation: limits::OOM_MITIGATION,
140            strictness: Strictness::STRICT,
141        }
142    }
143
144    /// Select the input format: [`Binary`](Format::Binary),
145    /// [`Hex`](Format::Hex), or [`Diagnostic`](Format::Diagnostic).
146    ///
147    /// Default: [`Format::Binary`].
148    ///
149    /// ```
150    /// use cbor_core::{DecodeOptions, Format};
151    ///
152    /// let hex = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
153    /// let bin = DecodeOptions::new().decode(&[0x18, 0x2a]).unwrap();
154    /// assert_eq!(hex, bin);
155    ///
156    /// let v = DecodeOptions::new().format(Format::Diagnostic).decode("42").unwrap();
157    /// assert_eq!(v.to_u32().unwrap(), 42);
158    /// ```
159    #[must_use]
160    pub const fn format(mut self, format: Format) -> Self {
161        self.format = format;
162        self
163    }
164
165    /// Set the maximum nesting depth of arrays, maps, and tags.
166    ///
167    /// Default: 200. Input that exceeds the limit returns
168    /// [`Error::NestingTooDeep`].
169    ///
170    /// ```
171    /// use cbor_core::{DecodeOptions, Error};
172    ///
173    /// // Two nested one-element arrays: 0x81 0x81 0x00
174    /// let err = DecodeOptions::new()
175    ///     .recursion_limit(1)
176    ///     .decode(&[0x81, 0x81, 0x00])
177    ///     .unwrap_err();
178    /// assert_eq!(err, Error::NestingTooDeep);
179    /// ```
180    #[must_use]
181    pub const fn recursion_limit(mut self, limit: u16) -> Self {
182        self.recursion_limit = limit;
183        self
184    }
185
186    /// Set the maximum declared length for byte strings, text strings,
187    /// arrays, and maps.
188    ///
189    /// Default: 1,000,000,000. Checked against the length field in the
190    /// CBOR head before any bytes are consumed; an oversized declaration
191    /// returns [`Error::LengthTooLarge`].
192    ///
193    /// ```
194    /// use cbor_core::{DecodeOptions, Error};
195    ///
196    /// // A five-byte text string: 0x65 'h' 'e' 'l' 'l' 'o'
197    /// let err = DecodeOptions::new()
198    ///     .length_limit(4)
199    ///     .decode(b"\x65hello")
200    ///     .unwrap_err();
201    /// assert_eq!(err, Error::LengthTooLarge);
202    /// ```
203    #[must_use]
204    pub const fn length_limit(mut self, limit: u64) -> Self {
205        self.length_limit = limit;
206        self
207    }
208
209    /// Set the byte budget for speculative pre-allocation of array
210    /// backing storage.
211    ///
212    /// Default: 100,000,000. Lower values trade a small amount of
213    /// decoding throughput for stronger resistance to memory-amplification
214    /// attacks. Valid input decodes regardless; only the up-front
215    /// reservation is bounded.
216    ///
217    /// ```
218    /// use cbor_core::DecodeOptions;
219    ///
220    /// // A two-element array: 0x82 0x01 0x02
221    /// let v = DecodeOptions::new()
222    ///     .oom_mitigation(0)
223    ///     .decode(&[0x82, 0x01, 0x02])
224    ///     .unwrap();
225    /// assert_eq!(v.len(), Some(2));
226    /// ```
227    #[must_use]
228    pub const fn oom_mitigation(mut self, bytes: usize) -> Self {
229        self.oom_mitigation = bytes;
230        self
231    }
232
233    /// Configure which non-deterministic encodings the decoder will
234    /// accept. Default: [`Strictness::STRICT`], which rejects every
235    /// deviation with [`Error::NonDeterministic`].
236    ///
237    /// Pass [`Strictness::LENIENT`] to accept all known deviations, or
238    /// build a custom mix of `allow_*` fields. Tolerated input is
239    /// normalized while decoding, so the resulting [`Value`] is
240    /// canonical and re-encoding it produces CBOR::Core compliant
241    /// bytes.
242    ///
243    /// ```
244    /// use cbor_core::{DecodeOptions, Strictness, Value};
245    ///
246    /// // 255 wrongly encoded with a two byte argument; normalized on read.
247    /// let v = DecodeOptions::new()
248    ///     .strictness(Strictness::LENIENT)
249    ///     .decode(&[0x19, 0x00, 0xff])
250    ///     .unwrap();
251    /// assert_eq!(v, Value::from(255));
252    /// assert_eq!(v.encode(), vec![0x18, 0xff]);
253    /// ```
254    #[must_use]
255    pub const fn strictness(mut self, strictness: Strictness) -> Self {
256        self.strictness = strictness;
257        self
258    }
259
260    /// Decode exactly one CBOR data item from an in-memory buffer.
261    ///
262    /// Takes the input by reference: `&[u8]`, `&[u8; N]`, `&Vec<u8>`,
263    /// `&str`, `&String`, etc. all work via `T: AsRef<[u8]> + ?Sized`.
264    /// In [`Format::Binary`], decoded text and byte strings borrow
265    /// directly from the input slice and the returned [`Value`]
266    /// inherits that lifetime; in [`Format::Hex`] and
267    /// [`Format::Diagnostic`] the result is owned.
268    ///
269    /// The input must contain **exactly one** value. Use
270    /// [`sequence_decoder`](Self::sequence_decoder) when the input is a
271    /// CBOR sequence.
272    ///
273    /// # Errors
274    ///
275    /// * [`Error::InvalidFormat`] if any bytes remain after the value
276    ///   has been read. In [`Format::Diagnostic`] mode trailing
277    ///   whitespace and comments are accepted, but nothing else.
278    /// * [`Error::UnexpectedEof`] for an empty buffer (in diagnostic
279    ///   notation, one containing only whitespace and comments) or a
280    ///   truncated value.
281    /// * Any other [`Error`](crate::Error) variant that the decoder
282    ///   raises for malformed, non-canonical, or oversized input.
283    ///
284    /// ```
285    /// use cbor_core::{DecodeOptions, Format};
286    ///
287    /// let v = DecodeOptions::new().decode(&[0x18, 42]).unwrap();
288    /// assert_eq!(v.to_u32().unwrap(), 42);
289    ///
290    /// let v = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
291    /// assert_eq!(v.to_u32().unwrap(), 42);
292    ///
293    /// let v = DecodeOptions::new()
294    ///     .format(Format::Diagnostic)
295    ///     .decode("42  / trailing comment is fine /")
296    ///     .unwrap();
297    /// assert_eq!(v.to_u32().unwrap(), 42);
298    /// ```
299    pub fn decode<'a, T>(&self, bytes: &'a T) -> Result<Value<'a>>
300    where
301        T: AsRef<[u8]> + ?Sized,
302    {
303        let bytes = bytes.as_ref();
304        match self.format {
305            Format::Binary => {
306                let mut reader = SliceReader(bytes);
307                let value = self.do_read(&mut reader, self.recursion_limit, self.oom_mitigation)?;
308                if !reader.0.is_empty() {
309                    return Err(Error::InvalidFormat);
310                }
311                Ok(value)
312            }
313            Format::Hex => {
314                let mut reader = HexSliceReader(bytes);
315                let value = self.do_read(&mut reader, self.recursion_limit, self.oom_mitigation)?;
316                if !reader.0.is_empty() {
317                    return Err(Error::InvalidFormat);
318                }
319                Ok(value)
320            }
321            Format::Diagnostic => {
322                let mut parser = Parser::new(SliceReader(bytes), self.recursion_limit, self.strictness);
323                parser.parse_complete()
324            }
325        }
326    }
327
328    /// Decode exactly one CBOR data item into an owned [`Value`].
329    ///
330    /// Takes the input by value: `Vec<u8>`, `&[u8]`, `&str`, and
331    /// anything else that implements `AsRef<[u8]>` all work. Unlike
332    /// [`decode`](Self::decode), the result never borrows from the
333    /// input regardless of format: text and byte strings are always
334    /// copied into owned allocations. The returned value can be held
335    /// as `Value<'static>` and stored or sent across threads without
336    /// any lifetime constraint.
337    ///
338    /// Use this when the input is short-lived (a temporary buffer, a
339    /// `Vec` returned from a function, etc.) and the decoded value
340    /// needs to outlive it. When the input already lives long enough,
341    /// [`decode`](Self::decode) avoids the copies.
342    ///
343    /// The input must contain **exactly one** value. Use
344    /// [`sequence_decoder`](Self::sequence_decoder) when the input is a
345    /// CBOR sequence.
346    ///
347    /// # Errors
348    ///
349    /// Same as [`decode`](Self::decode).
350    ///
351    /// ```
352    /// use cbor_core::{DecodeOptions, Format, Value};
353    ///
354    /// // Decode from a short-lived Vec without worrying about lifetimes.
355    /// let bytes: Vec<u8> = vec![0x18, 42];
356    /// let v: Value<'static> = DecodeOptions::new().decode_owned(bytes).unwrap();
357    /// assert_eq!(v.to_u32().unwrap(), 42);
358    ///
359    /// // Hex and diagnostic formats work the same way.
360    /// let v: Value<'static> = DecodeOptions::new()
361    ///     .format(Format::Hex)
362    ///     .decode_owned("182a")
363    ///     .unwrap();
364    /// assert_eq!(v.to_u32().unwrap(), 42);
365    /// ```
366    pub fn decode_owned<'a>(&self, bytes: impl AsRef<[u8]>) -> Result<Value<'a>> {
367        let mut bytes = bytes.as_ref();
368
369        match self.format {
370            Format::Binary | Format::Hex => {
371                let value = self.read_from(&mut bytes).map_err(|err| match err {
372                    crate::IoError::Io(_io_error) => unreachable!(),
373                    crate::IoError::Data(error) => error,
374                })?;
375
376                if bytes.is_empty() {
377                    Ok(value)
378                } else {
379                    Err(Error::InvalidFormat)
380                }
381            }
382
383            Format::Diagnostic => {
384                let mut parser = Parser::new(SliceReader(bytes), self.recursion_limit, self.strictness);
385                parser.parse_complete()
386            }
387        }
388    }
389
390    /// Read a single CBOR data item from a stream.
391    ///
392    /// Designed to be called repeatedly to pull successive elements of
393    /// a CBOR sequence:
394    ///
395    /// * In [`Format::Binary`] and [`Format::Hex`] the reader is
396    ///   consumed only up to the end of the item; any bytes after
397    ///   remain in the stream.
398    /// * In [`Format::Diagnostic`] trailing whitespace and comments
399    ///   are consumed up to either end of stream or a top-level
400    ///   separator comma (the comma is also consumed). Anything else
401    ///   after the value fails with [`Error::InvalidFormat`].
402    ///
403    /// Bytes are read into an internal buffer, so the result is
404    /// always owned and can be held as `Value<'static>`. For
405    /// zero-copy decoding from a byte slice, use
406    /// [`decode`](Self::decode) instead.
407    ///
408    /// # Errors
409    ///
410    /// * [`IoError::Io`](crate::IoError::Io) wrapping any I/O failure
411    ///   reported by the reader.
412    /// * [`IoError::Data`](crate::IoError::Data) wrapping any
413    ///   [`Error`](crate::Error) variant raised by the decoder for
414    ///   malformed, non-canonical, or oversized input.
415    ///
416    /// ```
417    /// use cbor_core::{DecodeOptions, Format};
418    ///
419    /// let mut bytes: &[u8] = &[0x18, 42];
420    /// let v = DecodeOptions::new().read_from(&mut bytes).unwrap();
421    /// assert_eq!(v.to_u32().unwrap(), 42);
422    ///
423    /// let mut hex: &[u8] = b"182a";
424    /// let v = DecodeOptions::new().format(Format::Hex).read_from(&mut hex).unwrap();
425    /// assert_eq!(v.to_u32().unwrap(), 42);
426    ///
427    /// // Diagnostic: repeated read_from pulls successive sequence items.
428    /// let mut diag: &[u8] = b"1, 2, 3";
429    /// let opts = DecodeOptions::new().format(Format::Diagnostic);
430    /// let a = opts.read_from(&mut diag).unwrap();
431    /// let b = opts.read_from(&mut diag).unwrap();
432    /// let c = opts.read_from(&mut diag).unwrap();
433    /// assert_eq!(a.to_u32().unwrap(), 1);
434    /// assert_eq!(b.to_u32().unwrap(), 2);
435    /// assert_eq!(c.to_u32().unwrap(), 3);
436    /// ```
437    pub fn read_from<'a>(&self, reader: impl std::io::Read) -> IoResult<Value<'a>> {
438        match self.format {
439            Format::Binary => {
440                let mut reader = reader;
441                self.do_read(&mut reader, self.recursion_limit, self.oom_mitigation)
442            }
443            Format::Hex => {
444                let mut reader = HexReader(reader);
445                self.do_read(&mut reader, self.recursion_limit, self.oom_mitigation)
446            }
447            Format::Diagnostic => {
448                let mut parser = Parser::new(reader, self.recursion_limit, self.strictness);
449                parser.parse_stream_item()
450            }
451        }
452    }
453
454    /// Create an iterator over a CBOR sequence stored in memory.
455    ///
456    /// The returned [`SequenceDecoder`] yields each successive item of the
457    /// sequence as `Result<Value<'a>>`, where `'a` is the lifetime of
458    /// the input slice. In binary format, items borrow text and byte
459    /// strings from the input; in hex and diagnostic format the items
460    /// are owned. The iterator captures a snapshot of these options;
461    /// subsequent changes to `self` do not affect it.
462    ///
463    /// ```
464    /// use cbor_core::{DecodeOptions, Format};
465    ///
466    /// let opts = DecodeOptions::new().format(Format::Diagnostic);
467    ///
468    /// let items: Vec<_> = opts
469    ///     .sequence_decoder(b"1, 2, 3,")
470    ///     .collect::<Result<_, _>>()
471    ///     .unwrap();
472    /// assert_eq!(items.len(), 3);
473    /// ```
474    pub fn sequence_decoder<'a, T>(&self, input: &'a T) -> SequenceDecoder<'a>
475    where
476        T: AsRef<[u8]> + ?Sized,
477    {
478        SequenceDecoder::with_options(self.clone(), input.as_ref())
479    }
480
481    /// Create an iterator over a CBOR sequence read from a stream.
482    ///
483    /// The returned [`SequenceReader`] yields each successive item as
484    /// `IoResult<Value<'static>>`. `None` indicates a clean end
485    /// between items; a truncated item produces `Some(Err(_))`. Items
486    /// are always owned (the bytes are read into an internal
487    /// buffer); for zero-copy iteration use
488    /// [`sequence_decoder`](Self::sequence_decoder) on a byte slice
489    /// instead.
490    ///
491    /// ```
492    /// use cbor_core::DecodeOptions;
493    ///
494    /// // Binary CBOR sequence: three one-byte items 0x01 0x02 0x03.
495    /// let bytes: &[u8] = &[0x01, 0x02, 0x03];
496    /// let items: Vec<_> = DecodeOptions::new()
497    ///     .sequence_reader(bytes)
498    ///     .collect::<Result<_, _>>()
499    ///     .unwrap();
500    /// assert_eq!(items.len(), 3);
501    /// ```
502    pub fn sequence_reader<R: std::io::Read>(&self, reader: R) -> SequenceReader<R> {
503        SequenceReader::with_options(self.clone(), reader)
504    }
505
506    /// Decode exactly one CBOR data item from an arbitrary reader.
507    /// Used by the sequence iterators to share the core decoding logic.
508    pub(crate) fn decode_one<'a, R>(&self, reader: &mut R) -> std::result::Result<Value<'a>, R::Error>
509    where
510        R: MyReader<'a>,
511        R::Error: From<Error>,
512    {
513        self.do_read(reader, self.recursion_limit, self.oom_mitigation)
514    }
515
516    fn do_read<'a, R>(
517        &self,
518        reader: &mut R,
519        recursion_limit: u16,
520        oom_mitigation: usize,
521    ) -> std::result::Result<Value<'a>, R::Error>
522    where
523        R: MyReader<'a>,
524        R::Error: From<Error>,
525    {
526        match self.read_value_or_break(reader, recursion_limit, oom_mitigation)? {
527            Some(value) => Ok(value),
528            // A break code where a value was expected (top level, array
529            // item position, map key position, tag content) is malformed.
530            None => Err(Error::Malformed.into()),
531        }
532    }
533
534    /// Read the next item, returning `Ok(None)` when a break code stops
535    /// the input. Used by indefinite-length container loops, which need
536    /// to terminate on the break.
537    fn read_value_or_break<'a, R>(
538        &self,
539        reader: &mut R,
540        recursion_limit: u16,
541        oom_mitigation: usize,
542    ) -> std::result::Result<Option<Value<'a>>, R::Error>
543    where
544        R: MyReader<'a>,
545        R::Error: From<Error>,
546    {
547        match HeadOrStop::read_from(reader)? {
548            HeadOrStop::Definite(head) => self
549                .process_head(head, reader, recursion_limit, oom_mitigation)
550                .map(Some),
551
552            HeadOrStop::Indefinite(major) => {
553                if self.strictness.allow_indefinite_length {
554                    self.process_indefinite(major, reader, recursion_limit, oom_mitigation)
555                        .map(Some)
556                } else {
557                    Err(Error::NonDeterministic.into())
558                }
559            }
560
561            HeadOrStop::Break => Ok(None),
562        }
563    }
564
565    fn process_head<'a, R>(
566        &self,
567        head: Head,
568        reader: &mut R,
569        recursion_limit: u16,
570        oom_mitigation: usize,
571    ) -> std::result::Result<Value<'a>, R::Error>
572    where
573        R: MyReader<'a>,
574        R::Error: From<Error>,
575    {
576        let is_float = head.initial_byte.major() == Major::SimpleOrFloat
577            && matches!(head.argument, Argument::U16(_) | Argument::U32(_) | Argument::U64(_));
578
579        if !is_float && !head.argument.is_deterministic() && !self.strictness.allow_non_shortest_integers {
580            return Err(Error::NonDeterministic.into());
581        }
582
583        let this = match head.initial_byte.major() {
584            Major::Unsigned => Value::Unsigned(head.value()),
585            Major::Negative => Value::Negative(head.value()),
586
587            Major::ByteString => {
588                let len = head.value();
589                if len > self.length_limit {
590                    return Err(Error::LengthTooLarge.into());
591                }
592                Value::ByteString(reader.read_cow(len, oom_mitigation)?)
593            }
594
595            Major::TextString => {
596                let len = head.value();
597                if len > self.length_limit {
598                    return Err(Error::LengthTooLarge.into());
599                }
600                let text = match reader.read_cow(len, oom_mitigation)? {
601                    Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8(bytes).map_err(Error::from)?),
602                    Cow::Owned(bytes) => Cow::Owned(String::from_utf8(bytes).map_err(Error::from)?),
603                };
604                Value::TextString(text)
605            }
606
607            Major::Array => {
608                let value = head.value();
609
610                if value > self.length_limit {
611                    return Err(Error::LengthTooLarge.into());
612                }
613
614                let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
615                    return Err(Error::NestingTooDeep.into());
616                };
617
618                let request: usize = value.try_into().or(Err(Error::LengthTooLarge))?;
619                let granted = request.min(oom_mitigation / size_of::<Value>());
620                let oom_mitigation = oom_mitigation - granted * size_of::<Value>();
621
622                let mut vec = Vec::with_capacity(granted);
623
624                for _ in 0..value {
625                    vec.push(self.do_read(reader, recursion_limit, oom_mitigation)?);
626                }
627
628                Value::Array(vec)
629            }
630
631            Major::Map => {
632                let value = head.value();
633
634                if value > self.length_limit {
635                    return Err(Error::LengthTooLarge.into());
636                }
637
638                let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
639                    return Err(Error::NestingTooDeep.into());
640                };
641
642                let mut map = BTreeMap::new();
643                for _ in 0..value {
644                    let key = self.do_read(reader, recursion_limit, oom_mitigation)?;
645                    let val = self.do_read(reader, recursion_limit, oom_mitigation)?;
646                    self.map_insert(&mut map, key, val)?;
647                }
648
649                Value::Map(map)
650            }
651
652            Major::Tag => {
653                let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
654                    return Err(Error::NestingTooDeep.into());
655                };
656
657                let tag_number = head.value();
658                let tag_content = self.do_read(reader, recursion_limit, oom_mitigation)?;
659
660                // Big integer canonicalization (tag 2 / tag 3): the
661                // payload must be a byte string longer than 8 bytes
662                // (otherwise the value fits in u64) with no leading
663                // zero byte.
664                match tag_content {
665                    Value::ByteString(bytes) if matches!(tag_number, POS_BIG_INT | NEG_BIG_INT) => {
666                        let canonical = bytes.len() > 8 && bytes[0] != 0;
667                        if canonical {
668                            Value::Tag(tag_number, Box::new(Value::ByteString(bytes)))
669                        } else if self.strictness.allow_oversized_bigints {
670                            normalize_bigint(tag_number, bytes)
671                        } else {
672                            return Err(Error::NonDeterministic.into());
673                        }
674                    }
675                    other => Value::Tag(tag_number, Box::new(other)),
676                }
677            }
678
679            Major::SimpleOrFloat => match head.argument {
680                Argument::None => Value::SimpleValue(SimpleValue(head.initial_byte.info())),
681                Argument::U8(n) if n >= 32 => Value::SimpleValue(SimpleValue(n)),
682
683                Argument::U16(bits) => Value::Float(Float::from_bits_u16(bits)),
684                Argument::U32(bits) => self.checked_float(Float::from_bits_u32(bits))?,
685                Argument::U64(bits) => self.checked_float(Float::from_bits_u64(bits))?,
686
687                _ => return Err(Error::Malformed.into()),
688            },
689        };
690
691        Ok(this)
692    }
693
694    fn checked_float<'a>(&self, float: Float) -> Result<Value<'a>> {
695        if float.is_deterministic() {
696            Ok(Value::Float(float))
697        } else if self.strictness.allow_non_shortest_floats {
698            Ok(Value::Float(float.shortest()))
699        } else {
700            Err(Error::NonDeterministic)
701        }
702    }
703
704    /// Insert a key/value pair into a map under the active determinism
705    /// policy. Used by both definite and indefinite-length map decoders.
706    fn map_insert<'a>(&self, map: &mut BTreeMap<Value<'a>, Value<'a>>, key: Value<'a>, val: Value<'a>) -> Result<()> {
707        if !self.strictness.allow_unsorted_map_keys
708            && let Some(last) = map.last_entry()
709            && *last.key() >= key
710        {
711            Err(Error::NonDeterministic)
712        } else if map.insert(key, val).is_some() && !self.strictness.allow_duplicate_map_keys {
713            Err(Error::NonDeterministic)
714        } else {
715            Ok(())
716        }
717    }
718
719    /// Decode an indefinite-length container of the given major type.
720    /// The break code that terminates the container is consumed.
721    fn process_indefinite<'a, R>(
722        &self,
723        major: Major,
724        reader: &mut R,
725        recursion_limit: u16,
726        oom_mitigation: usize,
727    ) -> std::result::Result<Value<'a>, R::Error>
728    where
729        R: MyReader<'a>,
730        R::Error: From<Error>,
731    {
732        match major {
733            Major::ByteString => self.read_indefinite_bytes(reader, oom_mitigation),
734            Major::TextString => self.read_indefinite_text(reader, oom_mitigation),
735            Major::Array => self.read_indefinite_array(reader, recursion_limit, oom_mitigation),
736            Major::Map => self.read_indefinite_map(reader, recursion_limit, oom_mitigation),
737            _ => unreachable!("process_indefinite: invalid major"),
738        }
739    }
740
741    /// Read a `(_ chunk*)` byte string. Each chunk is itself a
742    /// definite-length byte string; an indefinite-length chunk or a
743    /// chunk of a different major type is malformed even in lenient
744    /// mode.
745    fn read_indefinite_bytes<'a, R>(
746        &self,
747        reader: &mut R,
748        oom_mitigation: usize,
749    ) -> std::result::Result<Value<'a>, R::Error>
750    where
751        R: MyReader<'a>,
752        R::Error: From<Error>,
753    {
754        let mut buf = Vec::new();
755        let mut total: u64 = 0;
756
757        loop {
758            match HeadOrStop::read_from(reader)? {
759                HeadOrStop::Break => break,
760
761                HeadOrStop::Definite(head) if head.initial_byte.major() == Major::ByteString => {
762                    if !head.argument.is_deterministic() && !self.strictness.allow_non_shortest_integers {
763                        return Err(Error::NonDeterministic.into());
764                    }
765
766                    let chunk_len = head.value();
767
768                    total = total.checked_add(chunk_len).ok_or(Error::LengthTooLarge)?;
769                    if total > self.length_limit {
770                        return Err(Error::LengthTooLarge.into());
771                    }
772
773                    let chunk = reader.read_cow(chunk_len, oom_mitigation)?;
774                    buf.extend_from_slice(&chunk);
775                }
776
777                _ => return Err(Error::Malformed.into()),
778            }
779        }
780
781        Ok(Value::ByteString(Cow::Owned(buf)))
782    }
783
784    /// Read a `(_ chunk*)` text string. Each chunk is independently
785    /// validated as UTF-8 (per RFC 8949 ยง3.2.2).
786    fn read_indefinite_text<'a, R>(
787        &self,
788        reader: &mut R,
789        oom_mitigation: usize,
790    ) -> std::result::Result<Value<'a>, R::Error>
791    where
792        R: MyReader<'a>,
793        R::Error: From<Error>,
794    {
795        let mut buf = String::new();
796        let mut total: u64 = 0;
797
798        loop {
799            match HeadOrStop::read_from(reader)? {
800                HeadOrStop::Break => break,
801
802                HeadOrStop::Definite(head) if head.initial_byte.major() == Major::TextString => {
803                    if !head.argument.is_deterministic() && !self.strictness.allow_non_shortest_integers {
804                        return Err(Error::NonDeterministic.into());
805                    }
806
807                    let chunk_len = head.value();
808
809                    total = total.checked_add(chunk_len).ok_or(Error::LengthTooLarge)?;
810                    if total > self.length_limit {
811                        return Err(Error::LengthTooLarge.into());
812                    }
813
814                    let chunk = reader.read_cow(chunk_len, oom_mitigation)?;
815                    buf.push_str(std::str::from_utf8(&chunk).map_err(Error::from)?);
816                }
817
818                _ => return Err(Error::Malformed.into()),
819            }
820        }
821
822        Ok(Value::TextString(Cow::Owned(buf)))
823    }
824
825    fn read_indefinite_array<'a, R>(
826        &self,
827        reader: &mut R,
828        recursion_limit: u16,
829        oom_mitigation: usize,
830    ) -> std::result::Result<Value<'a>, R::Error>
831    where
832        R: MyReader<'a>,
833        R::Error: From<Error>,
834    {
835        let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
836            return Err(Error::NestingTooDeep.into());
837        };
838
839        let mut vec = Vec::new();
840
841        for _ in 0..self.length_limit {
842            match self.read_value_or_break(reader, recursion_limit, oom_mitigation)? {
843                Some(item) => vec.push(item),
844                None => return Ok(Value::Array(vec)),
845            }
846        }
847
848        match HeadOrStop::read_from(reader)? {
849            HeadOrStop::Definite(_) => Err(Error::LengthTooLarge.into()),
850            HeadOrStop::Indefinite(_) => Err(Error::Malformed.into()),
851            HeadOrStop::Break => Ok(Value::Array(vec)),
852        }
853    }
854
855    fn read_indefinite_map<'a, R>(
856        &self,
857        reader: &mut R,
858        recursion_limit: u16,
859        oom_mitigation: usize,
860    ) -> std::result::Result<Value<'a>, R::Error>
861    where
862        R: MyReader<'a>,
863        R::Error: From<Error>,
864    {
865        let Some(recursion_limit) = recursion_limit.checked_sub(1) else {
866            return Err(Error::NestingTooDeep.into());
867        };
868
869        let mut map = BTreeMap::new();
870
871        for _ in 0..self.length_limit {
872            match self.read_value_or_break(reader, recursion_limit, oom_mitigation)? {
873                Some(key) => {
874                    let value = self.do_read(reader, recursion_limit, oom_mitigation)?;
875                    self.map_insert(&mut map, key, value)?;
876                }
877                None => return Ok(Value::Map(map)),
878            }
879        }
880
881        match HeadOrStop::read_from(reader)? {
882            HeadOrStop::Definite(_) => Err(Error::LengthTooLarge.into()),
883            HeadOrStop::Indefinite(_) => Err(Error::Malformed.into()),
884            HeadOrStop::Break => Ok(Value::Map(map)),
885        }
886    }
887}
888
889/// Normalize a non-canonical big integer payload.
890///
891/// Strips leading zero bytes and downcasts to
892/// [`Value::Unsigned`] / [`Value::Negative`] when the magnitude fits
893/// in a `u64`. Otherwise returns a tag 2 / tag 3 with a stripped
894/// payload, preserving the [`Cow`] borrow when the input was borrowed.
895fn normalize_bigint(tag_number: u64, bytes: Cow<'_, [u8]>) -> Value<'_> {
896    fn integer<'b>(tag_number: u64, n: u64) -> Value<'b> {
897        match tag_number {
898            POS_BIG_INT => Value::Unsigned(n),
899            NEG_BIG_INT => Value::Negative(n),
900            _other => unreachable!("normalize_bigint: invalid tag"),
901        }
902    }
903
904    match bytes {
905        Cow::Borrowed(bytes) => {
906            let trimmed = trim_leading_zeros(bytes);
907
908            if let Ok(n) = u64_from_slice(trimmed) {
909                integer(tag_number, n)
910            } else {
911                let bytes = trimmed.into();
912                Value::Tag(tag_number, Box::new(Value::ByteString(bytes)))
913            }
914        }
915        Cow::Owned(bytes) => {
916            let trimmed = trim_leading_zeros(&bytes);
917
918            if let Ok(n) = u64_from_slice(trimmed) {
919                integer(tag_number, n)
920            } else {
921                let bytes = if trimmed.len() == bytes.len() {
922                    bytes.into()
923                } else {
924                    trimmed.to_vec().into()
925                };
926                Value::Tag(tag_number, Box::new(Value::ByteString(bytes)))
927            }
928        }
929    }
930}