1 // SPDX-License-Identifier: Apache-2.0
2 
3 //! Low level CBOR parsing tools
4 //!
5 //! This crate contains low-level types for encoding and decoding items in
6 //! CBOR. This crate is usable in both `no_std` and `no_alloc` environments.
7 //! To understand how this crate works, first we will look at the structure
8 //! of a CBOR item on the wire.
9 //!
10 //! # Anatomy of a CBOR Item
11 //!
12 //! This is a brief anatomy of a CBOR item on the wire.
13 //!
14 //! ```text
15 //! +------------+-----------+
16 //! |            |           |
17 //! |   Major    |   Minor   |
18 //! |  (3bits)   |  (5bits)  |
19 //! |            |           |
20 //! +------------+-----------+
21 //! ^                        ^
22 //! |                        |
23 //! +-----+            +-----+
24 //!       |            |
25 //!       |            |
26 //!       +----------------------------+--------------+
27 //!       |            |               |              |
28 //!       |   Prefix   |     Affix     |    Suffix    |
29 //!       |  (1 byte)  |  (0-8 bytes)  |  (0+ bytes)  |
30 //!       |            |               |              |
31 //!       +------------+---------------+--------------+
32 //!
33 //!       |                            |              |
34 //!       +------------+---------------+--------------+
35 //!                    |                       |
36 //!                    v                       v
37 //!
38 //!                  Header                   Body
39 //! ```
40 //!
41 //! The `ciborium` crate works by providing the `Decoder` and `Encoder` types
42 //! which provide input and output for a CBOR header (see: `Header`). From
43 //! there, you can either handle the body yourself or use the provided utility
44 //! functions.
45 //!
46 //! For more information on the CBOR format, see
47 //! [RFC 7049](https://tools.ietf.org/html/rfc7049).
48 //!
49 //! # Decoding
50 //!
51 //! In order to decode CBOR, you will create a `Decoder` from a reader. The
52 //! decoder instance will allow you to `Decoder::pull()` `Header` instances
53 //! from the input.
54 //!
55 //! Most CBOR items are fully contained in their headers and therefore have no
56 //! body. These items can be evaluated directly from the `Header` instance.
57 //!
58 //! Bytes and text items have a body but do not contain child items. Since
59 //! both bytes and text values may be segmented, parsing them can be a bit
60 //! tricky. Therefore, we provide helper functions to parse these types. See
61 //! `Decoder::bytes()` and `Decoder::text()` for more details.
62 //!
63 //! Array and map items have a body which contains child items. These can be
64 //! parsed by simply doing `Decoder::pull()` to parse the child items.
65 //!
66 //! ## Example
67 //!
68 //! ```rust
69 //! use ciborium_ll::{Decoder, Header};
70 //! use ciborium_io::Read as _;
71 //!
72 //! let input = b"\x6dHello, World!";
73 //! let mut decoder = Decoder::from(&input[..]);
74 //! let mut chunks = 0;
75 //!
76 //! match decoder.pull().unwrap() {
77 //!     Header::Text(len) => {
78 //!         let mut segments = decoder.text(len);
79 //!         while let Some(mut segment) = segments.pull().unwrap() {
80 //!             let mut buffer = [0u8; 7];
81 //!             while let Some(chunk) = segment.pull(&mut buffer[..]).unwrap() {
82 //!                  match chunk {
83 //!                      "Hello, " if chunks == 0 => chunks = 1,
84 //!                      "World!" if chunks == 1 => chunks = 2,
85 //!                      _ => panic!("received unexpected chunk"),
86 //!                  }
87 //!             }
88 //!         }
89 //!     }
90 //!
91 //!     _ => panic!("received unexpected value"),
92 //! }
93 //!
94 //! assert_eq!(chunks, 2);
95 //! ```
96 //!
97 //! # Encoding
98 //!
99 //! To encode values to CBOR, create an `Encoder` from a writer. The encoder
100 //! instance provides the `Encoder::push()` method to write a `Header` value
101 //! to the wire. CBOR item bodies can be written directly.
102 //!
103 //! For bytes and text, there are the `Encoder::bytes()` and `Encoder::text()`
104 //! utility functions, respectively, which will properly segment the output
105 //! on the wire for you.
106 //!
107 //! ## Example
108 //!
109 //! ```rust
110 //! use ciborium_ll::{Encoder, Header};
111 //! use ciborium_io::Write as _;
112 //!
113 //! let mut buffer = [0u8; 19];
114 //! let mut encoder = Encoder::from(&mut buffer[..]);
115 //!
116 //! // Write the structure
117 //! encoder.push(Header::Map(Some(1))).unwrap();
118 //! encoder.push(Header::Positive(7)).unwrap();
119 //! encoder.text("Hello, World!", 7).unwrap();
120 //!
121 //! // Validate our output
122 //! encoder.flush().unwrap();
123 //! assert_eq!(b"\xa1\x07\x7f\x67Hello, \x66World!\xff", &buffer[..]);
124 //! ```
125 
126 #![cfg_attr(not(feature = "std"), no_std)]
127 #![deny(missing_docs)]
128 #![deny(clippy::all)]
129 #![deny(clippy::cargo)]
130 
131 #[cfg(feature = "alloc")]
132 extern crate alloc;
133 
134 mod dec;
135 mod enc;
136 mod hdr;
137 mod seg;
138 
139 pub use dec::*;
140 pub use enc::*;
141 pub use hdr::*;
142 pub use seg::{Segment, Segments};
143 
144 /// Simple value constants
145 pub mod simple {
146     #![allow(missing_docs)]
147 
148     pub const FALSE: u8 = 20;
149     pub const TRUE: u8 = 21;
150     pub const NULL: u8 = 22;
151     pub const UNDEFINED: u8 = 23;
152 }
153 
154 /// Tag constants
155 pub mod tag {
156     #![allow(missing_docs)]
157 
158     pub const BIGPOS: u64 = 2;
159     pub const BIGNEG: u64 = 3;
160 }
161 
162 #[derive(Debug)]
163 struct InvalidError(());
164 
165 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
166 enum Major {
167     Positive,
168     Negative,
169     Bytes,
170     Text,
171     Array,
172     Map,
173     Tag,
174     Other,
175 }
176 
177 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
178 enum Minor {
179     This(u8),
180     Next1([u8; 1]),
181     Next2([u8; 2]),
182     Next4([u8; 4]),
183     Next8([u8; 8]),
184     More,
185 }
186 
187 impl AsRef<[u8]> for Minor {
188     #[inline]
as_ref(&self) -> &[u8]189     fn as_ref(&self) -> &[u8] {
190         match self {
191             Self::More => &[],
192             Self::This(..) => &[],
193             Self::Next1(x) => x.as_ref(),
194             Self::Next2(x) => x.as_ref(),
195             Self::Next4(x) => x.as_ref(),
196             Self::Next8(x) => x.as_ref(),
197         }
198     }
199 }
200 
201 impl AsMut<[u8]> for Minor {
202     #[inline]
as_mut(&mut self) -> &mut [u8]203     fn as_mut(&mut self) -> &mut [u8] {
204         match self {
205             Self::More => &mut [],
206             Self::This(..) => &mut [],
207             Self::Next1(x) => x.as_mut(),
208             Self::Next2(x) => x.as_mut(),
209             Self::Next4(x) => x.as_mut(),
210             Self::Next8(x) => x.as_mut(),
211         }
212     }
213 }
214 
215 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
216 struct Title(pub Major, pub Minor);
217 
218 #[cfg(test)]
219 mod tests {
220     use super::*;
221 
222     macro_rules! neg {
223         ($i:expr) => {
224             Header::Negative((($i as i128) ^ !0) as u64)
225         };
226     }
227 
228     #[allow(clippy::excessive_precision)]
229     #[test]
leaf()230     fn leaf() {
231         use core::f64::{INFINITY, NAN};
232 
233         let data = &[
234             (Header::Positive(0), "00", true),
235             (Header::Positive(1), "01", true),
236             (Header::Positive(10), "0a", true),
237             (Header::Positive(23), "17", true),
238             (Header::Positive(24), "1818", true),
239             (Header::Positive(25), "1819", true),
240             (Header::Positive(100), "1864", true),
241             (Header::Positive(1000), "1903e8", true),
242             (Header::Positive(1000000), "1a000f4240", true),
243             (Header::Positive(1000000000000), "1b000000e8d4a51000", true),
244             (
245                 Header::Positive(18446744073709551615),
246                 "1bffffffffffffffff",
247                 true,
248             ),
249             (neg!(-18446744073709551616), "3bffffffffffffffff", true),
250             (neg!(-1), "20", true),
251             (neg!(-10), "29", true),
252             (neg!(-100), "3863", true),
253             (neg!(-1000), "3903e7", true),
254             (Header::Float(0.0), "f90000", true),
255             (Header::Float(-0.0), "f98000", true),
256             (Header::Float(1.0), "f93c00", true),
257             (Header::Float(1.1), "fb3ff199999999999a", true),
258             (Header::Float(1.5), "f93e00", true),
259             (Header::Float(65504.0), "f97bff", true),
260             (Header::Float(100000.0), "fa47c35000", true),
261             (Header::Float(3.4028234663852886e+38), "fa7f7fffff", true),
262             (Header::Float(1.0e+300), "fb7e37e43c8800759c", true),
263             (Header::Float(5.960464477539063e-8), "f90001", true),
264             (Header::Float(0.00006103515625), "f90400", true),
265             (Header::Float(-4.0), "f9c400", true),
266             (Header::Float(-4.1), "fbc010666666666666", true),
267             (Header::Float(INFINITY), "f97c00", true),
268             (Header::Float(NAN), "f97e00", true),
269             (Header::Float(-INFINITY), "f9fc00", true),
270             (Header::Float(INFINITY), "fa7f800000", false),
271             (Header::Float(NAN), "fa7fc00000", false),
272             (Header::Float(-INFINITY), "faff800000", false),
273             (Header::Float(INFINITY), "fb7ff0000000000000", false),
274             (Header::Float(NAN), "fb7ff8000000000000", false),
275             (Header::Float(-INFINITY), "fbfff0000000000000", false),
276             (Header::Simple(simple::FALSE), "f4", true),
277             (Header::Simple(simple::TRUE), "f5", true),
278             (Header::Simple(simple::NULL), "f6", true),
279             (Header::Simple(simple::UNDEFINED), "f7", true),
280             (Header::Simple(16), "f0", true),
281             (Header::Simple(24), "f818", true),
282             (Header::Simple(255), "f8ff", true),
283             (Header::Tag(0), "c0", true),
284             (Header::Tag(1), "c1", true),
285             (Header::Tag(23), "d7", true),
286             (Header::Tag(24), "d818", true),
287             (Header::Tag(32), "d820", true),
288             (Header::Bytes(Some(0)), "40", true),
289             (Header::Bytes(Some(4)), "44", true),
290             (Header::Text(Some(0)), "60", true),
291             (Header::Text(Some(4)), "64", true),
292         ];
293 
294         for (header, bytes, encode) in data.iter().cloned() {
295             let bytes = hex::decode(bytes).unwrap();
296 
297             let mut decoder = Decoder::from(&bytes[..]);
298             match (header, decoder.pull().unwrap()) {
299                 // NaN equality...
300                 (Header::Float(l), Header::Float(r)) if l.is_nan() && r.is_nan() => (),
301 
302                 // Everything else...
303                 (l, r) => assert_eq!(l, r),
304             }
305 
306             if encode {
307                 let mut buffer = [0u8; 1024];
308                 let mut writer = &mut buffer[..];
309                 let mut encoder = Encoder::from(&mut writer);
310                 encoder.push(header).unwrap();
311 
312                 let len = writer.len();
313                 assert_eq!(&bytes[..], &buffer[..1024 - len]);
314             }
315         }
316     }
317 
318     #[test]
node()319     fn node() {
320         let data: &[(&str, &[Header])] = &[
321             ("80", &[Header::Array(Some(0))]),
322             (
323                 "83010203",
324                 &[
325                     Header::Array(Some(3)),
326                     Header::Positive(1),
327                     Header::Positive(2),
328                     Header::Positive(3),
329                 ],
330             ),
331             (
332                 "98190102030405060708090a0b0c0d0e0f101112131415161718181819",
333                 &[
334                     Header::Array(Some(25)),
335                     Header::Positive(1),
336                     Header::Positive(2),
337                     Header::Positive(3),
338                     Header::Positive(4),
339                     Header::Positive(5),
340                     Header::Positive(6),
341                     Header::Positive(7),
342                     Header::Positive(8),
343                     Header::Positive(9),
344                     Header::Positive(10),
345                     Header::Positive(11),
346                     Header::Positive(12),
347                     Header::Positive(13),
348                     Header::Positive(14),
349                     Header::Positive(15),
350                     Header::Positive(16),
351                     Header::Positive(17),
352                     Header::Positive(18),
353                     Header::Positive(19),
354                     Header::Positive(20),
355                     Header::Positive(21),
356                     Header::Positive(22),
357                     Header::Positive(23),
358                     Header::Positive(24),
359                     Header::Positive(25),
360                 ],
361             ),
362             ("a0", &[Header::Map(Some(0))]),
363             (
364                 "a201020304",
365                 &[
366                     Header::Map(Some(2)),
367                     Header::Positive(1),
368                     Header::Positive(2),
369                     Header::Positive(3),
370                     Header::Positive(4),
371                 ],
372             ),
373             ("9fff", &[Header::Array(None), Header::Break]),
374             (
375                 "9f018202039f0405ffff",
376                 &[
377                     Header::Array(None),
378                     Header::Positive(1),
379                     Header::Array(Some(2)),
380                     Header::Positive(2),
381                     Header::Positive(3),
382                     Header::Array(None),
383                     Header::Positive(4),
384                     Header::Positive(5),
385                     Header::Break,
386                     Header::Break,
387                 ],
388             ),
389             (
390                 "9f01820203820405ff",
391                 &[
392                     Header::Array(None),
393                     Header::Positive(1),
394                     Header::Array(Some(2)),
395                     Header::Positive(2),
396                     Header::Positive(3),
397                     Header::Array(Some(2)),
398                     Header::Positive(4),
399                     Header::Positive(5),
400                     Header::Break,
401                 ],
402             ),
403             (
404                 "83018202039f0405ff",
405                 &[
406                     Header::Array(Some(3)),
407                     Header::Positive(1),
408                     Header::Array(Some(2)),
409                     Header::Positive(2),
410                     Header::Positive(3),
411                     Header::Array(None),
412                     Header::Positive(4),
413                     Header::Positive(5),
414                     Header::Break,
415                 ],
416             ),
417             (
418                 "83019f0203ff820405",
419                 &[
420                     Header::Array(Some(3)),
421                     Header::Positive(1),
422                     Header::Array(None),
423                     Header::Positive(2),
424                     Header::Positive(3),
425                     Header::Break,
426                     Header::Array(Some(2)),
427                     Header::Positive(4),
428                     Header::Positive(5),
429                 ],
430             ),
431             (
432                 "9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff",
433                 &[
434                     Header::Array(None),
435                     Header::Positive(1),
436                     Header::Positive(2),
437                     Header::Positive(3),
438                     Header::Positive(4),
439                     Header::Positive(5),
440                     Header::Positive(6),
441                     Header::Positive(7),
442                     Header::Positive(8),
443                     Header::Positive(9),
444                     Header::Positive(10),
445                     Header::Positive(11),
446                     Header::Positive(12),
447                     Header::Positive(13),
448                     Header::Positive(14),
449                     Header::Positive(15),
450                     Header::Positive(16),
451                     Header::Positive(17),
452                     Header::Positive(18),
453                     Header::Positive(19),
454                     Header::Positive(20),
455                     Header::Positive(21),
456                     Header::Positive(22),
457                     Header::Positive(23),
458                     Header::Positive(24),
459                     Header::Positive(25),
460                     Header::Break,
461                 ],
462             ),
463         ];
464 
465         for (bytes, headers) in data {
466             let bytes = hex::decode(bytes).unwrap();
467 
468             // Test decoding
469             let mut decoder = Decoder::from(&bytes[..]);
470             for header in headers.iter().cloned() {
471                 assert_eq!(header, decoder.pull().unwrap());
472             }
473 
474             // Test encoding
475             let mut buffer = [0u8; 1024];
476             let mut writer = &mut buffer[..];
477             let mut encoder = Encoder::from(&mut writer);
478 
479             for header in headers.iter().cloned() {
480                 encoder.push(header).unwrap();
481             }
482 
483             let len = writer.len();
484             assert_eq!(&bytes[..], &buffer[..1024 - len]);
485         }
486     }
487 }
488