Coverage Report

Created: 2026-11-12 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/OpenSK/libraries/cbor/src/writer.rs
Line
Count
Source
1
// Copyright 2019 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
//! Functionality for serializing CBOR values into bytes.
16
17
use super::values::{Constants, Value, ValueImpl};
18
use alloc::vec::Vec;
19
20
/// Possible errors from a serialization operation.
21
#[derive(Debug, PartialEq)]
22
pub enum EncoderError {
23
    TooMuchNesting,
24
    DuplicateMapKey,
25
}
26
27
/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.
28
/// Maximum level of nesting supported is 127; more deeply nested structures will fail with
29
/// [`EncoderError::TooMuchNesting`].
30
1.63k
pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> Result<(), EncoderError> {
31
1.63k
    write_nested(value, encoded_cbor, Some(i8::MAX))
32
1.63k
}
33
34
/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.  If
35
/// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning
36
/// [`DecoderError::TooMuchNesting`] if the limit is hit).
37
8.68k
pub fn write_nested(
38
8.68k
    value: Value,
39
8.68k
    encoded_cbor: &mut Vec<u8>,
40
8.68k
    max_nest: Option<i8>,
41
8.68k
) -> Result<(), EncoderError> {
42
8.68k
    let mut writer = Writer::new(encoded_cbor);
43
8.68k
    writer.encode_cbor(value, max_nest)
44
8.68k
}
45
46
struct Writer<'a> {
47
    encoded_cbor: &'a mut Vec<u8>,
48
}
49
50
impl<'a> Writer<'a> {
51
8.68k
    pub fn new(encoded_cbor: &mut Vec<u8>) -> Writer<'_> {
52
8.68k
        Writer { encoded_cbor }
53
8.68k
    }
54
55
6.54M
    fn encode_cbor(
56
6.54M
        &mut self,
57
6.54M
        value: Value,
58
6.54M
        remaining_depth: Option<i8>,
59
6.54M
    ) -> Result<(), EncoderError> {
60
6.54M
        if remaining_depth.is_some_and(|d| d < 0) {
61
0
            return Err(EncoderError::TooMuchNesting);
62
6.54M
        }
63
6.54M
        let type_label = value.0.type_label();
64
6.54M
        match value.0 {
65
1.22M
            ValueImpl::Unsigned(unsigned) => self.start_item(type_label, unsigned),
66
1.90M
            ValueImpl::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
67
931k
            ValueImpl::ByteString(byte_string) => {
68
931k
                self.start_item(type_label, byte_string.len() as u64);
69
931k
                self.encoded_cbor.extend(byte_string);
70
931k
            }
71
56.8k
            ValueImpl::TextString(text_string) => {
72
56.8k
                self.start_item(type_label, text_string.len() as u64);
73
56.8k
                self.encoded_cbor.extend(text_string.into_bytes());
74
56.8k
            }
75
592k
            ValueImpl::Array(array) => {
76
592k
                self.start_item(type_label, array.len() as u64);
77
4.48M
                for el in array {
78
3.88M
                    self.encode_cbor(el, remaining_depth.map(|d| d - 1))?;
79
                }
80
            }
81
328k
            ValueImpl::Map(map) => {
82
328k
                self.start_item(type_label, map.len() as u64);
83
910k
                for (k, v) in map {
84
582k
                    self.encode_cbor(k, remaining_depth.map(|d| d - 1))?;
85
582k
                    self.encode_cbor(v, remaining_depth.map(|d| d - 1))?;
86
                }
87
            }
88
1.48M
            ValueImpl::Tag(tag, inner_value) => {
89
1.48M
                self.start_item(type_label, tag);
90
1.48M
                self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?;
91
            }
92
27.0k
            ValueImpl::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
93
        }
94
6.54M
        Ok(())
95
6.54M
    }
