1use crate::{CborError, CborValue, MAX_DAG_CBOR_INPUT_LEN, MAX_NESTING_DEPTH};
6use std::cmp::Ordering;
7use std::str;
8
9const MT_UINT: u8 = 0;
10const MT_NEGINT: u8 = 1;
11const MT_BYTES: u8 = 2;
12const MT_STRING: u8 = 3;
13const MT_ARRAY: u8 = 4;
14const MT_MAP: u8 = 5;
15const CONTAINER_INITIAL_RESERVE: usize = 8;
16
17const MIN_ELEMENT_ENCODED_LEN: usize = 1;
22
23pub fn decode_dag_cbor(bytes: &[u8]) -> Result<CborValue, CborError> {
33 if bytes.len() > MAX_DAG_CBOR_INPUT_LEN {
34 return Err(CborError::InputTooLarge);
35 }
36 let (value, offset) = decode_value(bytes, 0, 0)?;
37 if offset != bytes.len() {
38 return Err(CborError::TrailingBytes);
39 }
40 Ok(value)
41}
42
43fn decode_value(
47 bytes: &[u8],
48 mut offset: usize,
49 depth: usize,
50) -> Result<(CborValue, usize), CborError> {
51 if offset >= bytes.len() {
52 return Err(CborError::UnexpectedEnd);
53 }
54
55 let first = bytes[offset];
56 offset = offset.checked_add(1).ok_or(CborError::OffsetOverflow)?;
57
58 let major = first >> 5;
59 let ai = first & 0x1f;
60
61 let (arg, new_offset) = read_argument(bytes, offset, ai)?;
62 offset = new_offset;
63
64 match major {
65 MT_UINT => Ok((
66 CborValue::Int(i64::try_from(arg).map_err(|_| CborError::IntegerOutOfRange)?),
67 offset,
68 )),
69
70 MT_NEGINT => {
71 let magnitude = i128::from(arg);
72 let value = (-1_i128)
73 .checked_sub(magnitude)
74 .ok_or(CborError::IntegerOutOfRange)?;
75 Ok((
76 CborValue::Int(i64::try_from(value).map_err(|_| CborError::IntegerOutOfRange)?),
77 offset,
78 ))
79 }
80
81 MT_BYTES => {
82 let (b, off) = extract_bytes(bytes, offset, arg)?;
83 Ok((CborValue::Bytes(b), off))
84 }
85
86 MT_STRING => {
87 let (s, off) = extract_string(bytes, offset, arg)?;
88 Ok((CborValue::String(s), off))
89 }
90
91 MT_ARRAY => {
92 let child_depth = descend(depth)?;
93 let item_count = usize::try_from(arg).map_err(|_| CborError::LengthTooLarge)?;
94 bounded_capacity(item_count, bytes.len(), offset)?;
100 let capacity = initial_container_capacity(item_count);
101 let mut items = Vec::with_capacity(capacity);
102 let mut off = offset;
103 for _ in 0..item_count {
104 let (v, next) = decode_value(bytes, off, child_depth)?;
105 items.push(v);
106 off = next;
107 }
108 Ok((CborValue::Array(items), off))
109 }
110
111 MT_MAP => {
112 let child_depth = descend(depth)?;
113 let entry_count = usize::try_from(arg).map_err(|_| CborError::LengthTooLarge)?;
114 let entry_min = MIN_ELEMENT_ENCODED_LEN
117 .checked_mul(2)
118 .ok_or(CborError::OffsetOverflow)?;
119 bounded_capacity_with_min(entry_count, bytes.len(), offset, entry_min)?;
120 let capacity = initial_container_capacity(entry_count);
121 let mut entries = Vec::with_capacity(capacity);
122 let mut off = offset;
123 let mut last_key_bytes: Option<Vec<u8>> = None;
124
125 for _ in 0..entry_count {
126 let (key_val, key_off) = decode_value(bytes, off, child_depth)?;
127 off = key_off;
128
129 let key = match key_val {
130 CborValue::String(s) => s,
131 _ => return Err(CborError::MapKeyMustBeString),
132 };
133
134 let key_bytes = key.as_bytes().to_vec();
135 if let Some(prev) = &last_key_bytes {
136 match compare_bytes(prev, &key_bytes) {
137 Ordering::Less => {}
138 Ordering::Equal => return Err(CborError::DuplicateMapKey),
139 Ordering::Greater => return Err(CborError::MapKeysOutOfOrder),
140 }
141 }
142 last_key_bytes = Some(key_bytes);
143
144 let (val, val_off) = decode_value(bytes, off, child_depth)?;
145 off = val_off;
146
147 entries.push((key, val));
148 }
149
150 Ok((CborValue::Map(entries), off))
151 }
152
153 7 => match arg {
154 20 => Ok((CborValue::Bool(false), offset)),
155 21 => Ok((CborValue::Bool(true), offset)),
156 22 => Ok((CborValue::Null, offset)),
157 _ => Err(CborError::DisallowedSimpleValue { value: arg }),
158 },
159
160 _ => Err(CborError::DisallowedMajorType { major }),
161 }
162}
163
164fn read_argument(bytes: &[u8], offset: usize, ai: u8) -> Result<(u64, usize), CborError> {
165 match ai {
166 n @ 0..=23 => Ok((u64::from(n), offset)),
167
168 24 => {
169 let end = checked_end(offset, 1)?;
170 if end > bytes.len() {
171 return Err(CborError::TruncatedArgument);
172 }
173 let value = u64::from(bytes[offset]);
174 if value < 24 {
175 return Err(CborError::NonCanonicalInteger);
176 }
177 Ok((value, end))
178 }
179
180 25 => {
181 let end = checked_end(offset, 2)?;
182 if end > bytes.len() {
183 return Err(CborError::TruncatedArgument);
184 }
185 let val = u16::from_be_bytes([bytes[offset], bytes[offset + 1]]);
186 if val < 256 {
187 return Err(CborError::NonCanonicalInteger);
188 }
189 Ok((u64::from(val), end))
190 }
191
192 26 => {
193 let end = checked_end(offset, 4)?;
194 if end > bytes.len() {
195 return Err(CborError::TruncatedArgument);
196 }
197 let val = u32::from_be_bytes([
198 bytes[offset],
199 bytes[offset + 1],
200 bytes[offset + 2],
201 bytes[offset + 3],
202 ]);
203 if val < 65536 {
204 return Err(CborError::NonCanonicalInteger);
205 }
206 Ok((u64::from(val), end))
207 }
208
209 27 => {
210 let end = checked_end(offset, 8)?;
211 if end > bytes.len() {
212 return Err(CborError::TruncatedArgument);
213 }
214 let val = u64::from_be_bytes([
215 bytes[offset],
216 bytes[offset + 1],
217 bytes[offset + 2],
218 bytes[offset + 3],
219 bytes[offset + 4],
220 bytes[offset + 5],
221 bytes[offset + 6],
222 bytes[offset + 7],
223 ]);
224 if val < 0x1_0000_0000 {
225 return Err(CborError::NonCanonicalInteger);
226 }
227 Ok((val, end))
228 }
229
230 _ => Err(CborError::UnsupportedAdditionalInfo),
231 }
232}
233
234fn extract_bytes(bytes: &[u8], offset: usize, len: u64) -> Result<(Vec<u8>, usize), CborError> {
235 let len = usize::try_from(len).map_err(|_| CborError::LengthTooLarge)?;
236 let end = checked_end(offset, len)?;
237 if end > bytes.len() {
238 return Err(CborError::TruncatedBytes);
239 }
240 Ok((bytes[offset..end].to_vec(), end))
241}
242
243fn extract_string(bytes: &[u8], offset: usize, len: u64) -> Result<(String, usize), CborError> {
244 let (raw, off) = extract_bytes(bytes, offset, len)?;
245 let s = str::from_utf8(&raw).map_err(|_| CborError::InvalidUtf8)?;
246 Ok((s.to_string(), off))
247}
248
249fn checked_end(offset: usize, len: usize) -> Result<usize, CborError> {
250 offset.checked_add(len).ok_or(CborError::OffsetOverflow)
251}
252
253fn descend(depth: usize) -> Result<usize, CborError> {
256 let next = depth.checked_add(1).ok_or(CborError::OffsetOverflow)?;
257 if next > MAX_NESTING_DEPTH {
258 return Err(CborError::DepthExceeded);
259 }
260 Ok(next)
261}
262
263fn bounded_capacity(count: usize, total_len: usize, offset: usize) -> Result<usize, CborError> {
266 bounded_capacity_with_min(count, total_len, offset, MIN_ELEMENT_ENCODED_LEN)
267}
268
269fn bounded_capacity_with_min(
275 count: usize,
276 total_len: usize,
277 offset: usize,
278 min_element_len: usize,
279) -> Result<usize, CborError> {
280 let remaining = total_len.saturating_sub(offset);
281 let max_possible = remaining / min_element_len.max(1);
282 if count > max_possible {
283 return Err(CborError::ContainerLengthExceedsInput);
284 }
285 Ok(count)
286}
287
288fn initial_container_capacity(count: usize) -> usize {
289 count.min(CONTAINER_INITIAL_RESERVE)
294}
295
296fn compare_bytes(a: &[u8], b: &[u8]) -> Ordering {
297 match a.len().cmp(&b.len()) {
298 Ordering::Equal => a.cmp(b),
299 ordering => ordering,
300 }
301}