96
97
6.54M
    fn start_item(&mut self, type_label: u8, size: u64) {
98
6.54M
        let (mut first_byte, shift) = match size {
99
6.54M
            0..=23 => (size as u8, 0),
100
1.27M
            24..=0xFF => (Constants::ADDITIONAL_INFORMATION_1_BYTE, 1),
101
431k
            0x100..=0xFFFF => (Constants::ADDITIONAL_INFORMATION_2_BYTES, 2),
102
230k
            0x10000..=0xFFFF_FFFF => (Constants::ADDITIONAL_INFORMATION_4_BYTES, 4),
103
31.2k
            _ => (Constants::ADDITIONAL_INFORMATION_8_BYTES, 8),
104
        };
105
6.54M
        first_byte |= type_label << Constants::MAJOR_TYPE_BIT_SHIFT;
106
6.54M
        self.encoded_cbor.push(first_byte);
107
108
6.54M
        for i in (0..shift).rev() {
109
2.29M
            self.encoded_cbor.push((size >> (i * 8)) as u8);
110
2.29M
        }
111
6.54M
    }
112
}
113
114
#[cfg(test)]
115
mod test {
116
    use super::*;
117
    use crate::{
118
        cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null,
119
        cbor_tagged, cbor_text, cbor_true, cbor_undefined,
120
    };
121
    use alloc::vec;
122
123
    fn write_return(value: Value) -> Option<Vec<u8>> {
124
        let mut encoded_cbor = Vec::new();
125
        if write(value, &mut encoded_cbor).is_ok() {
126
            Some(encoded_cbor)
127
        } else {
128
            None
129
        }
130
    }
131
132
    #[test]
133
    fn test_write_unsigned() {
134
        let cases = vec![
135
            (0, vec![0x00]),
136
            (1, vec![0x01]),
137
            (10, vec![0x0A]),
138
            (23, vec![0x17]),
139
            (24, vec![0x18, 0x18]),
140
            (25, vec![0x18, 0x19]),
141
            (100, vec![0x18, 0x64]),
142
            (1000, vec![0x19, 0x03, 0xE8]),
143
            (1000000, vec![0x1A, 0x00, 0x0F, 0x42, 0x40]),
144
            (0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]),
145
            (
146
                0x100000000,
147
                vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
148
            ),
149
            (
150
                i64::MAX,
151
                vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
152
            ),
153
        ];
154
        for (unsigned, correct_cbor) in cases {
155
            assert_eq!(write_return(cbor_int!(unsigned)), Some(correct_cbor));
156
        }
157
    }
158
159
    #[test]
160
    fn test_write_negative() {
161
        let cases = vec![
162
            (-1, vec![0x20]),
163
            (-10, vec![0x29]),
164
            (-23, vec![0x36]),
165
            (-24, vec![0x37]),
166
            (-25, vec![0x38, 0x18]),
167
            (-100, vec![0x38, 0x63]),
168
            (-1000, vec![0x39, 0x03, 0xE7]),
169
            (-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]),
170
            (
171
                -4294967297,
172
                vec![0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
173
            ),
174
            (
175
                i64::MIN,
176
                vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
177
            ),
178
        ];
179
        for (negative, correct_cbor) in cases {
180
            assert_eq!(write_return(cbor_int!(negative)), Some(correct_cbor));
181
        }
182
    }
183
184
    #[test]
185
    fn test_write_byte_string() {
186
        let cases = vec![
187
            (vec![], vec![0x40]),
188
            (
189
                vec![0x01, 0x02, 0x03, 0x04],
190
                vec![0x44, 0x01, 0x02, 0x03, 0x04],
191
            ),
192
        ];
193
        for (byte_string, correct_cbor) in cases {
194
            assert_eq!(write_return(cbor_bytes!(byte_string)), Some(correct_cbor));
195
        }
196
    }
197
198
    #[test]
199
    fn test_write_text_string() {
200
        let unicode_3byte = vec![0xE6, 0xB0, 0xB4];
201
        let cases = vec![
202
            ("", vec![0x60]),
203
            ("a", vec![0x61, 0x61]),
204
            ("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]),
205
            ("\"\\", vec![0x62, 0x22, 0x5C]),
206
            ("ü", vec![0x62, 0xC3, 0xBC]),
207
            (
208
                core::str::from_utf8(&unicode_3byte).unwrap(),
209
                vec![0x63, 0xE6, 0xB0, 0xB4],
210
            ),
211
            ("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]),
212
        ];
213
        for (text_string, correct_cbor) in cases {
214
            assert_eq!(write_return(cbor_text!(text_string)), Some(correct_cbor));
215
        }
216
    }
217
218
    #[test]
219
    fn test_write_array() {
220
        let value_vec: Vec<_> = (1..26).collect();
221
        let expected_cbor = vec![
222
            0x98, 0x19, // array of 25 elements
223
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
224
            0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19,
225
        ];
226
        assert_eq!(
227
            write_return(cbor_array_vec!(value_vec)),
228
            Some(expected_cbor)
229
        );
230
    }
231
232
    #[test]
233
    fn test_write_map() {
234
        let value_map = cbor_map! {
235
            0 => "a",
236
            23 => "b",
237
            24 => "c",
238
            u8::MAX as i64 => "d",
239
            256 => "e",
240
            u16::MAX as i64 => "f",
241
            65536 => "g",
242
            u32::MAX as i64 => "h",
243
            4294967296_i64 => "i",
244
            i64::MAX => "j",
245
            -1 => "k",
246
            -24 => "l",
247
            -25 => "m",
248
            -256 => "n",
249
            -257 => "o",
250
            -65537 => "p",
251
            -4294967296_i64 => "q",
252
            -4294967297_i64 => "r",
253
            i64::MIN => "s",
254
            b"a" => 2,
255
            b"bar" => 3,
256
            b"foo" => 4,
257
            "" => ".",
258
            "e" => "E",
259
            "aa" => "AA",
260
        };
261
        let expected_cbor = vec![
262
            0xb8, 0x19, // map of 25 pairs:
263
            0x00, // key 0
264
            0x61, 0x61, // value "a"
265
            0x17, // key 23
266
            0x61, 0x62, // value "b"
267
            0x18, 0x18, // key 24
268
            0x61, 0x63, // value "c"
269
            0x18, 0xFF, // key 255
270
            0x61, 0x64, // value "d"
271
            0x19, 0x01, 0x00, // key 256
272
            0x61, 0x65, // value "e"
273
            0x19, 0xFF, 0xFF, // key 65535
274
            0x61, 0x66, // value "f"
275
            0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536
276
            0x61, 0x67, // value "g"
277
            0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295
278
            0x61, 0x68, // value "h"
279
            // key 4294967296
280
            0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x69, //  value "i"
281
            // key INT64_MAX
282
            0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x6a, //  value "j"
283
            0x20, // key -1
284
            0x61, 0x6b, // value "k"
285
            0x37, // key -24
286
            0x61, 0x6c, // value "l"
287
            0x38, 0x18, // key -25
288
            0x61, 0x6d, // value "m"
289
            0x38, 0xFF, // key -256
290
            0x61, 0x6e, // value "n"
291
            0x39, 0x01, 0x00, // key -257
292
            0x61, 0x6f, // value "o"
293
            0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537
294
            0x61, 0x70, // value "p"
295
            0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296
296
            0x61, 0x71, // value "q"
297
            // key -4294967297
298
            0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x72, //  value "r"
299
            // key INT64_MIN
300
            0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x73, //  value "s"
301
            0x41, b'a', // byte string "a"
302
            0x02, 0x43, b'b', b'a', b'r', // byte string "bar"
303
            0x03, 0x43, b'f', b'o', b'o', // byte string "foo"
304
            0x04, 0x60, // key ""
305
            0x61, 0x2e, // value "."
306
            0x61, 0x65, // key "e"
307
            0x61, 0x45, // value "E"
308
            0x62, 0x61, 0x61, // key "aa"
309
            0x62, 0x41, 0x41, // value "AA"
310
        ];
311
        assert_eq!(write_return(value_map), Some(expected_cbor));
312
    }
313
314
    #[test]
315
    fn test_write_map_sorted() {
316
        let sorted_map = cbor_map! {
317
            0 => "a",
318
            1 => "b",
319
            -1 => "c",
320
            -2 => "d",
321
            b"a" => "e",
322
            b"b" => "f",
323
            "" => "g",
324
            "c" => "h",
325
        };
326
        let unsorted_map = cbor_map! {
327
            1 => "b",
328
            -2 => "d",
329
            b"b" => "f",
330
            "c" => "h",
331
            "" => "g",
332
            b"a" => "e",
333
            -1 => "c",
334
            0 => "a",
335
        };
336
        assert_eq!(write_return(sorted_map), write_return(unsorted_map));
337
    }
338
339
    #[test]
340
    fn test_write_map_with_array() {
341
        let value_map = cbor_map! {
342
            "a" => 1,
343
            "b" => cbor_array![2, 3],
344
        };
345
        let expected_cbor = vec![
346
            0xa2, // map of 2 pairs
347
            0x61, 0x61, // "a"
348
            0x01, 0x61, 0x62, // "b"
349
            0x82, // array with 2 elements
350
            0x02, 0x03,
351
        ];
352
        assert_eq!(write_return(value_map), Some(expected_cbor));
353
    }
354
355
    #[test]
356
    fn test_write_nested_map() {
357
        let value_map = cbor_map! {
358
            "a" => 1,
359
            "b" => cbor_map! {
360
                "c" => 2,
361
                "d" => 3,
362
            },
363
        };
364
        let expected_cbor = vec![
365
            0xa2, // map of 2 pairs
366
            0x61, 0x61, // "a"
367
            0x01, 0x61, 0x62, // "b"
368
            0xa2, // map of 2 pairs
369
            0x61, 0x63, // "c"
370
            0x02, 0x61, 0x64, // "d"
371
            0x03,
372
        ];
373
        assert_eq!(write_return(value_map), Some(expected_cbor));
374
    }
375
376
    #[test]
377
    fn test_write_tagged() {
378
        let cases = vec![
379
            (cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
380
            (cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
381
            (
382
                cbor_tagged!(
383
                    1000,
384
                    cbor_map! {
385
                        "a" => 1,
386
                        "b" => cbor_array![2, 3],
387
                    }
388
                ),
389
                vec![
390
                    0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
391
                    0x61, 0x61, // "a"
392
                    0x01, 0x61, 0x62, // "b"
393
                    0x82, // array with 2 elements
394
                    0x02, 0x03,
395
                ],
396
            ),
397
        ];
398
        for (value, correct_cbor) in cases {
399
            assert_eq!(write_return(value), Some(correct_cbor));
400
        }
401
    }
402
403
    #[test]
404
    fn test_write_tagged_nesting_limit() {
405
        let mut encoded = Vec::new();
406
        assert_eq!(
407
            write_nested(cbor_tagged!(0, cbor_int!(0)), &mut encoded, Some(0)),
408
            Err(EncoderError::TooMuchNesting)
409
        );
410
        let mut encoded = Vec::new();
411
        assert_eq!(
412
            write_nested(cbor_tagged!(0, cbor_int!(0)), &mut encoded, Some(1)),
413
            Ok(())
414
        );
415
        assert_eq!(encoded, vec![0xc0, 0x00]);
416
    }
417
418
    #[test]
419
    fn test_write_simple() {
420
        let cases = vec![
421
            (cbor_false!(), vec![0xF4]),
422
            (cbor_true!(), vec![0xF5]),
423
            (cbor_null!(), vec![0xF6]),
424
            (cbor_undefined!(), vec![0xF7]),
425
        ];
426
        for (value, correct_cbor) in cases {
427
            assert_eq!(write_return(value), Some(correct_cbor));
428
        }
429
    }
430
431
    #[test]
432
    fn test_write_single_levels() {
433
        let simple_array: Value = cbor_array![2];
434
        let simple_map: Value = cbor_map! {"b" => 3};
435
        let positive_cases = vec![
436
            (cbor_int!(1), 0),
437
            (cbor_bytes!(vec![0x01, 0x02, 0x03, 0x04]), 0),
438
            (cbor_text!("a"), 0),
439
            (cbor_array![], 0),
440
            (cbor_map! {}, 0),
441
            (simple_array.clone(), 1),
442
            (simple_map.clone(), 1),
443
        ];
444
        let negative_cases = vec![(simple_array.clone(), 0), (simple_map.clone(), 0)];
445
        for (value, level) in positive_cases {
446
            let mut buf = Vec::new();
447
            let mut writer = Writer::new(&mut buf);
448
            assert!(writer.encode_cbor(value, Some(level)).is_ok());
449
        }
450
        for (value, level) in negative_cases {
451
            let mut buf = Vec::new();
452
            let mut writer = Writer::new(&mut buf);
453
            assert!(!writer.encode_cbor(value, Some(level)).is_ok());
454
        }
455
    }
456
457
    #[test]
458
    fn test_write_nested_map_levels() {
459
        let cbor_map: Value = cbor_map! {
460
            "a" => 1,
461
            "b" => cbor_map! {
462
                "c" => 2,
463
                "d" => 3,
464
            },
465
        };
466
467
        let mut buf = Vec::new();
468
        let mut writer = Writer::new(&mut buf);
469
        assert!(writer.encode_cbor(cbor_map.clone(), Some(2)).is_ok());
470
        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
471
        writer = Writer::new(&mut buf);
472
        assert!(writer.encode_cbor(cbor_map, Some(1)).is_err());
473
    }
474
475
    #[test]
476
    fn test_write_unbalanced_nested_containers() {
477
        let cbor_array: Value = cbor_array![
478
            1,
479
            2,
480
            3,
481
            cbor_map! {
482
                "a" => 1,
483
                "b" => cbor_map! {
484
                    "c" => 2,
485
                    "d" => 3,
486
                },
487
            },
488
        ];
489
490
        let mut buf = Vec::new();
491
        let mut writer = Writer::new(&mut buf);
492
        assert!(writer.encode_cbor(cbor_array.clone(), Some(3)).is_ok());
493
        writer = Writer::new(&mut buf);
494
        assert!(writer.encode_cbor(cbor_array, Some(2)).is_err());
495
    }
496
497
    #[test]
498
    fn test_write_overly_nested() {
499
        let cbor_map: Value = cbor_map! {
500
            "a" => 1,
501
            "b" => cbor_map! {
502
                "c" => 2,
503
                "d" => 3,
504
                "h" => cbor_map! {
505
                    "e" => 4,
506
                    "f" => 5,
507
                    "g" => cbor_array![
508
                        6,
509
                        7,
510
                        cbor_array![
511
                            8
512
                        ]
513
                    ],
514
                },
515
            },
516
        };
517
518
        let mut buf = Vec::new();
519
        let mut writer = Writer::new(&mut buf);
520
        assert!(writer.encode_cbor(cbor_map.clone(), Some(5)).is_ok());
521
        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
522
        writer = Writer::new(&mut buf);
523
        assert!(writer.encode_cbor(cbor_map, Some(4)).is_err());
524
    }
525
526
    #[test]
527
    fn test_write_default_nesting_boundary() {
528
        let mut encoded = Vec::new();
529
        let mut value = cbor_int!(0);
530
        for _ in 0..127 {
531
            value = cbor_array![value];
532
        }
533
        assert_eq!(write(value.clone(), &mut encoded), Ok(()));
534
        let mut bytes = vec![0x81; 127]; // 127 nested one-element arrays
535
        bytes.push(0x00); // 0
536
        assert_eq!(encoded, bytes);
537
        assert_eq!(
538
            write(cbor_array![value], &mut encoded),
539
            Err(EncoderError::TooMuchNesting)
540
        );
541
    }
542
543
    #[test]
544
    fn test_write_nested_unlimited() {
545
        let mut value = cbor_int!(0);
546
        for _ in 0..128 {
547
            value = cbor_array![value];
548
        }
549
        let mut bytes = vec![0x81; 128]; // 128 nested one-element arrays
550
        bytes.push(0x00); // 0
551
        let mut encoded = Vec::new();
552
        assert_eq!(write_nested(value, &mut encoded, None), Ok(()));
553
        assert_eq!(encoded, bytes);
554
    }
555
}