1#![cfg(feature = "std")]
2#![cfg(feature = "cbor")]
3#![cfg(not(feature = "lsp"))]
4
5use super::*;
6use crate::{
7 ast::*,
8 token,
9 visitor::{self, *},
10};
11
12use core::convert::TryInto;
13use std::{
14 borrow::Cow,
15 collections::HashMap,
16 convert::TryFrom,
17 fmt::{self, Write},
18};
19
20use chrono::{TimeZone, Utc};
21use ciborium::value::Value;
22use serde_json;
23
24#[cfg(feature = "additional-controls")]
25use crate::validator::control::{
26 abnf_from_complex_controller, cat_operation, plus_operation, validate_abnf,
27};
28
29pub type Result<T> = std::result::Result<(), Error<T>>;
31
32#[derive(Debug)]
34pub enum Error<T: std::fmt::Debug> {
35 Validation(Vec<ValidationError>),
37 CBORParsing(ciborium::de::Error<T>),
39 JSONParsing(serde_json::Error),
41 CDDLParsing(String),
43 UTF8Parsing(std::str::Utf8Error),
45 Base16Decoding(base16::DecodeError),
47 Base64Decoding(data_encoding::DecodeError),
49}
50
51impl<T: std::fmt::Debug> fmt::Display for Error<T> {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 match self {
54 Error::Validation(errors) => {
55 let mut error_str = String::new();
56 for e in errors.iter() {
57 let _ = writeln!(error_str, "{}", e);
58 }
59 write!(f, "{}", error_str)
60 }
61 Error::CBORParsing(error) => write!(f, "error parsing cbor: {}", error),
62 Error::JSONParsing(error) => write!(f, "error parsing json string: {}", error),
63 Error::CDDLParsing(error) => write!(f, "error parsing CDDL: {}", error),
64 Error::UTF8Parsing(error) => write!(f, "error parsing utf8: {}", error),
65 Error::Base16Decoding(error) => write!(f, "error decoding base16: {}", error),
66 Error::Base64Decoding(error) => write!(f, "error decoding base64: {}", error),
67 }
68 }
69}
70
71impl<T: std::fmt::Debug + 'static> std::error::Error for Error<T> {
72 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
73 match self {
74 Error::CBORParsing(error) => Some(error),
75 _ => None,
76 }
77 }
78}
79
80#[derive(Clone, Debug)]
82pub struct ValidationError {
83 pub reason: String,
85 pub cddl_location: String,
87 pub cbor_location: String,
89 pub is_multi_type_choice: bool,
91 pub is_multi_group_choice: bool,
93 pub is_group_to_choice_enum: bool,
95 pub type_group_name_entry: Option<String>,
97}
98
99impl fmt::Display for ValidationError {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 let mut error_str = String::from("error validating");
102 if self.is_multi_group_choice {
103 error_str.push_str(" group choice");
104 }
105 if self.is_multi_type_choice {
106 error_str.push_str(" type choice");
107 }
108 if self.is_group_to_choice_enum {
109 error_str.push_str(" type choice in group to choice enumeration");
110 }
111 if let Some(entry) = &self.type_group_name_entry {
112 let _ = write!(error_str, " group entry associated with rule \"{}\"", entry);
113 }
114
115 write!(
116 f,
117 "{} at cbor location {}: {}",
118 error_str, self.cbor_location, self.reason
119 )
120 }
121}
122
123impl std::error::Error for ValidationError {
124 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
125 None
126 }
127}
128
129impl<T: std::fmt::Debug> Error<T> {
130 fn from_validator(cv: &CBORValidator, reason: String) -> Self {
131 Error::Validation(vec![ValidationError {
132 cddl_location: cv.cddl_location.clone(),
133 cbor_location: cv.cbor_location.clone(),
134 reason,
135 is_multi_type_choice: cv.is_multi_type_choice,
136 is_group_to_choice_enum: cv.is_group_to_choice_enum,
137 type_group_name_entry: cv.type_group_name_entry.map(|e| e.to_string()),
138 is_multi_group_choice: cv.is_multi_group_choice,
139 }])
140 }
141}
142
143#[derive(Clone)]
145pub struct CBORValidator<'a> {
146 cddl: &'a CDDL<'a>,
147 cbor: Value,
148 errors: Vec<ValidationError>,
149 cddl_location: String,
150 cbor_location: String,
151 occurrence: Option<Occur>,
153 group_entry_idx: Option<usize>,
155 object_value: Option<Value>,
157 is_member_key: bool,
159 is_cut_present: bool,
161 cut_value: Option<Type1<'a>>,
163 eval_generic_rule: Option<&'a str>,
166 generic_rules: Vec<GenericRule<'a>>,
168 ctrl: Option<token::ControlOperator>,
170 is_group_to_choice_enum: bool,
173 is_multi_type_choice: bool,
175 is_multi_group_choice: bool,
177 type_group_name_entry: Option<&'a str>,
180 advance_to_next_entry: bool,
183 is_ctrl_map_equality: bool,
185 entry_counts: Option<Vec<EntryCount>>,
186 validated_keys: Option<Vec<Value>>,
188 values_to_validate: Option<Vec<Value>>,
190 validating_value: bool,
192 valid_array_items: Option<Vec<usize>>,
194 array_errors: Option<HashMap<usize, Vec<ValidationError>>>,
197 is_colon_shortcut_present: bool,
198 is_root: bool,
199 is_multi_type_choice_type_rule_validating_array: bool,
200 visited_rules: std::collections::HashSet<String>,
202 #[cfg(not(target_arch = "wasm32"))]
203 #[cfg(feature = "additional-controls")]
204 enabled_features: Option<&'a [&'a str]>,
205 #[cfg(target_arch = "wasm32")]
206 #[cfg(feature = "additional-controls")]
207 enabled_features: Option<Box<[JsValue]>>,
208 #[cfg(feature = "additional-controls")]
209 has_feature_errors: bool,
210 #[cfg(feature = "additional-controls")]
211 disabled_features: Option<Vec<String>>,
212 range_upper: Option<usize>,
213}
214
215#[derive(Clone, Debug)]
216struct GenericRule<'a> {
217 name: &'a str,
218 params: Vec<&'a str>,
219 args: Vec<Type1<'a>>,
220}
221
222impl<'a> CBORValidator<'a> {
223 #[cfg(not(target_arch = "wasm32"))]
224 #[cfg(feature = "additional-controls")]
225 pub fn new(cddl: &'a CDDL<'a>, cbor: Value, enabled_features: Option<&'a [&'a str]>) -> Self {
227 CBORValidator {
228 cddl,
229 cbor,
230 errors: Vec::default(),
231 cddl_location: String::new(),
232 cbor_location: String::new(),
233 occurrence: None,
234 group_entry_idx: None,
235 object_value: None,
236 is_member_key: false,
237 is_cut_present: false,
238 cut_value: None,
239 eval_generic_rule: None,
240 generic_rules: Vec::new(),
241 ctrl: None,
242 is_group_to_choice_enum: false,
243 is_multi_type_choice: false,
244 is_multi_group_choice: false,
245 type_group_name_entry: None,
246 advance_to_next_entry: false,
247 is_ctrl_map_equality: false,
248 entry_counts: None,
249 validated_keys: None,
250 values_to_validate: None,
251 validating_value: false,
252 valid_array_items: None,
253 array_errors: None,
254 is_colon_shortcut_present: false,
255 is_root: false,
256 is_multi_type_choice_type_rule_validating_array: false,
257 visited_rules: std::collections::HashSet::new(),
258 enabled_features,
259 has_feature_errors: false,
260 disabled_features: None,
261 range_upper: None,
262 }
263 }
264
265 #[cfg(not(target_arch = "wasm32"))]
266 #[cfg(not(feature = "additional-controls"))]
267 pub fn new(cddl: &'a CDDL<'a>, cbor: Value) -> Self {
269 CBORValidator {
270 cddl,
271 cbor,
272 errors: Vec::default(),
273 cddl_location: String::new(),
274 cbor_location: String::new(),
275 occurrence: None,
276 group_entry_idx: None,
277 object_value: None,
278 is_member_key: false,
279 is_cut_present: false,
280 cut_value: None,
281 eval_generic_rule: None,
282 generic_rules: Vec::new(),
283 ctrl: None,
284 is_group_to_choice_enum: false,
285 is_multi_type_choice: false,
286 is_multi_group_choice: false,
287 type_group_name_entry: None,
288 advance_to_next_entry: false,
289 is_ctrl_map_equality: false,
290 entry_counts: None,
291 validated_keys: None,
292 values_to_validate: None,
293 validating_value: false,
294 valid_array_items: None,
295 array_errors: None,
296 is_colon_shortcut_present: false,
297 is_root: false,
298 is_multi_type_choice_type_rule_validating_array: false,
299 visited_rules: std::collections::HashSet::new(),
300 range_upper: None,
301 }
302 }
303
304 #[cfg(target_arch = "wasm32")]
305 #[cfg(feature = "additional-controls")]
306 pub fn new(cddl: &'a CDDL<'a>, cbor: Value, enabled_features: Option<Box<[JsValue]>>) -> Self {
308 CBORValidator {
309 cddl,
310 cbor,
311 errors: Vec::default(),
312 cddl_location: String::new(),
313 cbor_location: String::new(),
314 occurrence: None,
315 group_entry_idx: None,
316 object_value: None,
317 is_member_key: false,
318 is_cut_present: false,
319 cut_value: None,
320 eval_generic_rule: None,
321 generic_rules: Vec::new(),
322 ctrl: None,
323 is_group_to_choice_enum: false,
324 is_multi_type_choice: false,
325 is_multi_group_choice: false,
326 type_group_name_entry: None,
327 advance_to_next_entry: false,
328 is_ctrl_map_equality: false,
329 entry_counts: None,
330 validated_keys: None,
331 values_to_validate: None,
332 validating_value: false,
333 valid_array_items: None,
334 array_errors: None,
335 is_colon_shortcut_present: false,
336 is_root: false,
337 is_multi_type_choice_type_rule_validating_array: false,
338 visited_rules: std::collections::HashSet::new(),
339 enabled_features,
340 has_feature_errors: false,
341 disabled_features: None,
342 range_upper: None,
343 }
344 }
345
346 #[cfg(target_arch = "wasm32")]
347 #[cfg(not(feature = "additional-controls"))]
348 pub fn new(cddl: &'a CDDL<'a>, cbor: Value) -> Self {
350 CBORValidator {
351 cddl,
352 cbor,
353 errors: Vec::default(),
354 cddl_location: String::new(),
355 cbor_location: String::new(),
356 occurrence: None,
357 group_entry_idx: None,
358 object_value: None,
359 is_member_key: false,
360 is_cut_present: false,
361 cut_value: None,
362 eval_generic_rule: None,
363 generic_rules: Vec::new(),
364 ctrl: None,
365 is_group_to_choice_enum: false,
366 is_multi_type_choice: false,
367 is_multi_group_choice: false,
368 type_group_name_entry: None,
369 advance_to_next_entry: false,
370 is_ctrl_map_equality: false,
371 entry_counts: None,
372 validated_keys: None,
373 values_to_validate: None,
374 validating_value: false,
375 valid_array_items: None,
376 array_errors: None,
377 is_colon_shortcut_present: false,
378 is_root: false,
379 is_multi_type_choice_type_rule_validating_array: false,
380 visited_rules: std::collections::HashSet::new(),
381 range_upper: None,
382 }
383 }
384
385 pub fn extract_cbor(self) -> Value {
387 self.cbor
388 }
389
390 fn new_with_recursion_state(&self, cbor: Value) -> CBORValidator<'a> {
392 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
393 let mut cv = CBORValidator::new(self.cddl, cbor, self.enabled_features.clone());
394 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
395 let mut cv = CBORValidator::new(self.cddl, cbor, self.enabled_features);
396 #[cfg(not(feature = "additional-controls"))]
397 let mut cv = CBORValidator::new(self.cddl, cbor);
398
399 cv.generic_rules = self.generic_rules.clone();
400 cv.eval_generic_rule = self.eval_generic_rule;
401 cv.visited_rules = self.visited_rules.clone();
402 cv
403 }
404
405 fn validate_array_items<T: std::fmt::Debug + 'static>(
406 &mut self,
407 token: &ArrayItemToken,
408 ) -> visitor::Result<Error<T>>
409 where
410 cbor::Error<T>: From<cbor::Error<std::io::Error>>,
411 {
412 if let Value::Array(a) = &self.cbor {
413 if self.is_member_key {
415 return Ok(());
416 }
417
418 match validate_array_occurrence(
419 self.occurrence.as_ref(),
420 self.entry_counts.as_ref().map(|ec| &ec[..]),
421 a,
422 ) {
423 Ok((iter_items, allow_empty_array)) => {
424 if iter_items {
425 for (idx, v) in a.iter().enumerate() {
426 if let Some(indices) = &self.valid_array_items {
427 if self.is_multi_type_choice && indices.contains(&idx) {
428 continue;
429 }
430 }
431
432 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
433 let mut cv = self.new_with_recursion_state(v.clone());
434 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
435 let mut cv = self.new_with_recursion_state(v.clone());
436 #[cfg(not(feature = "additional-controls"))]
437 let mut cv = self.new_with_recursion_state(v.clone());
438
439 cv.generic_rules = self.generic_rules.clone();
440 cv.eval_generic_rule = self.eval_generic_rule;
441 cv.ctrl = self.ctrl;
442 cv.is_multi_type_choice = self.is_multi_type_choice;
443 let _ = write!(cv.cbor_location, "{}/{}", self.cbor_location, idx);
444
445 match token {
446 ArrayItemToken::Value(value) => cv.visit_value(value)?,
447 ArrayItemToken::Range(lower, upper, is_inclusive) => {
448 cv.visit_range(lower, upper, *is_inclusive)?
449 }
450 ArrayItemToken::Group(group) if v.is_array() => {
452 cv.visit_group(group)?;
454 }
455 ArrayItemToken::Group(group) => cv.visit_group(group)?,
456 ArrayItemToken::Identifier(ident) => cv.visit_identifier(ident)?,
457 ArrayItemToken::TaggedData(tagged_data) => cv.visit_type2(tagged_data)?,
458 }
459
460 if self.is_multi_type_choice && cv.errors.is_empty() {
461 if let Some(indices) = &mut self.valid_array_items {
462 indices.push(idx);
463 } else {
464 self.valid_array_items = Some(vec![idx]);
465 }
466 continue;
467 }
468
469 if let Some(errors) = &mut self.array_errors {
470 if let Some(error) = errors.get_mut(&idx) {
471 error.append(&mut cv.errors);
472 } else {
473 errors.insert(idx, cv.errors);
474 }
475 } else {
476 let mut errors = HashMap::new();
477 errors.insert(idx, cv.errors);
478 self.array_errors = Some(errors)
479 }
480 }
481 } else {
482 let idx = if !self.is_multi_type_choice {
483 self.group_entry_idx.take()
484 } else {
485 self.group_entry_idx
486 };
487
488 if let Some(idx) = idx {
489 if let Some(v) = a.get(idx) {
490 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
491 let mut cv = self.new_with_recursion_state(v.clone());
492 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
493 let mut cv = self.new_with_recursion_state(v.clone());
494 #[cfg(not(feature = "additional-controls"))]
495 let mut cv = self.new_with_recursion_state(v.clone());
496
497 cv.ctrl = self.ctrl;
498 cv.is_multi_type_choice = self.is_multi_type_choice;
499 let _ = write!(cv.cbor_location, "{}/{}", self.cbor_location, idx);
500
501 match token {
502 ArrayItemToken::Value(value) => cv.visit_value(value)?,
503 ArrayItemToken::Range(lower, upper, is_inclusive) => {
504 cv.visit_range(lower, upper, *is_inclusive)?
505 }
506 ArrayItemToken::Group(group) if v.is_array() => {
508 cv.visit_group(group)?;
510 }
511 ArrayItemToken::Group(group) => cv.visit_group(group)?,
512 ArrayItemToken::Identifier(ident) => cv.visit_identifier(ident)?,
513 ArrayItemToken::TaggedData(tagged_data) => cv.visit_type2(tagged_data)?,
514 }
515
516 self.errors.append(&mut cv.errors);
517 } else if !allow_empty_array {
518 self.add_error(token.error_msg(Some(idx)));
519 }
520 } else if !self.is_multi_type_choice {
521 self.add_error(format!("{}, got {:?}", token.error_msg(None), self.cbor));
522 }
523 }
524 }
525 Err(errors) => {
526 for e in errors.into_iter() {
527 self.add_error(e);
528 }
529 }
530 }
531 }
532
533 Ok(())
534 }
535}
536
537impl<'a, T: std::fmt::Debug + 'static> Validator<'a, '_, cbor::Error<T>> for CBORValidator<'a>
538where
539 cbor::Error<T>: From<cbor::Error<std::io::Error>>,
540{
541 fn validate(&mut self) -> std::result::Result<(), cbor::Error<T>> {
542 for r in self.cddl.rules.iter() {
543 if let Rule::Type { rule, .. } = r {
545 if rule.generic_params.is_none() {
546 self.is_root = true;
547 self.visit_type_rule(rule)?;
548 self.is_root = false;
549 break;
550 }
551 }
552 }
553
554 if !self.errors.is_empty() {
555 return Err(Error::Validation(self.errors.clone()));
556 }
557
558 Ok(())
559 }
560
561 fn add_error(&mut self, reason: String) {
562 self.errors.push(ValidationError {
563 reason,
564 cddl_location: self.cddl_location.clone(),
565 cbor_location: self.cbor_location.clone(),
566 is_multi_type_choice: self.is_multi_type_choice,
567 is_multi_group_choice: self.is_multi_group_choice,
568 is_group_to_choice_enum: self.is_group_to_choice_enum,
569 type_group_name_entry: self.type_group_name_entry.map(|e| e.to_string()),
570 });
571 }
572}
573
574impl<'a, T: std::fmt::Debug + 'static> Visitor<'a, '_, Error<T>> for CBORValidator<'a>
575where
576 cbor::Error<T>: From<cbor::Error<std::io::Error>>,
577{
578 fn visit_type_rule(&mut self, tr: &TypeRule<'a>) -> visitor::Result<Error<T>> {
579 if let Some(gp) = &tr.generic_params {
580 if let Some(gr) = self
581 .generic_rules
582 .iter_mut()
583 .find(|r| r.name == tr.name.ident)
584 {
585 gr.params = gp.params.iter().map(|p| p.param.ident).collect();
586 } else {
587 self.generic_rules.push(GenericRule {
588 name: tr.name.ident,
589 params: gp.params.iter().map(|p| p.param.ident).collect(),
590 args: Vec::new(),
591 });
592 }
593 }
594
595 let type_choice_alternates = type_choice_alternates_from_ident(self.cddl, &tr.name);
596 if !type_choice_alternates.is_empty() {
597 self.is_multi_type_choice = true;
598
599 if self.cbor.is_array() {
600 self.is_multi_type_choice_type_rule_validating_array = true;
601 }
602 }
603
604 let error_count = self.errors.len();
605
606 for t in type_choice_alternates {
607 let cur_errors = self.errors.len();
608 self.visit_type(t)?;
609 if self.errors.len() == cur_errors {
610 for _ in 0..self.errors.len() - error_count {
611 self.errors.pop();
612 }
613
614 return Ok(());
615 }
616 }
617
618 if tr.value.type_choices.len() > 1 && self.cbor.is_array() {
619 self.is_multi_type_choice_type_rule_validating_array = true;
620 }
621
622 self.visit_type(&tr.value)
623 }
624
625 fn visit_group_rule(&mut self, gr: &GroupRule<'a>) -> visitor::Result<Error<T>> {
626 if let Some(gp) = &gr.generic_params {
627 if let Some(gr) = self
628 .generic_rules
629 .iter_mut()
630 .find(|r| r.name == gr.name.ident)
631 {
632 gr.params = gp.params.iter().map(|p| p.param.ident).collect();
633 } else {
634 self.generic_rules.push(GenericRule {
635 name: gr.name.ident,
636 params: gp.params.iter().map(|p| p.param.ident).collect(),
637 args: Vec::new(),
638 });
639 }
640 }
641
642 let group_choice_alternates = group_choice_alternates_from_ident(self.cddl, &gr.name);
643 if !group_choice_alternates.is_empty() {
644 self.is_multi_group_choice = true;
645 }
646
647 let error_count = self.errors.len();
648 for ge in group_choice_alternates {
649 let cur_errors = self.errors.len();
650 self.visit_group_entry(ge)?;
651 if self.errors.len() == cur_errors {
652 for _ in 0..self.errors.len() - error_count {
653 self.errors.pop();
654 }
655
656 return Ok(());
657 }
658 }
659
660 self.visit_group_entry(&gr.entry)
661 }
662
663 fn visit_type(&mut self, t: &Type<'a>) -> visitor::Result<Error<T>> {
664 if let Value::Array(outer_array) = &self.cbor {
666 if let Some(idx) = self.group_entry_idx {
667 if let Some(item) = outer_array.get(idx) {
669 if item.is_array() {
670 for tc in t.type_choices.iter() {
672 if let Type2::Array { .. } = &tc.type1.type2 {
673 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
674 let mut cv =
675 CBORValidator::new(self.cddl, item.clone(), self.enabled_features.clone());
676 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
677 let mut cv = CBORValidator::new(self.cddl, item.clone(), self.enabled_features);
678 #[cfg(not(feature = "additional-controls"))]
679 let mut cv = CBORValidator::new(self.cddl, item.clone());
680
681 cv.generic_rules = self.generic_rules.clone();
682 cv.eval_generic_rule = self.eval_generic_rule;
683 cv.is_multi_type_choice = self.is_multi_type_choice;
684
685 let _ = write!(cv.cbor_location, "{}/{}", self.cbor_location, idx);
686
687 cv.visit_type_choice(tc)?;
689
690 self.errors.append(&mut cv.errors);
691 return Ok(());
692 }
693 }
694 }
695 }
696 }
697 }
698
699 if t.type_choices.len() > 1 {
701 self.is_multi_type_choice = true;
702 }
703
704 let initial_error_count = self.errors.len();
705 let mut choice_validation_succeeded = false;
706
707 for type_choice in t.type_choices.iter() {
708 if matches!(self.cbor, Value::Array(_))
709 && !self.is_multi_type_choice_type_rule_validating_array
710 {
711 let error_count = self.errors.len();
712
713 self.visit_type_choice(type_choice)?;
714
715 #[cfg(feature = "additional-controls")]
716 if self.errors.len() == error_count
717 && !self.has_feature_errors
718 && self.disabled_features.is_none()
719 {
720 let type_choice_error_count = self.errors.len() - initial_error_count;
723 if type_choice_error_count > 0 {
724 for _ in 0..type_choice_error_count {
725 self.errors.pop();
726 }
727 }
728 choice_validation_succeeded = true;
729 }
730
731 #[cfg(not(feature = "additional-controls"))]
732 if self.errors.len() == error_count {
733 let type_choice_error_count = self.errors.len() - initial_error_count;
736 if type_choice_error_count > 0 {
737 for _ in 0..type_choice_error_count {
738 self.errors.pop();
739 }
740 }
741 choice_validation_succeeded = true;
742 }
743
744 continue;
745 }
746
747 let mut choice_validator = self.clone();
749 choice_validator.errors.clear();
750
751 choice_validator.visit_type_choice(type_choice)?;
752
753 if choice_validator.errors.is_empty() {
755 #[cfg(feature = "additional-controls")]
756 if !choice_validator.has_feature_errors || choice_validator.disabled_features.is_some() {
757 let type_choice_error_count = self.errors.len() - initial_error_count;
759 if type_choice_error_count > 0 {
760 for _ in 0..type_choice_error_count {
761 self.errors.pop();
762 }
763 }
764 return Ok(());
765 }
766
767 #[cfg(not(feature = "additional-controls"))]
768 {
769 let type_choice_error_count = self.errors.len() - initial_error_count;
771 if type_choice_error_count > 0 {
772 for _ in 0..type_choice_error_count {
773 self.errors.pop();
774 }
775 }
776 return Ok(());
777 }
778 } else {
779 self.errors.extend(choice_validator.errors);
781 }
782 }
783
784 if choice_validation_succeeded {
787 return Ok(());
788 }
789 Ok(())
790 }
791
792 fn visit_group(&mut self, g: &Group<'a>) -> visitor::Result<Error<T>> {
793 if g.group_choices.len() > 1 {
794 self.is_multi_group_choice = true;
795 }
796
797 if self.is_ctrl_map_equality {
799 if let Some(t) = &self.ctrl {
800 if let Value::Map(m) = &self.cbor {
801 let entry_counts = entry_counts_from_group(self.cddl, g);
802 let len = m.len();
803 if let ControlOperator::EQ | ControlOperator::NE = t {
804 if !validate_entry_count(&entry_counts, len) {
805 for ec in entry_counts.iter() {
806 if let Some(occur) = &ec.entry_occurrence {
807 self.add_error(format!(
808 "expected array with length per occurrence {}",
809 occur,
810 ));
811 } else {
812 self.add_error(format!(
813 "expected array with length {}, got {}",
814 ec.count, len
815 ));
816 }
817 }
818 return Ok(());
819 }
820 }
821 }
822 }
823 }
824
825 self.is_ctrl_map_equality = false;
826
827 let initial_error_count = self.errors.len();
828 for group_choice in g.group_choices.iter() {
829 let error_count = self.errors.len();
830 self.visit_group_choice(group_choice)?;
831 if self.errors.len() == error_count {
832 let group_choice_error_count = self.errors.len() - initial_error_count;
835 if group_choice_error_count > 0 {
836 for _ in 0..group_choice_error_count {
837 self.errors.pop();
838 }
839 }
840
841 return Ok(());
842 }
843 }
844
845 Ok(())
846 }
847
848 fn visit_group_choice(&mut self, gc: &GroupChoice<'a>) -> visitor::Result<Error<T>> {
849 if self.is_group_to_choice_enum {
850 let initial_error_count = self.errors.len();
851 for tc in type_choices_from_group_choice(self.cddl, gc).iter() {
852 let error_count = self.errors.len();
853 self.visit_type_choice(tc)?;
854 if self.errors.len() == error_count {
855 let type_choice_error_count = self.errors.len() - initial_error_count;
856 if type_choice_error_count > 0 {
857 for _ in 0..type_choice_error_count {
858 self.errors.pop();
859 }
860 }
861 return Ok(());
862 }
863 }
864
865 return Ok(());
866 }
867
868 for (idx, ge) in gc.group_entries.iter().enumerate() {
869 self.group_entry_idx = Some(idx);
870
871 self.visit_group_entry(&ge.0)?;
872 }
873
874 Ok(())
875 }
876
877 fn visit_range(
878 &mut self,
879 lower: &Type2,
880 upper: &Type2,
881 is_inclusive: bool,
882 ) -> visitor::Result<Error<T>> {
883 if let Value::Array(_) = &self.cbor {
884 return self.validate_array_items(&ArrayItemToken::Range(lower, upper, is_inclusive));
885 }
886
887 match (lower, upper) {
888 (Type2::UintValue { value: l, .. }, Type2::UintValue { value: u, .. }) => {
889 match &self.cbor {
890 Value::Bytes(b) => {
891 let len = b.len();
892 if is_inclusive {
893 if len < *l || len > *u {
894 self.add_error(format!(
895 "expected uint to be in range {} <= value <= {}, got Bytes({:?})",
896 l, u, b
897 ));
898 }
899 } else if len < *l || len >= *u {
900 self.add_error(format!(
901 "expected uint to be in range {} <= value < {}, got Bytes({:?})",
902 l, u, b
903 ));
904 }
905 }
906 Value::Text(s) => match self.ctrl {
907 Some(ControlOperator::SIZE) => {
908 let len = s.len();
909 let s = s.clone();
910 if is_inclusive {
911 if s.len() < *l || s.len() > *u {
912 self.add_error(format!(
913 "expected \"{}\" string length to be in the range {} <= value <= {}, got {}",
914 s, l, u, len
915 ));
916 }
917
918 return Ok(());
919 } else if s.len() < *l || s.len() >= *u {
920 self.add_error(format!(
921 "expected \"{}\" string length to be in the range {} <= value < {}, got {}",
922 s, l, u, len
923 ));
924 return Ok(());
925 }
926 }
927 _ => {
928 self.add_error("string value cannot be validated against a range without the .size control operator".to_string());
929 return Ok(());
930 }
931 },
932 Value::Integer(i) => {
933 if is_inclusive {
934 if i128::from(*i) < *l as i128 || i128::from(*i) > *u as i128 {
935 self.add_error(format!(
936 "expected integer to be in range {} <= value <= {}, got {:?}",
937 l, u, i
938 ));
939 }
940 } else if i128::from(*i) < *l as i128 || i128::from(*i) >= *u as i128 {
941 self.add_error(format!(
942 "expected integer to be in range {} <= value < {}, got {:?}",
943 l, u, i
944 ));
945 }
946 }
947 _ => {
948 self.add_error(format!(
949 "expected value to be in range {} {} value {} {}, got {:?}",
950 l,
951 if is_inclusive { "<=" } else { "<" },
952 if is_inclusive { "<=" } else { "<" },
953 u,
954 self.cbor
955 ));
956 }
957 }
958 }
959 _ => {
960 self.add_error(format!(
961 "invalid cddl range. upper and lower values must be uint types. got {} and {}",
962 lower, upper
963 ));
964 }
965 }
966
967 Ok(())
968 }
969
970 fn visit_control_operator(
971 &mut self,
972 target: &Type2<'a>,
973 ctrl: ControlOperator,
974 controller: &Type2<'a>,
975 ) -> visitor::Result<Error<T>> {
976 if let Type2::Typename {
977 ident: target_ident,
978 ..
979 } = target
980 {
981 if let Type2::Typename {
982 ident: controller_ident,
983 ..
984 } = controller
985 {
986 if let Some(name) = self.eval_generic_rule {
987 if let Some(gr) = self
988 .generic_rules
989 .iter()
990 .find(|&gr| gr.name == name)
991 .cloned()
992 {
993 for (idx, gp) in gr.params.iter().enumerate() {
994 if let Some(arg) = gr.args.get(idx) {
995 if *gp == target_ident.ident {
996 let t2 = Type2::from(arg.clone());
997
998 if *gp == controller_ident.ident {
999 return self.visit_control_operator(&t2, ctrl, &t2);
1000 }
1001
1002 return self.visit_control_operator(&arg.type2, ctrl, controller);
1003 }
1004 }
1005 }
1006 }
1007 }
1008 }
1009
1010 if let Some(name) = self.eval_generic_rule {
1011 if let Some(gr) = self
1012 .generic_rules
1013 .iter()
1014 .find(|&gr| gr.name == name)
1015 .cloned()
1016 {
1017 for (idx, gp) in gr.params.iter().enumerate() {
1018 if let Some(arg) = gr.args.get(idx) {
1019 if *gp == target_ident.ident {
1020 let t2 = Type2::from(arg.clone());
1021 return self.visit_control_operator(&t2, ctrl, controller);
1022 }
1023 }
1024 }
1025 }
1026 }
1027 }
1028
1029 match ctrl {
1030 ControlOperator::EQ => {
1031 match target {
1032 Type2::Typename { ident, .. } => {
1033 if is_ident_string_data_type(self.cddl, ident)
1034 || is_ident_numeric_data_type(self.cddl, ident)
1035 {
1036 return self.visit_type2(controller);
1037 }
1038 }
1039 Type2::Array { group, .. } => {
1040 if let Value::Array(_) = &self.cbor {
1041 self.entry_counts = Some(entry_counts_from_group(self.cddl, group));
1042 self.visit_type2(controller)?;
1043 self.entry_counts = None;
1044 return Ok(());
1045 }
1046 }
1047 Type2::Map { .. } => {
1048 if let Value::Map(_) = &self.cbor {
1049 self.ctrl = Some(ctrl);
1050 self.is_ctrl_map_equality = true;
1051 self.visit_type2(controller)?;
1052 self.ctrl = None;
1053 self.is_ctrl_map_equality = false;
1054 return Ok(());
1055 }
1056 }
1057 _ => self.add_error(format!(
1058 "target for .eq operator must be a string, numerical, array or map data type, got {}",
1059 target
1060 )),
1061 }
1062 Ok(())
1063 }
1064 ControlOperator::NE => {
1065 match target {
1066 Type2::Typename { ident, .. } => {
1067 if is_ident_string_data_type(self.cddl, ident)
1068 || is_ident_numeric_data_type(self.cddl, ident)
1069 {
1070 self.ctrl = Some(ctrl);
1071 self.visit_type2(controller)?;
1072 self.ctrl = None;
1073 return Ok(());
1074 }
1075 }
1076 Type2::Array { .. } => {
1077 if let Value::Array(_) = &self.cbor {
1078 self.ctrl = Some(ctrl);
1079 self.visit_type2(controller)?;
1080 self.ctrl = None;
1081 return Ok(());
1082 }
1083 }
1084 Type2::Map { .. } => {
1085 if let Value::Map(_) = &self.cbor {
1086 self.ctrl = Some(ctrl);
1087 self.is_ctrl_map_equality = true;
1088 self.visit_type2(controller)?;
1089 self.ctrl = None;
1090 self.is_ctrl_map_equality = false;
1091 return Ok(());
1092 }
1093 }
1094 _ => self.add_error(format!(
1095 "target for .ne operator must be a string, numerical, array or map data type, got {}",
1096 target
1097 )),
1098 }
1099 Ok(())
1100 }
1101 ControlOperator::LT | ControlOperator::GT | ControlOperator::GE | ControlOperator::LE => {
1102 match target {
1103 Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => {
1104 self.ctrl = Some(ctrl);
1105 self.visit_type2(controller)?;
1106 self.ctrl = None;
1107 Ok(())
1108 }
1109 _ => {
1110 self.add_error(format!(
1111 "target for .lt, .gt, .ge or .le operator must be a numerical data type, got {}",
1112 target
1113 ));
1114 Ok(())
1115 }
1116 }
1117 }
1118 ControlOperator::SIZE => match target {
1119 Type2::Typename { ident, .. }
1120 if is_ident_string_data_type(self.cddl, ident)
1121 || is_ident_uint_data_type(self.cddl, ident)
1122 || is_ident_byte_string_data_type(self.cddl, ident) =>
1123 {
1124 self.ctrl = Some(ctrl);
1125 self.visit_type2(controller)?;
1126 self.ctrl = None;
1127 Ok(())
1128 }
1129 _ => {
1130 self.add_error(format!(
1131 "target for .size must a string or uint data type, got {}",
1132 target
1133 ));
1134 Ok(())
1135 }
1136 },
1137 ControlOperator::AND => {
1138 self.ctrl = Some(ctrl);
1139 self.visit_type2(target)?;
1140 self.visit_type2(controller)?;
1141 self.ctrl = None;
1142 Ok(())
1143 }
1144 ControlOperator::WITHIN => {
1145 self.ctrl = Some(ctrl);
1146 let error_count = self.errors.len();
1147 self.visit_type2(target)?;
1148 let no_errors = self.errors.len() == error_count;
1149 self.visit_type2(controller)?;
1150 if no_errors && self.errors.len() > error_count {
1151 for _ in 0..self.errors.len() - error_count {
1152 self.errors.pop();
1153 }
1154
1155 self.add_error(format!(
1156 "expected type {} .within type {}, got {:?}",
1157 target, controller, self.cbor,
1158 ));
1159 }
1160
1161 self.ctrl = None;
1162
1163 Ok(())
1164 }
1165 ControlOperator::DEFAULT => {
1166 self.ctrl = Some(ctrl);
1167 let error_count = self.errors.len();
1168 self.visit_type2(target)?;
1169 if self.errors.len() != error_count {
1170 #[cfg(feature = "ast-span")]
1171 if let Some(Occur::Optional { .. }) = self.occurrence.take() {
1172 self.add_error(format!(
1173 "expected default value {}, got {:?}",
1174 controller, self.cbor
1175 ));
1176 }
1177 #[cfg(not(feature = "ast-span"))]
1178 if let Some(Occur::Optional {}) = self.occurrence.take() {
1179 self.add_error(format!(
1180 "expected default value {}, got {:?}",
1181 controller, self.cbor
1182 ));
1183 }
1184 }
1185 self.ctrl = None;
1186 Ok(())
1187 }
1188 ControlOperator::REGEXP | ControlOperator::PCRE => {
1189 self.ctrl = Some(ctrl);
1190 match target {
1191 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1192 match self.cbor {
1193 Value::Text(_) | Value::Array(_) => self.visit_type2(controller)?,
1194 _ => self.add_error(format!(
1195 ".regexp/.pcre control can only be matched against CBOR string, got {:?}",
1196 self.cbor
1197 )),
1198 }
1199 }
1200 _ => self.add_error(format!(
1201 ".regexp/.pcre control can only be matched against string data type, got {}",
1202 target
1203 )),
1204 }
1205 self.ctrl = None;
1206
1207 Ok(())
1208 }
1209 ControlOperator::CBOR | ControlOperator::CBORSEQ => {
1210 self.ctrl = Some(ctrl);
1211 match target {
1212 Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => {
1213 match &self.cbor {
1214 Value::Bytes(b) => {
1215 let inner_value = ciborium::de::from_reader(&b[..]);
1217 match inner_value {
1218 Ok(value) => {
1219 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
1220 let mut cv =
1221 CBORValidator::new(self.cddl, value, self.enabled_features.clone());
1222 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
1223 let mut cv = CBORValidator::new(self.cddl, value, self.enabled_features);
1224 #[cfg(not(feature = "additional-controls"))]
1225 let mut cv = CBORValidator::new(self.cddl, value);
1226
1227 cv.generic_rules = self.generic_rules.clone();
1228 cv.eval_generic_rule = self.eval_generic_rule;
1229 cv.cbor_location.push_str(&self.cbor_location);
1230
1231 cv.visit_type2(controller)?;
1232
1233 if !cv.errors.is_empty() {
1234 self.errors.append(&mut cv.errors);
1235 }
1236 }
1237 Err(e) => {
1238 self.add_error(format!("error decoding embedded CBOR: {}", e));
1239 }
1240 }
1241 }
1242 Value::Array(arr) => {
1243 for (idx, item) in arr.iter().enumerate() {
1245 if let Value::Bytes(b) = item {
1246 let inner_value = ciborium::de::from_reader(&b[..]);
1247 match inner_value {
1248 Ok(value) => {
1249 let current_location = self.cbor_location.clone();
1250 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
1251 let mut cv =
1252 CBORValidator::new(self.cddl, value, self.enabled_features.clone());
1253 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
1254 let mut cv = CBORValidator::new(self.cddl, value, self.enabled_features);
1255 #[cfg(not(feature = "additional-controls"))]
1256 let mut cv = CBORValidator::new(self.cddl, value);
1257
1258 cv.generic_rules = self.generic_rules.clone();
1259 cv.eval_generic_rule = self.eval_generic_rule;
1260 let _ = write!(cv.cbor_location, "{}/{}", self.cbor_location, idx);
1261
1262 cv.visit_type2(controller)?;
1263
1264 if !cv.errors.is_empty() {
1265 self.errors.append(&mut cv.errors);
1266 }
1267 self.cbor_location = current_location;
1268 }
1269 Err(e) => {
1270 let error_msg =
1271 format!("error decoding embedded CBOR at index {}: {}", idx, e);
1272 self.errors.push(ValidationError {
1273 reason: error_msg,
1274 cddl_location: self.cddl_location.clone(),
1275 cbor_location: self.cbor_location.clone(),
1276 is_multi_type_choice: self.is_multi_type_choice,
1277 is_multi_group_choice: self.is_multi_group_choice,
1278 is_group_to_choice_enum: self.is_group_to_choice_enum,
1279 type_group_name_entry: self.type_group_name_entry.map(|e| e.to_string()),
1280 });
1281 }
1282 }
1283 } else {
1284 let error_msg = format!(
1285 "array item at index {} must be a byte string for .cbor control, got {:?}",
1286 idx, item
1287 );
1288 self.errors.push(ValidationError {
1289 reason: error_msg,
1290 cddl_location: self.cddl_location.clone(),
1291 cbor_location: self.cbor_location.clone(),
1292 is_multi_type_choice: self.is_multi_type_choice,
1293 is_multi_group_choice: self.is_multi_group_choice,
1294 is_group_to_choice_enum: self.is_group_to_choice_enum,
1295 type_group_name_entry: self.type_group_name_entry.map(|e| e.to_string()),
1296 });
1297 }
1298 }
1299 }
1300 _ => {
1301 self.add_error(format!(
1302 ".cbor control can only be matched against a CBOR byte string or array of byte strings, got {:?}",
1303 self.cbor
1304 ));
1305 }
1306 }
1307 }
1308 _ => self.add_error(format!(
1309 ".cbor control can only be matched against a byte string data type, got {}",
1310 target
1311 )),
1312 }
1313 self.ctrl = None;
1314
1315 Ok(())
1316 }
1317 ControlOperator::BITS => {
1318 self.ctrl = Some(ctrl);
1319 match target {
1320 Type2::Typename { ident, .. }
1321 if is_ident_byte_string_data_type(self.cddl, ident)
1322 || is_ident_uint_data_type(self.cddl, ident) =>
1323 {
1324 match &self.cbor {
1325 Value::Bytes(_) | Value::Array(_) => self.visit_type2(controller)?,
1326 Value::Integer(i) if i128::from(*i) >= 0i128 => self.visit_type2(controller)?,
1327 _ => self.add_error(format!(
1328 "{} control can only be matched against a CBOR byte string or uint, got {:?}",
1329 ctrl, self.cbor,
1330 )),
1331 }
1332 }
1333 _ => self.add_error(format!(
1334 ".bits control can only be matched against a byte string data type, got {}",
1335 target
1336 )),
1337 }
1338 self.ctrl = None;
1339
1340 Ok(())
1341 }
1342 #[cfg(feature = "additional-controls")]
1343 ControlOperator::CAT => {
1344 self.ctrl = Some(ctrl);
1345
1346 match cat_operation(self.cddl, target, controller, false) {
1347 Ok(values) => {
1348 let error_count = self.errors.len();
1349 for v in values.iter() {
1350 let cur_errors = self.errors.len();
1351
1352 self.visit_type2(v)?;
1353
1354 if self.errors.len() == cur_errors {
1355 for _ in 0..self.errors.len() - error_count {
1356 self.errors.pop();
1357 }
1358
1359 break;
1360 }
1361 }
1362 }
1363 Err(e) => self.add_error(e),
1364 }
1365
1366 self.ctrl = None;
1367
1368 Ok(())
1369 }
1370 #[cfg(feature = "additional-controls")]
1371 ControlOperator::DET => {
1372 self.ctrl = Some(ctrl);
1373
1374 match cat_operation(self.cddl, target, controller, true) {
1375 Ok(values) => {
1376 let error_count = self.errors.len();
1377
1378 for v in values.iter() {
1379 let cur_errors = self.errors.len();
1380 self.visit_type2(v)?;
1381
1382 if self.errors.len() == cur_errors {
1383 for _ in 0..self.errors.len() - error_count {
1384 self.errors.pop();
1385 }
1386
1387 break;
1388 }
1389 }
1390 }
1391 Err(e) => self.add_error(e),
1392 }
1393
1394 self.ctrl = None;
1395
1396 Ok(())
1397 }
1398 #[cfg(feature = "additional-controls")]
1399 ControlOperator::PLUS => {
1400 self.ctrl = Some(ctrl);
1401
1402 match plus_operation(self.cddl, target, controller) {
1403 Ok(values) => {
1404 let error_count = self.errors.len();
1405 for v in values.iter() {
1406 let cur_errors = self.errors.len();
1407
1408 self.visit_type2(v)?;
1409
1410 self.visit_type2(v)?;
1411 if self.errors.len() == cur_errors {
1412 for _ in 0..self.errors.len() - error_count {
1413 self.errors.pop();
1414 }
1415
1416 break;
1417 }
1418 }
1419 }
1420
1421 Err(e) => self.add_error(e),
1422 }
1423
1424 self.ctrl = None;
1425
1426 Ok(())
1427 }
1428 #[cfg(feature = "additional-controls")]
1429 ControlOperator::ABNF => {
1430 self.ctrl = Some(ctrl);
1431
1432 match target {
1433 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1434 match self.cbor {
1435 Value::Text(_) | Value::Array(_) => {
1436 if let Type2::ParenthesizedType { pt, .. } = controller {
1437 match abnf_from_complex_controller(self.cddl, pt) {
1438 Ok(values) => {
1439 let error_count = self.errors.len();
1440 for v in values.iter() {
1441 let cur_errors = self.errors.len();
1442
1443 self.visit_type2(v)?;
1444
1445 if self.errors.len() == cur_errors {
1446 for _ in 0..self.errors.len() - error_count {
1447 self.errors.pop();
1448 }
1449
1450 break;
1451 }
1452 }
1453 }
1454 Err(e) => self.add_error(e),
1455 }
1456 } else {
1457 self.visit_type2(controller)?
1458 }
1459 }
1460 _ => self.add_error(format!(
1461 ".abnf control can only be matched against a cbor string, got {:?}",
1462 self.cbor,
1463 )),
1464 }
1465 }
1466 _ => self.add_error(format!(
1467 ".abnf can only be matched against string data type, got {}",
1468 target,
1469 )),
1470 }
1471
1472 self.ctrl = None;
1473
1474 Ok(())
1475 }
1476 #[cfg(feature = "additional-controls")]
1477 ControlOperator::ABNFB => {
1478 self.ctrl = Some(ctrl);
1479
1480 match target {
1481 Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => {
1482 match self.cbor {
1483 Value::Bytes(_) | Value::Array(_) => {
1484 if let Type2::ParenthesizedType { pt, .. } = controller {
1485 match abnf_from_complex_controller(self.cddl, pt) {
1486 Ok(values) => {
1487 let error_count = self.errors.len();
1488 for v in values.iter() {
1489 let cur_errors = self.errors.len();
1490
1491 self.visit_type2(v)?;
1492
1493 if self.errors.len() == cur_errors {
1494 for _ in 0..self.errors.len() - error_count {
1495 self.errors.pop();
1496 }
1497
1498 break;
1499 }
1500 }
1501 }
1502 Err(e) => self.add_error(e),
1503 }
1504 } else {
1505 self.visit_type2(controller)?
1506 }
1507 }
1508 _ => self.add_error(format!(
1509 ".abnfb control can only be matched against cbor bytes, got {:?}",
1510 self.cbor,
1511 )),
1512 }
1513 }
1514 _ => self.add_error(format!(
1515 ".abnfb can only be matched against byte string target data type, got {}",
1516 target,
1517 )),
1518 }
1519
1520 self.ctrl = None;
1521
1522 Ok(())
1523 }
1524 #[cfg(feature = "additional-controls")]
1525 #[cfg(not(target_arch = "wasm32"))]
1526 ControlOperator::FEATURE => {
1527 self.ctrl = Some(ctrl);
1528
1529 if let Some(ef) = self.enabled_features {
1530 let tv = text_value_from_type2(self.cddl, controller);
1531 if let Some(Type2::TextValue { value, .. }) = tv {
1532 if ef.contains(&&**value) {
1533 let err_count = self.errors.len();
1534 self.visit_type2(target)?;
1535 if self.errors.len() > err_count {
1536 self.has_feature_errors = true;
1537 }
1538 self.ctrl = None;
1539 } else {
1540 self
1541 .disabled_features
1542 .get_or_insert(vec![value.to_string()])
1543 .push(value.to_string());
1544 }
1545 } else if let Some(Type2::UTF8ByteString { value, .. }) = tv {
1546 let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?;
1547 if ef.contains(&value) {
1548 let err_count = self.errors.len();
1549 self.visit_type2(target)?;
1550 if self.errors.len() > err_count {
1551 self.has_feature_errors = true;
1552 }
1553 self.ctrl = None;
1554 } else {
1555 self
1556 .disabled_features
1557 .get_or_insert(vec![value.to_string()])
1558 .push(value.to_string());
1559 }
1560 }
1561 }
1562
1563 self.ctrl = None;
1564
1565 Ok(())
1566 }
1567 #[cfg(feature = "additional-controls")]
1568 #[cfg(target_arch = "wasm32")]
1569 ControlOperator::FEATURE => {
1570 self.ctrl = Some(ctrl);
1571
1572 if let Some(ef) = &self.enabled_features {
1573 let tv = text_value_from_type2(self.cddl, controller);
1574 if let Some(Type2::TextValue { value, .. }) = tv {
1575 if ef.contains(&JsValue::from(value.as_ref())) {
1576 let err_count = self.errors.len();
1577 self.visit_type2(target)?;
1578 if self.errors.len() > err_count {
1579 self.has_feature_errors = true;
1580 }
1581 self.ctrl = None;
1582 } else {
1583 self
1584 .disabled_features
1585 .get_or_insert(vec![value.to_string()])
1586 .push(value.to_string());
1587 }
1588 } else if let Some(Type2::UTF8ByteString { value, .. }) = tv {
1589 let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?;
1590 if ef.contains(&JsValue::from(value)) {
1591 let err_count = self.errors.len();
1592 self.visit_type2(target)?;
1593 if self.errors.len() > err_count {
1594 self.has_feature_errors = true;
1595 }
1596 self.ctrl = None;
1597 } else {
1598 self
1599 .disabled_features
1600 .get_or_insert(vec![value.to_string()])
1601 .push(value.to_string());
1602 }
1603 }
1604 }
1605
1606 self.ctrl = None;
1607
1608 Ok(())
1609 }
1610 #[cfg(feature = "additional-controls")]
1611 ControlOperator::B64U => {
1612 match target {
1613 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1614 match &self.cbor {
1615 Value::Text(s) => {
1616 match crate::validator::control::validate_b64u_text(target, controller, s, false) {
1617 Ok(is_valid) => {
1618 if !is_valid {
1619 self.add_error(format!(
1620 "text string \"{}\" does not match .b64u encoded bytes",
1621 s
1622 ));
1623 }
1624 }
1625 Err(e) => self.add_error(e),
1626 }
1627 }
1628 _ => self.add_error(format!(
1629 ".b64u can only be matched against CBOR text, got {:?}",
1630 self.cbor
1631 )),
1632 }
1633 }
1634 _ => self.add_error(format!(
1635 ".b64u can only be matched against string data type, got {}",
1636 target
1637 )),
1638 }
1639
1640 Ok(())
1641 }
1642 #[cfg(feature = "additional-controls")]
1643 ControlOperator::B64C => {
1644 match target {
1645 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1646 match &self.cbor {
1647 Value::Text(s) => {
1648 match crate::validator::control::validate_b64c_text(target, controller, s, false) {
1649 Ok(is_valid) => {
1650 if !is_valid {
1651 self.add_error(format!(
1652 "text string \"{}\" does not match .b64c encoded bytes",
1653 s
1654 ));
1655 }
1656 }
1657 Err(e) => self.add_error(e),
1658 }
1659 }
1660 _ => self.add_error(format!(
1661 ".b64c can only be matched against CBOR text, got {:?}",
1662 self.cbor
1663 )),
1664 }
1665 }
1666 _ => self.add_error(format!(
1667 ".b64c can only be matched against string data type, got {}",
1668 target
1669 )),
1670 }
1671
1672 Ok(())
1673 }
1674 #[cfg(feature = "additional-controls")]
1675 ControlOperator::B64USLOPPY => {
1676 match target {
1677 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1678 match &self.cbor {
1679 Value::Text(s) => {
1680 match crate::validator::control::validate_b64u_text(target, controller, s, true) {
1681 Ok(is_valid) => {
1682 if !is_valid {
1683 self.add_error(format!(
1684 "text string \"{}\" does not match .b64u-sloppy encoded bytes",
1685 s
1686 ));
1687 }
1688 }
1689 Err(e) => self.add_error(e),
1690 }
1691 }
1692 _ => self.add_error(format!(
1693 ".b64u-sloppy can only be matched against CBOR text, got {:?}",
1694 self.cbor
1695 )),
1696 }
1697 }
1698 _ => self.add_error(format!(
1699 ".b64u-sloppy can only be matched against string data type, got {}",
1700 target
1701 )),
1702 }
1703
1704 Ok(())
1705 }
1706 #[cfg(feature = "additional-controls")]
1707 ControlOperator::B64CSLOPPY => {
1708 match target {
1709 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1710 match &self.cbor {
1711 Value::Text(s) => {
1712 match crate::validator::control::validate_b64c_text(target, controller, s, true) {
1713 Ok(is_valid) => {
1714 if !is_valid {
1715 self.add_error(format!(
1716 "text string \"{}\" does not match .b64c-sloppy encoded bytes",
1717 s
1718 ));
1719 }
1720 }
1721 Err(e) => self.add_error(e),
1722 }
1723 }
1724 _ => self.add_error(format!(
1725 ".b64c-sloppy can only be matched against CBOR text, got {:?}",
1726 self.cbor
1727 )),
1728 }
1729 }
1730 _ => self.add_error(format!(
1731 ".b64c-sloppy can only be matched against string data type, got {}",
1732 target
1733 )),
1734 }
1735
1736 Ok(())
1737 }
1738 #[cfg(feature = "additional-controls")]
1739 ControlOperator::HEX => {
1740 match target {
1741 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1742 match &self.cbor {
1743 Value::Text(s) => {
1744 match crate::validator::control::validate_hex_text(
1745 target,
1746 controller,
1747 s,
1748 crate::validator::control::HexCase::Any,
1749 ) {
1750 Ok(is_valid) => {
1751 if !is_valid {
1752 self.add_error(format!(
1753 "text string \"{}\" does not match .hex encoded bytes",
1754 s
1755 ));
1756 }
1757 }
1758 Err(e) => self.add_error(e),
1759 }
1760 }
1761 _ => self.add_error(format!(
1762 ".hex can only be matched against CBOR text, got {:?}",
1763 self.cbor
1764 )),
1765 }
1766 }
1767 _ => self.add_error(format!(
1768 ".hex can only be matched against string data type, got {}",
1769 target
1770 )),
1771 }
1772
1773 Ok(())
1774 }
1775 #[cfg(feature = "additional-controls")]
1776 ControlOperator::HEXLC => {
1777 match target {
1778 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1779 match &self.cbor {
1780 Value::Text(s) => {
1781 match crate::validator::control::validate_hex_text(
1782 target,
1783 controller,
1784 s,
1785 crate::validator::control::HexCase::Lower,
1786 ) {
1787 Ok(is_valid) => {
1788 if !is_valid {
1789 self.add_error(format!(
1790 "text string \"{}\" does not match .hexlc encoded bytes",
1791 s
1792 ));
1793 }
1794 }
1795 Err(e) => self.add_error(e),
1796 }
1797 }
1798 _ => self.add_error(format!(
1799 ".hexlc can only be matched against CBOR text, got {:?}",
1800 self.cbor
1801 )),
1802 }
1803 }
1804 _ => self.add_error(format!(
1805 ".hexlc can only be matched against string data type, got {}",
1806 target
1807 )),
1808 }
1809
1810 Ok(())
1811 }
1812 #[cfg(feature = "additional-controls")]
1813 ControlOperator::HEXUC => {
1814 match target {
1815 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1816 match &self.cbor {
1817 Value::Text(s) => {
1818 match crate::validator::control::validate_hex_text(
1819 target,
1820 controller,
1821 s,
1822 crate::validator::control::HexCase::Upper,
1823 ) {
1824 Ok(is_valid) => {
1825 if !is_valid {
1826 self.add_error(format!(
1827 "text string \"{}\" does not match .hexuc encoded bytes",
1828 s
1829 ));
1830 }
1831 }
1832 Err(e) => self.add_error(e),
1833 }
1834 }
1835 _ => self.add_error(format!(
1836 ".hexuc can only be matched against CBOR text, got {:?}",
1837 self.cbor
1838 )),
1839 }
1840 }
1841 _ => self.add_error(format!(
1842 ".hexuc can only be matched against string data type, got {}",
1843 target
1844 )),
1845 }
1846
1847 Ok(())
1848 }
1849 #[cfg(feature = "additional-controls")]
1850 ControlOperator::B32 => {
1851 match target {
1852 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1853 match &self.cbor {
1854 Value::Text(s) => {
1855 match crate::validator::control::validate_b32_text(target, controller, s, false) {
1856 Ok(is_valid) => {
1857 if !is_valid {
1858 self.add_error(format!(
1859 "text string \"{}\" does not match .b32 encoded bytes",
1860 s
1861 ));
1862 }
1863 }
1864 Err(e) => self.add_error(e),
1865 }
1866 }
1867 _ => self.add_error(format!(
1868 ".b32 can only be matched against CBOR text, got {:?}",
1869 self.cbor
1870 )),
1871 }
1872 }
1873 _ => self.add_error(format!(
1874 ".b32 can only be matched against string data type, got {}",
1875 target
1876 )),
1877 }
1878
1879 Ok(())
1880 }
1881 #[cfg(feature = "additional-controls")]
1882 ControlOperator::H32 => {
1883 match target {
1884 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1885 match &self.cbor {
1886 Value::Text(s) => {
1887 match crate::validator::control::validate_b32_text(target, controller, s, true) {
1888 Ok(is_valid) => {
1889 if !is_valid {
1890 self.add_error(format!(
1891 "text string \"{}\" does not match .h32 encoded bytes",
1892 s
1893 ));
1894 }
1895 }
1896 Err(e) => self.add_error(e),
1897 }
1898 }
1899 _ => self.add_error(format!(
1900 ".h32 can only be matched against CBOR text, got {:?}",
1901 self.cbor
1902 )),
1903 }
1904 }
1905 _ => self.add_error(format!(
1906 ".h32 can only be matched against string data type, got {}",
1907 target
1908 )),
1909 }
1910
1911 Ok(())
1912 }
1913 #[cfg(feature = "additional-controls")]
1914 ControlOperator::B45 => {
1915 match target {
1916 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1917 match &self.cbor {
1918 Value::Text(s) => {
1919 match crate::validator::control::validate_b45_text(target, controller, s) {
1920 Ok(is_valid) => {
1921 if !is_valid {
1922 self.add_error(format!(
1923 "text string \"{}\" does not match .b45 encoded bytes",
1924 s
1925 ));
1926 }
1927 }
1928 Err(e) => self.add_error(e),
1929 }
1930 }
1931 _ => self.add_error(format!(
1932 ".b45 can only be matched against CBOR text, got {:?}",
1933 self.cbor
1934 )),
1935 }
1936 }
1937 _ => self.add_error(format!(
1938 ".b45 can only be matched against string data type, got {}",
1939 target
1940 )),
1941 }
1942
1943 Ok(())
1944 }
1945 #[cfg(feature = "additional-controls")]
1946 ControlOperator::BASE10 => {
1947 match target {
1948 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1949 match &self.cbor {
1950 Value::Text(s) => {
1951 match crate::validator::control::validate_base10_text(target, controller, s) {
1952 Ok(is_valid) => {
1953 if !is_valid {
1954 self.add_error(format!(
1955 "text string \"{}\" does not match .base10 integer format",
1956 s
1957 ));
1958 }
1959 }
1960 Err(e) => self.add_error(e),
1961 }
1962 }
1963 _ => self.add_error(format!(
1964 ".base10 can only be matched against CBOR text, got {:?}",
1965 self.cbor
1966 )),
1967 }
1968 }
1969 _ => self.add_error(format!(
1970 ".base10 can only be matched against string data type, got {}",
1971 target
1972 )),
1973 }
1974
1975 Ok(())
1976 }
1977 #[cfg(feature = "additional-controls")]
1978 ControlOperator::PRINTF => {
1979 match target {
1980 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
1981 match &self.cbor {
1982 Value::Text(s) => {
1983 match crate::validator::control::validate_printf_text(target, controller, s) {
1984 Ok(is_valid) => {
1985 if !is_valid {
1986 self.add_error(format!(
1987 "text string \"{}\" does not match .printf format",
1988 s
1989 ));
1990 }
1991 }
1992 Err(e) => self.add_error(e),
1993 }
1994 }
1995 _ => self.add_error(format!(
1996 ".printf can only be matched against CBOR text, got {:?}",
1997 self.cbor
1998 )),
1999 }
2000 }
2001 _ => self.add_error(format!(
2002 ".printf can only be matched against string data type, got {}",
2003 target
2004 )),
2005 }
2006
2007 Ok(())
2008 }
2009 #[cfg(feature = "additional-controls")]
2010 ControlOperator::JSON => {
2011 match target {
2012 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
2013 match &self.cbor {
2014 Value::Text(s) => {
2015 match crate::validator::control::validate_json_text(target, controller, s) {
2016 Ok(is_valid) => {
2017 if !is_valid {
2018 self.add_error(format!("text string \"{}\" does not contain valid JSON", s));
2019 }
2020 }
2021 Err(e) => self.add_error(e),
2022 }
2023 }
2024 _ => self.add_error(format!(
2025 ".json can only be matched against CBOR text, got {:?}",
2026 self.cbor
2027 )),
2028 }
2029 }
2030 _ => self.add_error(format!(
2031 ".json can only be matched against string data type, got {}",
2032 target
2033 )),
2034 }
2035
2036 Ok(())
2037 }
2038 #[cfg(feature = "additional-controls")]
2039 ControlOperator::JOIN => {
2040 match target {
2041 Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => {
2042 match &self.cbor {
2043 Value::Text(s) => {
2044 match crate::validator::control::validate_join_text(target, controller, s) {
2045 Ok(is_valid) => {
2046 if !is_valid {
2047 self.add_error(format!("text string \"{}\" does not match .join result", s));
2048 }
2049 }
2050 Err(e) => self.add_error(e),
2051 }
2052 }
2053 _ => self.add_error(format!(
2054 ".join can only be matched against CBOR text, got {:?}",
2055 self.cbor
2056 )),
2057 }
2058 }
2059 _ => self.add_error(format!(
2060 ".join can only be matched against string data type, got {}",
2061 target
2062 )),
2063 }
2064
2065 Ok(())
2066 }
2067 }
2068 }
2069
2070 fn visit_type2(&mut self, t2: &Type2<'a>) -> visitor::Result<Error<T>> {
2071 if matches!(self.ctrl, Some(ControlOperator::CBOR)) {
2072 if let Value::Bytes(b) = &self.cbor {
2073 let value = ciborium::de::from_reader(&b[..]);
2074 match value {
2075 Ok(value) => {
2076 let current_location = self.cbor_location.clone();
2077
2078 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2079 let mut cv = CBORValidator::new(self.cddl, value, self.enabled_features.clone());
2080 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2081 let mut cv = CBORValidator::new(self.cddl, value, self.enabled_features);
2082 #[cfg(not(feature = "additional-controls"))]
2083 let mut cv = CBORValidator::new(self.cddl, value);
2084
2085 cv.generic_rules = self.generic_rules.clone();
2086 cv.eval_generic_rule = self.eval_generic_rule;
2087 cv.is_multi_type_choice = self.is_multi_type_choice;
2088 cv.is_multi_group_choice = self.is_multi_group_choice;
2089 cv.cbor_location.push_str(&self.cbor_location);
2090 cv.type_group_name_entry = self.type_group_name_entry;
2091 cv.visit_type2(t2)?;
2092
2093 if cv.errors.is_empty() {
2094 self.cbor_location = current_location;
2095 return Ok(());
2096 }
2097
2098 self.errors.append(&mut cv.errors);
2099 }
2100 Err(e) => {
2101 self.add_error(format!("error decoding embedded CBOR, {}", e));
2102 }
2103 }
2104 }
2105
2106 return Ok(());
2107 } else if matches!(self.ctrl, Some(ControlOperator::CBORSEQ)) {
2108 if let Value::Bytes(b) = &self.cbor {
2109 let value = ciborium::de::from_reader(&b[..]);
2110 match value {
2111 Ok(Value::Array(_)) => {
2112 let current_location = self.cbor_location.clone();
2113
2114 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2115 let mut cv = CBORValidator::new(
2116 self.cddl,
2117 value.unwrap_or(Value::Null),
2118 self.enabled_features.clone(),
2119 );
2120 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2121 let mut cv = CBORValidator::new(
2122 self.cddl,
2123 value.unwrap_or(Value::Null),
2124 self.enabled_features,
2125 );
2126
2127 #[cfg(not(feature = "additional-controls"))]
2128 let mut cv = CBORValidator::new(self.cddl, value.unwrap_or(Value::Null));
2129
2130 cv.generic_rules = self.generic_rules.clone();
2131 cv.eval_generic_rule = self.eval_generic_rule;
2132 cv.is_multi_type_choice = self.is_multi_type_choice;
2133 cv.is_multi_group_choice = self.is_multi_group_choice;
2134 cv.cbor_location.push_str(&self.cbor_location);
2135 cv.type_group_name_entry = self.type_group_name_entry;
2136 cv.visit_type2(t2)?;
2137
2138 if cv.errors.is_empty() {
2139 self.cbor_location = current_location;
2140 return Ok(());
2141 }
2142
2143 self.errors.append(&mut cv.errors);
2144 }
2145 Err(e) => {
2146 self.add_error(format!("error decoding embedded CBOR, {}", e));
2147 }
2148 Ok(v) => self.add_error(format!(
2149 "embedded CBOR must be a CBOR sequence, got {:?}",
2150 v
2151 )),
2152 }
2153 }
2154
2155 return Ok(());
2156 }
2157
2158 match t2 {
2159 Type2::TextValue { value, .. } => self.visit_value(&token::Value::TEXT(value.clone())),
2160 Type2::Map { group, .. } => match &self.cbor {
2161 Value::Map(m) => {
2162 if self.is_member_key {
2163 let current_location = self.cbor_location.clone();
2164
2165 for (k, v) in m.iter() {
2166 #[cfg(feature = "additional-controls")]
2167 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2168 let mut cv = CBORValidator::new(self.cddl, k.clone(), self.enabled_features.clone());
2169 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2170 let mut cv = CBORValidator::new(self.cddl, k.clone(), self.enabled_features);
2171 #[cfg(not(feature = "additional-controls"))]
2172 let mut cv = CBORValidator::new(self.cddl, k.clone());
2173
2174 cv.generic_rules = self.generic_rules.clone();
2175 cv.eval_generic_rule = self.eval_generic_rule;
2176 cv.is_multi_type_choice = self.is_multi_type_choice;
2177 cv.is_multi_group_choice = self.is_multi_group_choice;
2178 cv.cbor_location.push_str(&self.cbor_location);
2179 cv.type_group_name_entry = self.type_group_name_entry;
2180 cv.visit_type2(t2)?;
2181
2182 if cv.errors.is_empty() {
2183 self.object_value = Some(v.clone());
2184 self
2185 .validated_keys
2186 .get_or_insert(vec![k.clone()])
2187 .push(k.clone());
2188 self.cbor_location = current_location;
2189 return Ok(());
2190 }
2191
2192 self.errors.append(&mut cv.errors);
2193 }
2194
2195 return Ok(());
2196 }
2197
2198 if group.group_choices.len() == 1
2200 && group.group_choices[0].group_entries.is_empty()
2201 && !m.is_empty()
2202 && !matches!(
2203 self.ctrl,
2204 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT)
2205 )
2206 {
2207 self.add_error(format!("expected empty map, got {:?}", self.cbor));
2208 return Ok(());
2209 }
2210
2211 #[allow(clippy::needless_collect)]
2212 let m = m.iter().map(|entry| entry.0.clone()).collect::<Vec<_>>();
2213
2214 self.visit_group(group)?;
2215
2216 if self.values_to_validate.is_none() {
2218 for k in m.into_iter() {
2219 if let Some(keys) = &self.validated_keys {
2220 if !keys.contains(&k) {
2221 self.add_error(format!("unexpected key {:?}", k));
2222 }
2223 }
2224 }
2225 }
2226
2227 self.is_cut_present = false;
2228 self.cut_value = None;
2229 Ok(())
2230 }
2231 Value::Array(_) => self.validate_array_items(&ArrayItemToken::Group(group)),
2232 _ => {
2233 self.add_error(format!("expected map object {}, got {:?}", t2, self.cbor));
2234 Ok(())
2235 }
2236 },
2237 Type2::Array { group, .. } => match &self.cbor {
2238 Value::Array(a) => {
2239 if group.group_choices.len() == 1
2240 && group.group_choices[0].group_entries.is_empty()
2241 && !a.is_empty()
2242 && !matches!(
2243 self.ctrl,
2244 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT)
2245 )
2246 {
2247 self.add_error(format!("expected empty array, got {:?}", self.cbor));
2248 return Ok(());
2249 }
2250
2251 self.entry_counts = Some(entry_counts_from_group(self.cddl, group));
2252 self.visit_group(group)?;
2253 self.entry_counts = None;
2254
2255 if let Some(errors) = &mut self.array_errors {
2256 if let Some(indices) = &self.valid_array_items {
2257 for idx in indices.iter() {
2258 errors.remove(idx);
2259 }
2260 }
2261
2262 for error in errors.values_mut() {
2263 self.errors.append(error);
2264 }
2265 }
2266
2267 self.valid_array_items = None;
2268 self.array_errors = None;
2269
2270 Ok(())
2271 }
2272 Value::Map(m) if self.is_member_key => {
2273 let current_location = self.cbor_location.clone();
2274
2275 self.entry_counts = Some(entry_counts_from_group(self.cddl, group));
2276
2277 for (k, v) in m.iter() {
2278 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2279 let mut cv = CBORValidator::new(self.cddl, k.clone(), self.enabled_features.clone());
2280 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2281 let mut cv = CBORValidator::new(self.cddl, k.clone(), self.enabled_features);
2282 #[cfg(not(feature = "additional-controls"))]
2283 let mut cv = CBORValidator::new(self.cddl, k.clone());
2284
2285 cv.generic_rules = self.generic_rules.clone();
2286 cv.entry_counts = self.entry_counts.clone();
2287 cv.eval_generic_rule = self.eval_generic_rule;
2288 cv.is_multi_type_choice = self.is_multi_type_choice;
2289 cv.is_multi_group_choice = self.is_multi_group_choice;
2290 cv.cbor_location.push_str(&self.cbor_location);
2291 cv.type_group_name_entry = self.type_group_name_entry;
2292 cv.visit_type2(t2)?;
2293
2294 if cv.errors.is_empty() {
2295 self.object_value = Some(v.clone());
2296 self
2297 .validated_keys
2298 .get_or_insert(vec![k.clone()])
2299 .push(k.clone());
2300 self.cbor_location = current_location;
2301 return Ok(());
2302 }
2303
2304 self.errors.append(&mut cv.errors);
2305 }
2306
2307 self.entry_counts = None;
2308
2309 Ok(())
2310 }
2311 _ => {
2312 self.add_error(format!("expected array type, got {:?}", self.cbor));
2313 Ok(())
2314 }
2315 },
2316 Type2::ChoiceFromGroup {
2317 ident,
2318 generic_args,
2319 ..
2320 } => {
2321 if let Some(ga) = generic_args {
2322 if let Some(rule) = rule_from_ident(self.cddl, ident) {
2323 if let Some(gr) = self
2324 .generic_rules
2325 .iter_mut()
2326 .find(|gr| gr.name == ident.ident)
2327 {
2328 for arg in ga.args.iter() {
2329 gr.args.push((*arg.arg).clone());
2330 }
2331 } else if let Some(params) = generic_params_from_rule(rule) {
2332 self.generic_rules.push(GenericRule {
2333 name: ident.ident,
2334 params,
2335 args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(),
2336 });
2337 }
2338
2339 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2340 let mut cv =
2341 CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features.clone());
2342 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2343 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features);
2344 #[cfg(not(feature = "additional-controls"))]
2345 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone());
2346
2347 cv.generic_rules = self.generic_rules.clone();
2348 cv.eval_generic_rule = Some(ident.ident);
2349 cv.is_group_to_choice_enum = true;
2350 cv.is_multi_type_choice = self.is_multi_type_choice;
2351 cv.visit_rule(rule)?;
2352
2353 self.errors.append(&mut cv.errors);
2354
2355 return Ok(());
2356 }
2357 }
2358
2359 if group_rule_from_ident(self.cddl, ident).is_none() {
2360 self.add_error(format!(
2361 "rule {} must be a group rule to turn it into a choice",
2362 ident
2363 ));
2364 return Ok(());
2365 }
2366
2367 self.is_group_to_choice_enum = true;
2368 self.visit_identifier(ident)?;
2369 self.is_group_to_choice_enum = false;
2370
2371 Ok(())
2372 }
2373 Type2::ChoiceFromInlineGroup { group, .. } => {
2374 self.is_group_to_choice_enum = true;
2375 self.visit_group(group)?;
2376 self.is_group_to_choice_enum = false;
2377 Ok(())
2378 }
2379 Type2::Typename {
2380 ident,
2381 generic_args,
2382 ..
2383 } => {
2384 if let Some(ga) = generic_args {
2385 if let Some(rule) = rule_from_ident(self.cddl, ident) {
2386 if let Some(gr) = self
2387 .generic_rules
2388 .iter_mut()
2389 .find(|gr| gr.name == ident.ident)
2390 {
2391 for arg in ga.args.iter() {
2392 gr.args.push((*arg.arg).clone());
2393 }
2394 } else if let Some(params) = generic_params_from_rule(rule) {
2395 self.generic_rules.push(GenericRule {
2396 name: ident.ident,
2397 params,
2398 args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(),
2399 });
2400 }
2401
2402 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2403 let mut cv =
2404 CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features.clone());
2405 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2406 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features);
2407 #[cfg(not(feature = "additional-controls"))]
2408 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone());
2409
2410 cv.generic_rules = self.generic_rules.clone();
2411 cv.eval_generic_rule = Some(ident.ident);
2412 cv.is_multi_type_choice = self.is_multi_type_choice;
2413 cv.visit_rule(rule)?;
2414
2415 self.errors.append(&mut cv.errors);
2416
2417 return Ok(());
2418 }
2419 }
2420
2421 let type_choice_alternates = type_choice_alternates_from_ident(self.cddl, ident);
2422 if !type_choice_alternates.is_empty() {
2423 self.is_multi_type_choice = true;
2424 }
2425
2426 let error_count = self.errors.len();
2427 for t in type_choice_alternates {
2428 let cur_errors = self.errors.len();
2429 self.visit_type(t)?;
2430 if self.errors.len() == cur_errors {
2431 for _ in 0..self.errors.len() - error_count {
2432 self.errors.pop();
2433 }
2434
2435 return Ok(());
2436 }
2437 }
2438
2439 self.visit_identifier(ident)
2440 }
2441 Type2::IntValue { value, .. } => self.visit_value(&token::Value::INT(*value)),
2442 Type2::UintValue { value, .. } => self.visit_value(&token::Value::UINT(*value)),
2443 Type2::FloatValue { value, .. } => self.visit_value(&token::Value::FLOAT(*value)),
2444 Type2::UTF8ByteString { value, .. } => {
2445 self.visit_value(&token::Value::BYTE(ByteValue::UTF8(value.clone())))
2446 }
2447 Type2::B16ByteString { value, .. } => {
2448 self.visit_value(&token::Value::BYTE(ByteValue::B16(value.clone())))
2449 }
2450 Type2::ParenthesizedType { pt, .. } => self.visit_type(pt),
2451 Type2::Unwrap {
2452 ident,
2453 generic_args,
2454 ..
2455 } => {
2456 if let Some(Type2::TaggedData { t, .. }) = tag_from_token(&lookup_ident(ident.ident)) {
2460 return self.visit_type(&t);
2461 }
2462
2463 if let Some(ga) = generic_args {
2464 if let Some(rule) = unwrap_rule_from_ident(self.cddl, ident) {
2465 if let Some(gr) = self
2466 .generic_rules
2467 .iter_mut()
2468 .find(|gr| gr.name == ident.ident)
2469 {
2470 for arg in ga.args.iter() {
2471 gr.args.push((*arg.arg).clone());
2472 }
2473 } else if let Some(params) = generic_params_from_rule(rule) {
2474 self.generic_rules.push(GenericRule {
2475 name: ident.ident,
2476 params,
2477 args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(),
2478 });
2479 }
2480
2481 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2482 let mut cv =
2483 CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features.clone());
2484 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2485 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features);
2486 #[cfg(not(feature = "additional-controls"))]
2487 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone());
2488
2489 cv.generic_rules = self.generic_rules.clone();
2490 cv.eval_generic_rule = Some(ident.ident);
2491 cv.is_multi_type_choice = self.is_multi_type_choice;
2492 cv.visit_rule(rule)?;
2493
2494 self.errors.append(&mut cv.errors);
2495
2496 return Ok(());
2497 }
2498 }
2499
2500 if let Some(rule) = unwrap_rule_from_ident(self.cddl, ident) {
2501 return self.visit_rule(rule);
2502 }
2503
2504 self.add_error(format!(
2505 "cannot unwrap identifier {}, rule not found",
2506 ident
2507 ));
2508
2509 Ok(())
2510 }
2511 Type2::TaggedData { tag, t, .. } => match &self.cbor {
2512 Value::Tag(actual_tag, value) => {
2513 if let Some(tag_constraint) = tag {
2514 if let Some(expected_tag) = tag_constraint.as_literal() {
2516 if expected_tag != *actual_tag {
2517 self.add_error(format!(
2518 "expected tagged data #6.{}({}), got {:?}",
2519 expected_tag, t, self.cbor
2520 ));
2521 return Ok(());
2522 }
2523 } else {
2524 }
2527 } else if *actual_tag > 0 {
2528 self.add_error(format!(
2529 "expected tagged data #6({}), got {:?}",
2530 t, self.cbor
2531 ));
2532 return Ok(());
2533 }
2534
2535 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
2536 let mut cv = CBORValidator::new(
2537 self.cddl,
2538 value.as_ref().clone(),
2539 self.enabled_features.clone(),
2540 );
2541 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
2542 let mut cv = CBORValidator::new(self.cddl, value.as_ref().clone(), self.enabled_features);
2543 #[cfg(not(feature = "additional-controls"))]
2544 let mut cv = CBORValidator::new(self.cddl, value.as_ref().clone());
2545
2546 cv.generic_rules = self.generic_rules.clone();
2547 cv.eval_generic_rule = self.eval_generic_rule;
2548 cv.is_multi_type_choice = self.is_multi_type_choice;
2549 cv.is_multi_group_choice = self.is_multi_group_choice;
2550 cv.cbor_location.push_str(&self.cbor_location);
2551 cv.type_group_name_entry = self.type_group_name_entry;
2552 cv.visit_type(t)?;
2553
2554 self.errors.append(&mut cv.errors);
2555 Ok(())
2556 }
2557 Value::Array(_) => self.validate_array_items(&ArrayItemToken::TaggedData(t2)),
2558 _ => {
2559 if let Some(tag) = tag {
2560 self.add_error(format!(
2561 "expected tagged data #6.{}({}), got {:?}",
2562 tag, t, self.cbor
2563 ));
2564 } else {
2565 self.add_error(format!(
2566 "expected tagged data #6({}), got {:?}",
2567 t, self.cbor
2568 ));
2569 }
2570
2571 Ok(())
2572 }
2573 },
2574 Type2::DataMajorType { mt, constraint, .. } => match &self.cbor {
2575 Value::Integer(i) => {
2576 match mt {
2577 0u8 => match constraint {
2578 Some(c) => {
2579 if let Some(literal_val) = c.as_literal() {
2580 if i128::from(*i) == literal_val as i128 && i128::from(*i) >= 0i128 {
2581 return Ok(());
2582 }
2583 }
2584 self.add_error(format!(
2585 "expected uint data type with constraint {} (#{}.{}), got {:?}",
2586 c, mt, c, self.cbor
2587 ));
2588 return Ok(());
2589 }
2590 _ => {
2591 if i128::from(*i).is_negative() {
2592 self.add_error(format!(
2593 "expected uint data type (#{}), got {:?}",
2594 mt, self.cbor
2595 ));
2596 return Ok(());
2597 }
2598 }
2599 },
2600 1u8 => match constraint {
2601 Some(c) => {
2602 if let Some(literal_val) = c.as_literal() {
2603 if i128::from(*i) == 0i128 - literal_val as i128 {
2604 return Ok(());
2605 }
2606 }
2607 self.add_error(format!(
2608 "expected nint type with constraint {} (#{}.{}), got {:?}",
2609 c, mt, c, self.cbor
2610 ));
2611 return Ok(());
2612 }
2613 _ => {
2614 if i128::from(*i) >= 0i128 {
2615 self.add_error(format!(
2616 "expected nint data type (#{}), got {:?}",
2617 mt, self.cbor
2618 ));
2619 return Ok(());
2620 }
2621 }
2622 },
2623 _ => self.add_error(format!(
2624 "expected major type {} with constraint {:?}, got {:?}",
2625 mt, constraint, self.cbor
2626 )),
2627 }
2628
2629 Ok(())
2630 }
2631 Value::Bytes(b) => {
2632 match mt {
2633 2u8 => match constraint {
2634 Some(c) if c.is_literal(b.len() as u64) => return Ok(()),
2635 Some(c) => self.add_error(format!(
2636 "expected byte string type with constraint {} (#{}.{}), got {:?}",
2637 c, mt, c, self.cbor
2638 )),
2639 _ => return Ok(()),
2640 },
2641 _ => self.add_error(format!(
2642 "expected major type {} with constraint {:?}, got {:?}",
2643 mt, constraint, self.cbor
2644 )),
2645 }
2646
2647 Ok(())
2648 }
2649 Value::Text(t) => {
2650 match mt {
2651 3u8 => match constraint {
2652 Some(c) if c.is_literal(t.len() as u64) => return Ok(()),
2653 Some(c) => self.add_error(format!(
2654 "expected text string type with constraint {} (#{}.{}), got {:?}",
2655 c, mt, c, self.cbor
2656 )),
2657 _ => return Ok(()),
2658 },
2659 _ => self.add_error(format!(
2660 "expected major type {} with constraint {:?}, got {:?}",
2661 mt, constraint, self.cbor
2662 )),
2663 }
2664
2665 Ok(())
2666 }
2667 Value::Array(a) => {
2668 match mt {
2669 4u8 => match constraint {
2670 Some(c) if c.is_literal(a.len() as u64) => return Ok(()),
2671 Some(c) => self.add_error(format!(
2672 "expected array type with constraint {} (#{}.{}), got {:?}",
2673 c, mt, c, self.cbor
2674 )),
2675 _ => return Ok(()),
2676 },
2677 _ => self.add_error(format!(
2678 "expected major type {} with constraint {:?}, got {:?}",
2679 mt, constraint, self.cbor
2680 )),
2681 }
2682
2683 Ok(())
2684 }
2685 Value::Map(m) => {
2686 match mt {
2687 5u8 => match constraint {
2688 Some(c) if c.is_literal(m.len() as u64) => return Ok(()),
2689 Some(c) => self.add_error(format!(
2690 "expected map type with constraint {} (#{}.{}), got {:?}",
2691 c, mt, c, self.cbor
2692 )),
2693 _ => return Ok(()),
2694 },
2695 _ => self.add_error(format!(
2696 "expected major type {} with constraint {:?}, got {:?}",
2697 mt, constraint, self.cbor
2698 )),
2699 }
2700
2701 Ok(())
2702 }
2703 Value::Float(_f) => {
2704 match mt {
2705 7u8 => match constraint {
2706 Some(_c) => unimplemented!(),
2707 _ => return Ok(()),
2708 },
2709 _ => self.add_error(format!(
2710 "expected major type {} with constraint {:?}, got {:?}",
2711 mt, constraint, self.cbor
2712 )),
2713 }
2714
2715 Ok(())
2716 }
2717 _ => {
2718 if let Some(constraint) = constraint {
2719 self.add_error(format!(
2720 "expected major type #{}.{}, got {:?}",
2721 mt, constraint, self.cbor
2722 ));
2723 } else {
2724 self.add_error(format!("expected major type #{}, got {:?}", mt, self.cbor));
2725 }
2726
2727 Ok(())
2728 }
2729 },
2730 #[cfg(feature = "ast-span")]
2731 Type2::Any { .. } => Ok(()),
2732 #[cfg(not(feature = "ast-span"))]
2733 Type2::Any {} => Ok(()),
2734 _ => {
2735 self.add_error(format!(
2736 "unsupported data type for validating cbor, got {}",
2737 t2
2738 ));
2739 Ok(())
2740 }
2741 }
2742 }
2743
2744 fn visit_identifier(&mut self, ident: &Identifier<'a>) -> visitor::Result<Error<T>> {
2745 if let Some(name) = self.eval_generic_rule {
2746 if let Some(gr) = self
2747 .generic_rules
2748 .iter()
2749 .find(|&gr| gr.name == name)
2750 .cloned()
2751 {
2752 for (idx, gp) in gr.params.iter().enumerate() {
2753 if *gp == ident.ident {
2754 if let Some(arg) = gr.args.get(idx) {
2755 return self.visit_type1(arg);
2756 }
2757 }
2758 }
2759 }
2760 }
2761
2762 if !self.is_colon_shortcut_present {
2765 if let Some(r) = rule_from_ident(self.cddl, ident) {
2766 let rule_key = ident.ident.to_string();
2768 if self.visited_rules.contains(&rule_key) {
2769 return Ok(());
2772 }
2773
2774 self.visited_rules.insert(rule_key.clone());
2776 let result = self.visit_rule(r);
2777 self.visited_rules.remove(&rule_key);
2779
2780 return result;
2781 }
2782 }
2783
2784 if is_ident_any_type(self.cddl, ident) {
2785 return Ok(());
2786 }
2787
2788 if let Value::Array(_) = &self.cbor {
2791 if let Some(Rule::Type { rule, .. }) = rule_from_ident(self.cddl, ident) {
2792 for tc in rule.value.type_choices.iter() {
2793 if let Type2::Array { .. } = &tc.type1.type2 {
2794 return self.visit_type_choice(tc);
2795 }
2796 }
2797 }
2798 }
2799
2800 match &self.cbor {
2801 Value::Null if is_ident_null_data_type(self.cddl, ident) => Ok(()),
2802 Value::Bytes(_) if is_ident_byte_string_data_type(self.cddl, ident) => Ok(()),
2803 Value::Bool(b) => {
2804 if is_ident_bool_data_type(self.cddl, ident) {
2805 return Ok(());
2806 }
2807
2808 if ident_matches_bool_value(self.cddl, ident, *b) {
2809 return Ok(());
2810 }
2811
2812 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2813 Ok(())
2814 }
2815 Value::Integer(i) => {
2816 if is_ident_uint_data_type(self.cddl, ident) {
2817 if i128::from(*i).is_negative() {
2818 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2819 }
2820
2821 Ok(())
2822 } else if is_ident_integer_data_type(self.cddl, ident) {
2823 Ok(())
2824 } else if is_ident_time_data_type(self.cddl, ident) {
2825 if let chrono::LocalResult::None =
2826 Utc.timestamp_millis_opt((i128::from(*i) * 1000) as i64)
2827 {
2828 let i = *i;
2829 self.add_error(format!(
2830 "expected time data type, invalid UNIX timestamp {:?}",
2831 i,
2832 ));
2833 }
2834
2835 Ok(())
2836 } else {
2837 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2838 Ok(())
2839 }
2840 }
2841 Value::Float(f) => {
2842 if is_ident_float_data_type(self.cddl, ident) {
2843 Ok(())
2844 } else if is_ident_time_data_type(self.cddl, ident) {
2845 if let chrono::LocalResult::None = Utc.timestamp_millis_opt((*f * 1000f64) as i64) {
2846 let f = *f;
2847 self.add_error(format!(
2848 "expected time data type, invalid UNIX timestamp {:?}",
2849 f,
2850 ));
2851 }
2852
2853 Ok(())
2854 } else {
2855 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2856 Ok(())
2857 }
2858 }
2859 Value::Text(s) => {
2860 if is_ident_uri_data_type(self.cddl, ident) {
2861 if let Err(e) = uriparse::URI::try_from(&**s) {
2862 self.add_error(format!("expected URI data type, decoding error: {}", e));
2863 }
2864 } else if is_ident_b64url_data_type(self.cddl, ident) {
2865 if let Err(e) = base64_url::decode(s) {
2866 self.add_error(format!(
2867 "expected base64 URL data type, decoding error: {}",
2868 e
2869 ));
2870 }
2871 } else if is_ident_tdate_data_type(self.cddl, ident) {
2872 if let Err(e) = chrono::DateTime::parse_from_rfc3339(s) {
2873 self.add_error(format!("expected tdate data type, decoding error: {}", e));
2874 }
2875 } else if is_ident_string_data_type(self.cddl, ident) {
2876 return Ok(());
2877 } else {
2878 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2879 }
2880
2881 Ok(())
2882 }
2883 Value::Tag(tag, value) => {
2884 match *tag {
2885 0 => {
2886 if is_ident_tdate_data_type(self.cddl, ident) {
2887 if let Value::Text(value) = value.as_ref() {
2888 if let Err(e) = chrono::DateTime::parse_from_rfc3339(value) {
2889 self.add_error(format!("expected tdate data type, decoding error: {}", e));
2890 }
2891 } else {
2892 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2893 }
2894 } else {
2895 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2896 }
2897 }
2898 1 => {
2899 if is_ident_time_data_type(self.cddl, ident) {
2900 if let Value::Integer(value) = *value.as_ref() {
2901 let dt = Utc.timestamp_opt(value.try_into().unwrap(), 0);
2902 if let chrono::LocalResult::None = dt {
2903 self.add_error(format!(
2904 "expected time data type, invalid UNIX timestamp {:?}",
2905 self.cbor
2906 ));
2907 }
2908 } else if let Value::Float(value) = value.as_ref() {
2909 let seconds = value.trunc() as i64;
2910 let nanoseconds = (value.fract() * 1e9) as u32;
2911 let dt = Utc.timestamp_opt(seconds, nanoseconds);
2912 if let chrono::LocalResult::None = dt {
2913 self.add_error(format!(
2914 "expected time data type, invalid UNIX timestamp {:?}",
2915 self.cbor
2916 ));
2917 }
2918 } else {
2919 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2920 }
2921 } else {
2922 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
2923 }
2924 }
2925 _ => (),
2926 }
2927
2928 Ok(())
2929 }
2930 Value::Array(_) => self.validate_array_items(&ArrayItemToken::Identifier(ident)),
2931 Value::Map(m) => {
2932 match &self.occurrence {
2933 #[cfg(feature = "ast-span")]
2934 Some(Occur::Optional { .. }) | None => {
2935 if is_ident_string_data_type(self.cddl, ident) && !self.validating_value {
2936 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Text(_))) {
2937 self
2938 .validated_keys
2939 .get_or_insert(vec![k.clone()])
2940 .push(k.clone());
2941 self.object_value = Some(v.clone());
2942 let _ = write!(self.cbor_location, "/{:?}", v);
2943 } else {
2944 self.add_error(format!("map requires entry key of type {}", ident));
2945 }
2946 return Ok(());
2947 }
2948
2949 if is_ident_integer_data_type(self.cddl, ident) && !self.validating_value {
2950 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Integer(_))) {
2951 self
2952 .validated_keys
2953 .get_or_insert(vec![k.clone()])
2954 .push(k.clone());
2955 self.object_value = Some(v.clone());
2956 let _ = write!(self.cbor_location, "/{:?}", v);
2957 } else {
2958 self.add_error(format!("map requires entry key of type {}", ident));
2959 }
2960 return Ok(());
2961 }
2962
2963 if is_ident_bool_data_type(self.cddl, ident) && !self.validating_value {
2964 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bool(_))) {
2965 self
2966 .validated_keys
2967 .get_or_insert(vec![k.clone()])
2968 .push(k.clone());
2969 self.object_value = Some(v.clone());
2970 let _ = write!(self.cbor_location, "/{:?}", v);
2971 } else {
2972 self.add_error(format!("map requires entry key of type {}", ident));
2973 }
2974 return Ok(());
2975 }
2976
2977 if is_ident_null_data_type(self.cddl, ident) && !self.validating_value {
2978 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
2979 self
2980 .validated_keys
2981 .get_or_insert(vec![k.clone()])
2982 .push(k.clone());
2983 self.object_value = Some(v.clone());
2984 let _ = write!(self.cbor_location, "/{:?}", v);
2985 } else {
2986 self.add_error(format!("map requires entry key of type {}", ident));
2987 }
2988 return Ok(());
2989 }
2990
2991 if is_ident_byte_string_data_type(self.cddl, ident) && !self.validating_value {
2992 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bytes(_))) {
2993 self
2994 .validated_keys
2995 .get_or_insert(vec![k.clone()])
2996 .push(k.clone());
2997 self.object_value = Some(v.clone());
2998 let _ = write!(self.cbor_location, "/{:?}", v);
2999 } else {
3000 self.add_error(format!("map requires entry key of type {}", ident));
3001 }
3002 return Ok(());
3003 }
3004
3005 if is_ident_float_data_type(self.cddl, ident) && !self.validating_value {
3006 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
3007 self
3008 .validated_keys
3009 .get_or_insert(vec![k.clone()])
3010 .push(k.clone());
3011 self.object_value = Some(v.clone());
3012 let _ = write!(self.cbor_location, "/{:?}", v);
3013 } else {
3014 self.add_error(format!("map requires entry key of type {}", ident));
3015 }
3016 return Ok(());
3017 }
3018
3019 if token::lookup_ident(ident.ident)
3020 .in_standard_prelude()
3021 .is_some()
3022 {
3023 self.add_error(format!(
3024 "expected object value of type {}, got object",
3025 ident.ident
3026 ));
3027 return Ok(());
3028 }
3029
3030 self.visit_value(&token::Value::TEXT(ident.ident.into()))
3031 }
3032 #[cfg(not(feature = "ast-span"))]
3033 Some(Occur::Optional {}) | None => {
3034 if is_ident_string_data_type(self.cddl, ident) && !self.validating_value {
3035 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Text(_))) {
3036 self
3037 .validated_keys
3038 .get_or_insert(vec![k.clone()])
3039 .push(k.clone());
3040 self.object_value = Some(v.clone());
3041 self.cbor_location.push_str(&format!("/{}", value));
3042 } else {
3043 self.add_error(format!("map requires entry key of type {}", ident));
3044 }
3045
3046 return Ok(());
3047 }
3048
3049 if is_ident_integer_data_type(self.cddl, ident) && !self.validating_value {
3050 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Integer(_))) {
3051 self
3052 .validated_keys
3053 .get_or_insert(vec![k.clone()])
3054 .push(k.clone());
3055 self.object_value = Some(v.clone());
3056 self.cbor_location.push_str(&format!("/{}", value));
3057 } else {
3058 self.add_error(format!("map requires entry key of type {}", ident));
3059 }
3060 return Ok(());
3061 }
3062
3063 if is_ident_bool_data_type(self.cddl, ident) && !self.validating_value {
3064 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bool(_))) {
3065 self
3066 .validated_keys
3067 .get_or_insert(vec![k.clone()])
3068 .push(k.clone());
3069 self.object_value = Some(v.clone());
3070 self.cbor_location.push_str(&format!("/{}", value));
3071 } else {
3072 self.add_error(format!("map requires entry key of type {}", ident));
3073 }
3074 return Ok(());
3075 }
3076
3077 if is_ident_null_data_type(self.cddl, ident) && !self.validating_value {
3078 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
3079 self
3080 .validated_keys
3081 .get_or_insert(vec![k.clone()])
3082 .push(k.clone());
3083 self.object_value = Some(v.clone());
3084 self.cbor_location.push_str(&format!("/{}", value));
3085 } else {
3086 self.add_error(format!("map requires entry key of type {}", ident));
3087 }
3088 return Ok(());
3089 }
3090
3091 if is_ident_byte_string_data_type(self.cddl, ident) && !self.validating_value {
3092 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bytes(_))) {
3093 self
3094 .validated_keys
3095 .get_or_insert(vec![k.clone()])
3096 .push(k.clone());
3097 self.object_value = Some(v.clone());
3098 self.cbor_location.push_str(&format!("/{}", value));
3099 } else {
3100 self.add_error(format!("map requires entry key of type {}", ident));
3101 }
3102 return Ok(());
3103 }
3104
3105 if is_ident_float_data_type(self.cddl, ident) && !self.validating_value {
3106 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
3107 self
3108 .validated_keys
3109 .get_or_insert(vec![k.clone()])
3110 .push(k.clone());
3111 self.object_value = Some(v.clone());
3112 self.cbor_location.push_str(&format!("/{}", value));
3113 } else {
3114 self.add_error(format!("map requires entry key of type {}", ident));
3115 }
3116 return Ok(());
3117 }
3118
3119 if token::lookup_ident(ident.ident)
3120 .in_standard_prelude()
3121 .is_some()
3122 {
3123 self.add_error(format!(
3124 "expected object value of type {}, got object",
3125 ident.ident
3126 ));
3127 return Ok(());
3128 }
3129
3130 self.visit_value(&token::Value::TEXT(ident.ident.into()))
3131 }
3132 Some(occur) => {
3133 let mut errors = Vec::new();
3134
3135 if is_ident_string_data_type(self.cddl, ident) {
3136 let values_to_validate = m
3137 .iter()
3138 .filter_map(|(k, v)| {
3139 if let Some(keys) = &self.validated_keys {
3140 if !keys.contains(k) {
3141 if matches!(k, Value::Text(_)) {
3142 Some(v.clone())
3143 } else {
3144 errors.push(format!("key of type {} required, got {:?}", ident, k));
3145 None
3146 }
3147 } else {
3148 None
3149 }
3150 } else if matches!(k, Value::Text(_)) {
3151 Some(v.clone())
3152 } else {
3153 errors.push(format!("key of type {} required, got {:?}", ident, k));
3154 None
3155 }
3156 })
3157 .collect::<Vec<_>>();
3158
3159 self.values_to_validate = Some(values_to_validate);
3160 }
3161
3162 if is_ident_integer_data_type(self.cddl, ident) {
3163 let mut errors = Vec::new();
3164 let values_to_validate = m
3165 .iter()
3166 .filter_map(|(k, v)| {
3167 if let Some(keys) = &self.validated_keys {
3168 if !keys.contains(k) {
3169 if matches!(k, Value::Integer(_)) {
3170 Some(v.clone())
3171 } else {
3172 errors.push(format!("key of type {} required, got {:?}", ident, k));
3173 None
3174 }
3175 } else {
3176 None
3177 }
3178 } else if matches!(k, Value::Integer(_)) {
3179 Some(v.clone())
3180 } else {
3181 errors.push(format!("key of type {} required, got {:?}", ident, k));
3182 None
3183 }
3184 })
3185 .collect::<Vec<_>>();
3186
3187 self.values_to_validate = Some(values_to_validate);
3188 }
3189
3190 if is_ident_bool_data_type(self.cddl, ident) {
3191 let mut errors = Vec::new();
3192 let values_to_validate = m
3193 .iter()
3194 .filter_map(|(k, v)| {
3195 if let Some(keys) = &self.validated_keys {
3196 if !keys.contains(k) {
3197 if matches!(k, Value::Bool(_)) {
3198 Some(v.clone())
3199 } else {
3200 errors.push(format!("key of type {} required, got {:?}", ident, k));
3201 None
3202 }
3203 } else {
3204 None
3205 }
3206 } else if matches!(k, Value::Bool(_)) {
3207 Some(v.clone())
3208 } else {
3209 errors.push(format!("key of type {} required, got {:?}", ident, k));
3210 None
3211 }
3212 })
3213 .collect::<Vec<_>>();
3214
3215 self.values_to_validate = Some(values_to_validate);
3216 }
3217
3218 if is_ident_byte_string_data_type(self.cddl, ident) {
3219 let mut errors = Vec::new();
3220 let values_to_validate = m
3221 .iter()
3222 .filter_map(|(k, v)| {
3223 if let Some(keys) = &self.validated_keys {
3224 if !keys.contains(k) {
3225 if matches!(k, Value::Bytes(_)) {
3226 Some(v.clone())
3227 } else {
3228 errors.push(format!("key of type {} required, got {:?}", ident, k));
3229 None
3230 }
3231 } else {
3232 None
3233 }
3234 } else if matches!(k, Value::Bytes(_)) {
3235 Some(v.clone())
3236 } else {
3237 errors.push(format!("key of type {} required, got {:?}", ident, k));
3238 None
3239 }
3240 })
3241 .collect::<Vec<_>>();
3242
3243 self.values_to_validate = Some(values_to_validate);
3244 }
3245
3246 if is_ident_null_data_type(self.cddl, ident) {
3247 let mut errors = Vec::new();
3248 let values_to_validate = m
3249 .iter()
3250 .filter_map(|(k, v)| {
3251 if let Some(keys) = &self.validated_keys {
3252 if !keys.contains(k) {
3253 if matches!(k, Value::Null) {
3254 Some(v.clone())
3255 } else {
3256 errors.push(format!("key of type {} required, got {:?}", ident, k));
3257 None
3258 }
3259 } else {
3260 None
3261 }
3262 } else if matches!(k, Value::Null) {
3263 Some(v.clone())
3264 } else {
3265 errors.push(format!("key of type {} required, got {:?}", ident, k));
3266 None
3267 }
3268 })
3269 .collect::<Vec<_>>();
3270
3271 self.values_to_validate = Some(values_to_validate);
3272 }
3273
3274 if is_ident_float_data_type(self.cddl, ident) {
3275 let mut errors = Vec::new();
3276 let values_to_validate = m
3277 .iter()
3278 .filter_map(|(k, v)| {
3279 if let Some(keys) = &self.validated_keys {
3280 if !keys.contains(k) {
3281 if matches!(k, Value::Float(_)) {
3282 Some(v.clone())
3283 } else {
3284 errors.push(format!("key of type {} required, got {:?}", ident, k));
3285 None
3286 }
3287 } else {
3288 None
3289 }
3290 } else if matches!(k, Value::Float(_)) {
3291 Some(v.clone())
3292 } else {
3293 errors.push(format!("key of type {} required, got {:?}", ident, k));
3294 None
3295 }
3296 })
3297 .collect::<Vec<_>>();
3298
3299 self.values_to_validate = Some(values_to_validate);
3300 }
3301
3302 if !errors.is_empty() {
3304 for e in errors.into_iter() {
3305 self.add_error(e);
3306 }
3307
3308 return Ok(());
3309 }
3310
3311 #[cfg(feature = "ast-span")]
3312 if let Occur::ZeroOrMore { .. } | Occur::OneOrMore { .. } = occur {
3313 if let Occur::OneOrMore { .. } = occur {
3314 if m.is_empty() {
3315 self.add_error(format!(
3316 "map cannot be empty, one or more entries with key type {} required",
3317 ident
3318 ));
3319 return Ok(());
3320 }
3321 }
3322 } else if let Occur::Exact { lower, upper, .. } = occur {
3323 if let Some(values_to_validate) = &self.values_to_validate {
3324 if let Some(lower) = lower {
3325 if let Some(upper) = upper {
3326 if values_to_validate.len() < *lower || values_to_validate.len() > *upper {
3327 if lower == upper {
3328 self.add_error(format!(
3329 "object must contain exactly {} entries of key of type {}",
3330 lower, ident,
3331 ));
3332 } else {
3333 self.add_error(format!(
3334 "object must contain between {} and {} entries of key of type {}",
3335 lower, upper, ident,
3336 ));
3337 }
3338
3339 return Ok(());
3340 }
3341 }
3342
3343 if values_to_validate.len() < *lower {
3344 self.add_error(format!(
3345 "object must contain at least {} entries of key of type {}",
3346 lower, ident,
3347 ));
3348
3349 return Ok(());
3350 }
3351 }
3352
3353 if let Some(upper) = upper {
3354 if values_to_validate.len() > *upper {
3355 self.add_error(format!(
3356 "object must contain no more than {} entries of key of type {}",
3357 upper, ident,
3358 ));
3359
3360 return Ok(());
3361 }
3362 }
3363
3364 return Ok(());
3365 }
3366 }
3367
3368 #[cfg(not(feature = "ast-span"))]
3369 if let Occur::ZeroOrMore {} | Occur::OneOrMore {} = occur {
3370 if let Occur::OneOrMore {} = occur {
3371 if m.is_empty() {
3372 self.add_error(format!(
3373 "object cannot be empty, one or more entries with key type {} required",
3374 ident
3375 ));
3376 return Ok(());
3377 }
3378 }
3379 } else if let Occur::Exact { lower, upper } = occur {
3380 if let Some(values_to_validate) = &self.values_to_validate {
3381 if let Some(lower) = lower {
3382 if let Some(upper) = upper {
3383 if values_to_validate.len() < *lower || values_to_validate.len() > *upper {
3384 if lower == upper {
3385 self.add_error(format!(
3386 "object must contain exactly {} entries of key of type {}",
3387 lower, ident,
3388 ));
3389 } else {
3390 self.add_error(format!(
3391 "object must contain between {} and {} entries of key of type {}",
3392 lower, upper, ident,
3393 ));
3394 }
3395
3396 return Ok(());
3397 }
3398 }
3399
3400 if values_to_validate.len() < *lower {
3401 self.add_error(format!(
3402 "object must contain at least {} entries of key of type {}",
3403 lower, ident,
3404 ));
3405
3406 return Ok(());
3407 }
3408 }
3409
3410 if let Some(upper) = upper {
3411 if values_to_validate.len() > *upper {
3412 self.add_error(format!(
3413 "object must contain no more than {} entries of key of type {}",
3414 upper, ident,
3415 ));
3416
3417 return Ok(());
3418 }
3419 }
3420
3421 return Ok(());
3422 }
3423 }
3424
3425 if is_ident_string_data_type(self.cddl, ident) && !self.validating_value {
3426 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Text(_))) {
3427 self
3428 .validated_keys
3429 .get_or_insert(vec![k.clone()])
3430 .push(k.clone());
3431 self.object_value = Some(v.clone());
3432 let _ = write!(self.cbor_location, "/{:?}", v);
3433 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3434 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3435 {
3436 self.add_error(format!("map requires entry key of type {}", ident));
3437 }
3438
3439 return Ok(());
3440 }
3441
3442 if is_ident_integer_data_type(self.cddl, ident) && !self.validating_value {
3443 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Integer(_))) {
3444 self
3445 .validated_keys
3446 .get_or_insert(vec![k.clone()])
3447 .push(k.clone());
3448 self.object_value = Some(v.clone());
3449 let _ = write!(self.cbor_location, "/{:?}", v);
3450 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3451 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3452 {
3453 self.add_error(format!("map requires entry key of type {}", ident));
3454 }
3455 return Ok(());
3456 }
3457
3458 if is_ident_bool_data_type(self.cddl, ident) && !self.validating_value {
3459 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bool(_))) {
3460 self
3461 .validated_keys
3462 .get_or_insert(vec![k.clone()])
3463 .push(k.clone());
3464 self.object_value = Some(v.clone());
3465 let _ = write!(self.cbor_location, "/{:?}", v);
3466 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3467 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3468 {
3469 self.add_error(format!("map requires entry key of type {}", ident));
3470 }
3471 return Ok(());
3472 }
3473
3474 if is_ident_null_data_type(self.cddl, ident) && !self.validating_value {
3475 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
3476 self
3477 .validated_keys
3478 .get_or_insert(vec![k.clone()])
3479 .push(k.clone());
3480 self.object_value = Some(v.clone());
3481 let _ = write!(self.cbor_location, "/{:?}", v);
3482 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3483 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3484 {
3485 self.add_error(format!("map requires entry key of type {}", ident));
3486 }
3487 return Ok(());
3488 }
3489
3490 if is_ident_byte_string_data_type(self.cddl, ident) && !self.validating_value {
3491 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Bytes(_))) {
3492 self
3493 .validated_keys
3494 .get_or_insert(vec![k.clone()])
3495 .push(k.clone());
3496 self.object_value = Some(v.clone());
3497 let _ = write!(self.cbor_location, "/{:?}", v);
3498 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3499 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3500 {
3501 self.add_error(format!("map requires entry key of type {}", ident));
3502 }
3503 return Ok(());
3504 }
3505
3506 if is_ident_float_data_type(self.cddl, ident) && !self.validating_value {
3507 if let Some((k, v)) = m.iter().find(|(k, _)| matches!(k, Value::Null)) {
3508 self
3509 .validated_keys
3510 .get_or_insert(vec![k.clone()])
3511 .push(k.clone());
3512 self.object_value = Some(v.clone());
3513 let _ = write!(self.cbor_location, "/{:?}", v);
3514 } else if (!matches!(occur, Occur::ZeroOrMore { .. }) && m.is_empty())
3515 || (matches!(occur, Occur::ZeroOrMore { .. }) && !m.is_empty())
3516 {
3517 self.add_error(format!("map requires entry key of type {}", ident));
3518 }
3519 return Ok(());
3520 }
3521
3522 if token::lookup_ident(ident.ident)
3523 .in_standard_prelude()
3524 .is_some()
3525 {
3526 self.add_error(format!(
3527 "expected object value of type {}, got object",
3528 ident.ident
3529 ));
3530 return Ok(());
3531 }
3532
3533 self.visit_value(&token::Value::TEXT(ident.ident.into()))
3534 }
3535 }
3536 }
3537 _ => {
3538 if let Some(cut_value) = self.cut_value.take() {
3539 self.add_error(format!(
3540 "cut present for member key {}. expected type {}, got {:?}",
3541 cut_value, ident, self.cbor
3542 ));
3543 } else {
3544 self.add_error(format!("expected type {}, got {:?}", ident, self.cbor));
3545 }
3546 Ok(())
3547 }
3548 }
3549 }
3550
3551 fn visit_value_member_key_entry(
3552 &mut self,
3553 entry: &ValueMemberKeyEntry<'a>,
3554 ) -> visitor::Result<Error<T>> {
3555 if let Some(occur) = &entry.occur {
3556 self.visit_occurrence(occur)?;
3557 }
3558
3559 let current_location = self.cbor_location.clone();
3560
3561 if let Some(mk) = &entry.member_key {
3562 let error_count = self.errors.len();
3563 self.is_member_key = true;
3564 self.visit_memberkey(mk)?;
3565 self.is_member_key = false;
3566
3567 if self.errors.len() != error_count {
3569 self.advance_to_next_entry = true;
3570 return Ok(());
3571 }
3572 }
3573
3574 if let Some(values) = &self.values_to_validate {
3575 for v in values.iter() {
3576 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
3577 let mut cv = CBORValidator::new(self.cddl, v.clone(), self.enabled_features.clone());
3578 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
3579 let mut cv = CBORValidator::new(self.cddl, v.clone(), self.enabled_features);
3580 #[cfg(not(feature = "additional-controls"))]
3581 let mut cv = CBORValidator::new(self.cddl, v.clone());
3582
3583 cv.generic_rules = self.generic_rules.clone();
3584 cv.eval_generic_rule = self.eval_generic_rule;
3585 cv.is_multi_type_choice = self.is_multi_type_choice;
3586 cv.is_multi_group_choice = self.is_multi_group_choice;
3587 cv.cbor_location.push_str(&self.cbor_location);
3588 cv.type_group_name_entry = self.type_group_name_entry;
3589 cv.validating_value = true;
3590 cv.visit_type(&entry.entry_type)?;
3591
3592 self.cbor_location = current_location.clone();
3593
3594 self.errors.append(&mut cv.errors);
3595 if entry.occur.is_some() {
3596 self.occurrence = None;
3597 }
3598 }
3599
3600 return Ok(());
3601 }
3602
3603 if let Some(v) = self.object_value.take() {
3604 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
3605 let mut cv = CBORValidator::new(self.cddl, v, self.enabled_features.clone());
3606 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
3607 let mut cv = CBORValidator::new(self.cddl, v, self.enabled_features);
3608 #[cfg(not(feature = "additional-controls"))]
3609 let mut cv = CBORValidator::new(self.cddl, v);
3610
3611 cv.generic_rules = self.generic_rules.clone();
3612 cv.eval_generic_rule = self.eval_generic_rule;
3613 cv.is_multi_type_choice = self.is_multi_type_choice;
3614 cv.is_multi_group_choice = self.is_multi_group_choice;
3615 cv.cbor_location.push_str(&self.cbor_location);
3616 cv.type_group_name_entry = self.type_group_name_entry;
3617 cv.visit_type(&entry.entry_type)?;
3618
3619 self.cbor_location = current_location;
3620
3621 self.errors.append(&mut cv.errors);
3622 if entry.occur.is_some() {
3623 self.occurrence = None;
3624 }
3625
3626 Ok(())
3627 } else if !self.advance_to_next_entry {
3628 self.visit_type(&entry.entry_type)
3629 } else {
3630 Ok(())
3631 }
3632 }
3633
3634 fn visit_type_groupname_entry(
3635 &mut self,
3636 entry: &TypeGroupnameEntry<'a>,
3637 ) -> visitor::Result<Error<T>> {
3638 self.type_group_name_entry = Some(entry.name.ident);
3639
3640 if let Some(ga) = &entry.generic_args {
3641 if let Some(rule) = rule_from_ident(self.cddl, &entry.name) {
3642 if let Some(gr) = self
3643 .generic_rules
3644 .iter_mut()
3645 .find(|gr| gr.name == entry.name.ident)
3646 {
3647 for arg in ga.args.iter() {
3648 gr.args.push((*arg.arg).clone());
3649 }
3650 } else if let Some(params) = generic_params_from_rule(rule) {
3651 self.generic_rules.push(GenericRule {
3652 name: entry.name.ident,
3653 params,
3654 args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(),
3655 });
3656 }
3657
3658 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
3659 let mut cv =
3660 CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features.clone());
3661 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
3662 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone(), self.enabled_features);
3663 #[cfg(not(feature = "additional-controls"))]
3664 let mut cv = CBORValidator::new(self.cddl, self.cbor.clone());
3665
3666 cv.generic_rules = self.generic_rules.clone();
3667 cv.eval_generic_rule = Some(entry.name.ident);
3668 cv.is_multi_type_choice = self.is_multi_type_choice;
3669 cv.visit_rule(rule)?;
3670
3671 self.errors.append(&mut cv.errors);
3672
3673 return Ok(());
3674 }
3675 }
3676
3677 let type_choice_alternates = type_choice_alternates_from_ident(self.cddl, &entry.name);
3678 if !type_choice_alternates.is_empty() {
3679 self.is_multi_type_choice = true;
3680 }
3681
3682 let error_count = self.errors.len();
3683 for t in type_choice_alternates {
3684 let cur_errors = self.errors.len();
3685 self.visit_type(t)?;
3686 if self.errors.len() == cur_errors {
3687 for _ in 0..self.errors.len() - error_count {
3688 self.errors.pop();
3689 }
3690
3691 return Ok(());
3692 }
3693 }
3694
3695 let error_count = self.errors.len();
3696 let group_choice_alternates = group_choice_alternates_from_ident(self.cddl, &entry.name);
3697 if !group_choice_alternates.is_empty() {
3698 self.is_multi_group_choice = true;
3699 }
3700
3701 for ge in group_choice_alternates {
3702 let cur_errors = self.errors.len();
3703 self.visit_group_entry(ge)?;
3704 if self.errors.len() == cur_errors {
3705 for _ in 0..self.errors.len() - error_count {
3706 self.errors.pop();
3707 }
3708
3709 return Ok(());
3710 }
3711 }
3712
3713 walk_type_groupname_entry(self, entry)?;
3714 self.type_group_name_entry = None;
3715
3716 Ok(())
3717 }
3718
3719 fn visit_memberkey(&mut self, mk: &MemberKey<'a>) -> visitor::Result<Error<T>> {
3720 match mk {
3721 MemberKey::Type1 { is_cut, .. } => {
3722 self.is_cut_present = *is_cut;
3723 walk_memberkey(self, mk)?;
3724 self.is_cut_present = false;
3725 }
3726 MemberKey::Bareword { .. } => {
3727 self.is_colon_shortcut_present = true;
3728 walk_memberkey(self, mk)?;
3729 self.is_colon_shortcut_present = false;
3730 }
3731 _ => return walk_memberkey(self, mk),
3732 }
3733
3734 Ok(())
3735 }
3736
3737 fn visit_value(&mut self, value: &token::Value<'a>) -> visitor::Result<Error<T>> {
3738 let error: Option<String> = match &self.cbor {
3739 Value::Integer(i) => match value {
3740 token::Value::INT(v) => match &self.ctrl {
3741 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT)
3742 if i128::from(*i) != *v as i128 =>
3743 {
3744 None
3745 }
3746 Some(ControlOperator::LT) if i128::from(*i) < *v as i128 => None,
3747 Some(ControlOperator::LE) if i128::from(*i) <= *v as i128 => None,
3748 Some(ControlOperator::GT) if i128::from(*i) > *v as i128 => None,
3749 Some(ControlOperator::GE) if i128::from(*i) >= *v as i128 => None,
3750 #[cfg(feature = "additional-controls")]
3751 Some(ControlOperator::PLUS) => {
3752 if i128::from(*i) == *v as i128 {
3753 None
3754 } else {
3755 Some(format!("expected computed .plus value {}, got {:?}", v, i))
3756 }
3757 }
3758 #[cfg(feature = "additional-controls")]
3759 None | Some(ControlOperator::FEATURE) => {
3760 if i128::from(*i) == *v as i128 {
3761 None
3762 } else {
3763 Some(format!("expected value {}, got {:?}", v, i))
3764 }
3765 }
3766 #[cfg(not(feature = "additional-controls"))]
3767 None => {
3768 if i128::from(*i) == *v as i128 {
3769 None
3770 } else {
3771 Some(format!("expected value {}, got {:?}", v, i))
3772 }
3773 }
3774 _ => Some(format!(
3775 "expected value {} {}, got {:?}",
3776 self.ctrl.unwrap(),
3777 v,
3778 i
3779 )),
3780 },
3781 token::Value::UINT(v) => match &self.ctrl {
3782 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT)
3783 if i128::from(*i) != *v as i128 =>
3784 {
3785 None
3786 }
3787 Some(ControlOperator::LT) if i128::from(*i) < *v as i128 => None,
3788 Some(ControlOperator::LE) if i128::from(*i) <= *v as i128 => None,
3789 Some(ControlOperator::GT) if i128::from(*i) > *v as i128 => None,
3790 Some(ControlOperator::GE) if i128::from(*i) >= *v as i128 => None,
3791 Some(ControlOperator::SIZE) => match 256i128.checked_pow(*v as u32) {
3792 Some(n) if i128::from(*i) < n => None,
3793 _ => Some(format!("expected value .size {}, got {:?}", v, i)),
3794 },
3795 Some(ControlOperator::BITS) => {
3796 if let Some(sv) = 1u32.checked_shl(*v as u32) {
3797 if (i128::from(*i) & sv as i128) != 0 {
3798 None
3799 } else {
3800 Some(format!("expected uint .bits {}, got {:?}", v, i))
3801 }
3802 } else {
3803 Some(format!("expected uint .bits {}, got {:?}", v, i))
3804 }
3805 }
3806 #[cfg(feature = "additional-controls")]
3807 Some(ControlOperator::PLUS) => {
3808 if i128::from(*i) == *v as i128 {
3809 None
3810 } else {
3811 Some(format!("expected computed .plus value {}, got {:?}", v, i))
3812 }
3813 }
3814 #[cfg(feature = "additional-controls")]
3815 None | Some(ControlOperator::FEATURE) => {
3816 if i128::from(*i) == *v as i128 {
3817 None
3818 } else {
3819 Some(format!("expected value {}, got {:?}", v, i))
3820 }
3821 }
3822 #[cfg(not(feature = "additional-controls"))]
3823 None => {
3824 if i128::from(*i) == *v as i128 {
3825 None
3826 } else {
3827 Some(format!("expected value {}, got {:?}", v, i))
3828 }
3829 }
3830 _ => Some(format!(
3831 "expected value {} {}, got {:?}",
3832 self.ctrl.unwrap(),
3833 v,
3834 i
3835 )),
3836 },
3837
3838 _ => Some(format!("expected {}, got {:?}", value, i)),
3839 },
3840 Value::Float(f) => match value {
3841 token::Value::FLOAT(v) => match &self.ctrl {
3842 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT)
3843 if (*f - *v).abs() > f64::EPSILON =>
3844 {
3845 None
3846 }
3847 Some(ControlOperator::LT) if *f < *v => None,
3848 Some(ControlOperator::LE) if *f <= *v => None,
3849 Some(ControlOperator::GT) if *f > *v => None,
3850 Some(ControlOperator::GE) if *f >= *v => None,
3851 #[cfg(feature = "additional-controls")]
3852 Some(ControlOperator::PLUS) => {
3853 if (*f - *v).abs() < f64::EPSILON {
3854 None
3855 } else {
3856 Some(format!("expected computed .plus value {}, got {:?}", v, f))
3857 }
3858 }
3859 #[cfg(feature = "additional-controls")]
3860 None | Some(ControlOperator::FEATURE) => {
3861 if (*f - *v).abs() < f64::EPSILON {
3862 None
3863 } else {
3864 Some(format!("expected value {}, got {:?}", v, f))
3865 }
3866 }
3867 #[cfg(not(feature = "additional-controls"))]
3868 None => {
3869 if (*f - *v).abs() < f64::EPSILON {
3870 None
3871 } else {
3872 Some(format!("expected value {}, got {:?}", v, f))
3873 }
3874 }
3875 _ => Some(format!(
3876 "expected value {} {}, got {:?}",
3877 self.ctrl.unwrap(),
3878 v,
3879 f
3880 )),
3881 },
3882 _ => Some(format!("expected {}, got {:?}", value, f)),
3883 },
3884 Value::Text(s) => match value {
3885 token::Value::TEXT(t) => match &self.ctrl {
3886 Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT) => {
3887 if s != t {
3888 None
3889 } else {
3890 Some(format!("expected {} .ne to \"{}\"", value, s))
3891 }
3892 }
3893 Some(ControlOperator::REGEXP) | Some(ControlOperator::PCRE) => {
3894 let re = regex::Regex::new(
3895 &format_regex(
3896 serde_json::from_str::<serde_json::Value>(&format!("\"{}\"", t))
3899 .map_err(Error::JSONParsing)?
3900 .as_str()
3901 .ok_or_else(|| Error::from_validator(self, "malformed regex".to_string()))?,
3902 )
3903 .ok_or_else(|| Error::from_validator(self, "malformed regex".to_string()))?,
3904 )
3905 .map_err(|e| Error::from_validator(self, e.to_string()))?;
3906
3907 if re.is_match(s) {
3908 None
3909 } else {
3910 Some(format!("expected \"{}\" to match regex \"{}\"", s, t))
3911 }
3912 }
3913 #[cfg(feature = "additional-controls")]
3914 Some(ControlOperator::ABNF) => validate_abnf(t, s)
3915 .err()
3916 .map(|e| format!("\"{}\" is not valid against abnf: {}", s, e)),
3917 _ => {
3918 #[cfg(feature = "additional-controls")]
3919 if s == t {
3920 None
3921 } else if let Some(ControlOperator::CAT) | Some(ControlOperator::DET) = &self.ctrl {
3922 Some(format!(
3923 "expected value to match concatenated string {}, got \"{}\"",
3924 value, s
3925 ))
3926 } else if let Some(ctrl) = &self.ctrl {
3927 Some(format!("expected value {} {}, got \"{}\"", ctrl, value, s))
3928 } else {
3929 Some(format!("expected value {} got \"{}\"", value, s))
3930 }
3931
3932 #[cfg(not(feature = "additional-controls"))]
3933 if s == t {
3934 None
3935 } else if let Some(ctrl) = &self.ctrl {
3936 Some(format!("expected value {} {}, got \"{}\"", ctrl, value, s))
3937 } else {
3938 Some(format!("expected value {} got \"{}\"", value, s))
3939 }
3940 }
3941 },
3942 token::Value::UINT(u) => match &self.ctrl {
3943 Some(ControlOperator::SIZE) => {
3944 if s.len() == *u {
3945 None
3946 } else {
3947 Some(format!("expected \"{}\" .size {}, got {}", s, u, s.len()))
3948 }
3949 }
3950 _ => Some(format!("expected {}, got {}", u, s)),
3951 },
3952 token::Value::BYTE(token::ByteValue::UTF8(b)) if s.as_bytes() == b.as_ref() => None,
3953 token::Value::BYTE(token::ByteValue::B16(b)) if s.as_bytes() == b.as_ref() => None,
3954 token::Value::BYTE(token::ByteValue::B64(b)) if s.as_bytes() == b.as_ref() => None,
3955 _ => Some(format!("expected {}, got \"{}\"", value, s)),
3956 },
3957 Value::Bytes(b) => match value {
3958 token::Value::UINT(v) => match &self.ctrl {
3959 Some(ControlOperator::SIZE) => {
3960 if let Some(range_upper) = self.range_upper.as_ref() {
3961 let len = b.len();
3962 if len < *v || len > *range_upper {
3963 Some(format!(
3964 "expected bytes .size to be in range {} <= value <= {}, got {}",
3965 v, range_upper, len
3966 ))
3967 } else {
3968 None
3969 }
3970 } else if b.len() == *v {
3971 None
3972 } else {
3973 Some(format!("expected \"{:?}\" .size {}, got {}", b, v, b.len()))
3974 }
3975 }
3976 Some(ControlOperator::BITS) => {
3977 if let Some(rsv) = v.checked_shr(3) {
3978 if let Some(s) = b.get(rsv) {
3979 if let Some(lsv) = 1u32.checked_shl(*v as u32 & 7) {
3980 if (*s as u32 & lsv) != 0 {
3981 None
3982 } else {
3983 Some(format!(
3984 "expected value {} {}, got {:?}",
3985 self.ctrl.unwrap(),
3986 v,
3987 b
3988 ))
3989 }
3990 } else {
3991 Some(format!(
3992 "expected value {} {}, got {:?}",
3993 self.ctrl.unwrap(),
3994 v,
3995 b
3996 ))
3997 }
3998 } else {
3999 Some(format!(
4000 "expected value {} {}, got {:?}",
4001 self.ctrl.unwrap(),
4002 v,
4003 b
4004 ))
4005 }
4006 } else {
4007 Some(format!(
4008 "expected value {} {}, got {:?}",
4009 self.ctrl.unwrap(),
4010 v,
4011 b
4012 ))
4013 }
4014 }
4015 _ => {
4016 if let Some(ctrl) = self.ctrl {
4017 Some(format!("expected value {} {}, got {:?}", ctrl, v, b))
4018 } else {
4019 Some(format!("expected value {}, got {:?}", v, b))
4020 }
4021 }
4022 },
4023 #[cfg(feature = "additional-controls")]
4024 token::Value::TEXT(t) => match &self.ctrl {
4025 Some(ControlOperator::ABNFB) => {
4026 validate_abnf(t, std::str::from_utf8(b).map_err(Error::UTF8Parsing)?)
4027 .err()
4028 .map(|e| {
4029 format!(
4030 "cbor bytes \"{:?}\" are not valid against abnf {}: {}",
4031 b, t, e
4032 )
4033 })
4034 }
4035 _ => Some(format!(
4036 "expected value {} {}, got {:?}",
4037 self.ctrl.unwrap(),
4038 t,
4039 b
4040 )),
4041 },
4042 #[cfg(feature = "additional-controls")]
4043 token::Value::BYTE(bv) => match &self.ctrl {
4044 Some(ControlOperator::ABNFB) => match bv {
4045 ByteValue::UTF8(utf8bv) => validate_abnf(
4046 std::str::from_utf8(utf8bv).map_err(Error::UTF8Parsing)?,
4047 std::str::from_utf8(b).map_err(Error::UTF8Parsing)?,
4048 )
4049 .err()
4050 .map(|e| {
4051 format!(
4052 "cbor bytes \"{:?}\" are not valid against abnf {}: {}",
4053 b, bv, e
4054 )
4055 }),
4056 ByteValue::B16(b16bv) => validate_abnf(
4057 std::str::from_utf8(&base16::decode(b16bv).map_err(Error::Base16Decoding)?)
4058 .map_err(Error::UTF8Parsing)?,
4059 std::str::from_utf8(b).map_err(Error::UTF8Parsing)?,
4060 )
4061 .err()
4062 .map(|e| {
4063 format!(
4064 "cbor bytes \"{:?}\" are not valid against abnf {}: {}",
4065 b, bv, e
4066 )
4067 }),
4068 ByteValue::B64(b64bv) => validate_abnf(
4069 std::str::from_utf8(
4070 &data_encoding::BASE64URL
4071 .decode(b64bv)
4072 .map_err(Error::Base64Decoding)?,
4073 )
4074 .map_err(Error::UTF8Parsing)?,
4075 std::str::from_utf8(b).map_err(Error::UTF8Parsing)?,
4076 )
4077 .err()
4078 .map(|e| {
4079 format!(
4080 "cbor bytes \"{:?}\" are not valid against abnf {}: {}",
4081 b, bv, e
4082 )
4083 }),
4084 },
4085 _ => Some(format!(
4086 "expected value {} {}, got {:?}",
4087 self.ctrl.unwrap(),
4088 bv,
4089 b
4090 )),
4091 },
4092 _ => Some(format!("expected {}, got {:?}", value, b)),
4093 },
4094 Value::Array(_) => {
4095 self.validate_array_items(&ArrayItemToken::Value(value))?;
4096
4097 None
4098 }
4099 Value::Map(o) => {
4100 if self.is_cut_present {
4101 self.cut_value = Some(Type1::from(value.clone()));
4102 }
4103
4104 if let token::Value::TEXT(Cow::Borrowed("any")) = value {
4105 return Ok(());
4106 }
4107
4108 let k = token_value_into_cbor_value(value.clone());
4111
4112 #[cfg(feature = "ast-span")]
4113 if let Some(v) = o
4114 .iter()
4115 .find_map(|entry| if entry.0 == k { Some(&entry.1) } else { None })
4116 {
4117 self.validated_keys.get_or_insert(vec![k.clone()]).push(k);
4118 self.object_value = Some(v.clone());
4119 let _ = write!(self.cbor_location, "/{}", value);
4120
4121 None
4122 } else if let Some(Occur::Optional { .. }) | Some(Occur::ZeroOrMore { .. }) =
4123 &self.occurrence.take()
4124 {
4125 self.advance_to_next_entry = true;
4126 None
4127 } else if let Some(ControlOperator::NE) | Some(ControlOperator::DEFAULT) = &self.ctrl {
4128 None
4129 } else {
4130 Some(format!("object missing key: \"{}\"", value))
4131 }
4132
4133 #[cfg(not(feature = "ast-span"))]
4134 if let Some(v) = o
4135 .iter()
4136 .find_map(|entry| if entry.0 == k { Some(&entry.1) } else { None })
4137 {
4138 self.validated_keys.get_or_insert(vec![k.clone()]).push(k);
4139 self.object_value = Some(v.clone());
4140 self.cbor_location.push_str(&format!("/{}", value));
4141
4142 None
4143 } else if let Some(Occur::Optional {}) | Some(Occur::ZeroOrMore {}) =
4144 &self.occurrence.take()
4145 {
4146 self.advance_to_next_entry = true;
4147 None
4148 } else if let Some(Token::NE) | Some(Token::DEFAULT) = &self.ctrl {
4149 None
4150 } else {
4151 Some(format!("object missing key: \"{}\"", value))
4152 }
4153 }
4154 _ => Some(format!("expected {}, got {:?}", value, self.cbor)),
4155 };
4156
4157 if let Some(e) = error {
4158 self.add_error(e);
4159 }
4160
4161 Ok(())
4162 }
4163
4164 fn visit_occurrence(&mut self, o: &Occurrence<'a>) -> visitor::Result<Error<T>> {
4165 self.occurrence = Some(o.occur);
4166
4167 Ok(())
4168 }
4169}
4170
4171pub fn token_value_into_cbor_value(value: token::Value) -> ciborium::value::Value {
4173 match value {
4174 token::Value::UINT(i) => ciborium::value::Value::Integer(i.into()),
4175 token::Value::INT(i) => ciborium::value::Value::Integer(i.into()),
4176 token::Value::FLOAT(f) => ciborium::value::Value::Float(f),
4177 token::Value::TEXT(t) => ciborium::value::Value::Text(t.to_string()),
4178 token::Value::BYTE(b) => match b {
4179 ByteValue::UTF8(b) | ByteValue::B16(b) | ByteValue::B64(b) => {
4180 ciborium::value::Value::Bytes(b.into_owned())
4181 }
4182 },
4183 }
4184}
4185
4186#[cfg(test)]
4187#[cfg(not(target_arch = "wasm32"))]
4188mod tests {
4189 use super::*;
4190 use ciborium::cbor;
4191 use indoc::indoc;
4192
4193 #[cfg(not(feature = "additional-controls"))]
4194 #[test]
4195 fn validate() -> std::result::Result<(), Box<dyn std::error::Error>> {
4196 let cddl = indoc!(
4197 r#"
4198 tcpflagbytes = bstr .bits flags
4199 flags = &(
4200 fin: 8,
4201 syn: 9,
4202 rst: 10,
4203 psh: 11,
4204 ack: 12,
4205 urg: 13,
4206 ece: 14,
4207 cwr: 15,
4208 ns: 0,
4209 ) / (4..7) ; data offset bits
4210 "#
4211 );
4212
4213 let cbor = ciborium::value::Value::Bytes(vec![0x90, 0x6d]);
4214
4215 let mut lexer = lexer_from_str(cddl);
4216 let cddl = cddl_from_str(&mut lexer, cddl, true)?;
4217
4218 let mut cv = CBORValidator::new(&cddl, cbor);
4219 cv.validate()?;
4220
4221 Ok(())
4222 }
4223
4224 #[cfg(feature = "additional-controls")]
4225 #[test]
4226 fn validate_abnfb_1() -> std::result::Result<(), Box<dyn std::error::Error>> {
4227 let cddl = indoc!(
4228 r#"
4229 oid = bytes .abnfb ("oid" .det cbor-tags-oid)
4230 roid = bytes .abnfb ("roid" .det cbor-tags-oid)
4231
4232 cbor-tags-oid = '
4233 oid = 1*arc
4234 roid = *arc
4235 arc = [nlsb] %x00-7f
4236 nlsb = %x81-ff *%x80-ff
4237 '
4238 "#
4239 );
4240
4241 let sha256_oid = "2.16.840.1.101.3.4.2.1";
4242
4243 let cbor = ciborium::value::Value::Bytes(sha256_oid.as_bytes().to_vec());
4244
4245 let cddl = cddl_from_str(cddl, true)?;
4246
4247 let mut cv = CBORValidator::new(&cddl, cbor, None);
4248 cv.validate()?;
4249
4250 Ok(())
4251 }
4252
4253 #[cfg(feature = "additional-controls")]
4254 #[test]
4255 fn validate_feature() -> std::result::Result<(), Box<dyn std::error::Error>> {
4256 let cddl = indoc!(
4257 r#"
4258 v = JC<"v", 2>
4259 JC<J, C> = J .feature "json" / C .feature "cbor"
4260 "#
4261 );
4262
4263 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4264 if let Err(e) = &cddl {
4265 println!("{}", e);
4266 }
4267
4268 let cbor = ciborium::value::Value::Integer(2.into());
4269
4270 let cddl = cddl.unwrap();
4271
4272 let mut cv = CBORValidator::new(&cddl, cbor, Some(&["cbor"]));
4273 cv.validate()?;
4274
4275 Ok(())
4276 }
4277
4278 #[test]
4279 fn validate_type_choice_alternate() -> std::result::Result<(), Box<dyn std::error::Error>> {
4280 let cddl = indoc!(
4281 r#"
4282 tester = [ $vals ]
4283 $vals /= 12
4284 $vals /= 13
4285 "#
4286 );
4287
4288 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4289 if let Err(e) = &cddl {
4290 println!("{}", e);
4291 }
4292
4293 let cbor = ciborium::cbor!([13]).unwrap();
4294
4295 let cddl = cddl.unwrap();
4296
4297 let mut cv = CBORValidator::new(&cddl, cbor, None);
4298 cv.validate()?;
4299
4300 Ok(())
4301 }
4302
4303 #[test]
4304 fn validate_group_choice_alternate_in_array(
4305 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
4306 let cddl = indoc!(
4307 r#"
4308 tester = [$$val]
4309 $$val //= (
4310 type: 10,
4311 data: uint
4312 )
4313 $$val //= (
4314 type: 11,
4315 data: tstr
4316 )
4317 "#
4318 );
4319
4320 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4321 if let Err(e) = &cddl {
4322 println!("{}", e);
4323 }
4324
4325 let cbor = ciborium::cbor!([11, "test"]).unwrap();
4326
4327 let cddl = cddl.unwrap();
4328
4329 let mut cv = CBORValidator::new(&cddl, cbor, None);
4330 cv.validate()?;
4331
4332 Ok(())
4333 }
4334
4335 #[test]
4336 fn validate_tdate_tag() -> std::result::Result<(), Box<dyn std::error::Error>> {
4337 let cddl = indoc!(
4338 r#"
4339 root = time
4340 "#
4341 );
4342
4343 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4344 if let Err(e) = &cddl {
4345 println!("{}", e);
4346 }
4347
4348 let cbor = ciborium::value::Value::Tag(
4349 1,
4350 Box::from(ciborium::value::Value::Float(1680965875.01_f64)),
4351 );
4352
4353 let cddl = cddl.unwrap();
4354
4355 let mut cv = CBORValidator::new(&cddl, cbor, None);
4356 cv.validate()?;
4357
4358 Ok(())
4359 }
4360
4361 #[test]
4362 fn validate_abnfb_2() -> std::result::Result<(), Box<dyn std::error::Error>> {
4363 let cddl = indoc!(
4364 r#"
4365 ; Binary ABNF Test Schema
4366 test_cbor = {
4367 61285: sub_map
4368 }
4369
4370 sub_map = {
4371 1: signature_abnf
4372 }
4373
4374 signature = bytes .size 64
4375
4376 signature_abnf = signature .abnfb '
4377 ANYDATA
4378 ANYDATA = *OCTET
4379
4380 OCTET = %x00-FF
4381 '
4382 "#
4383 );
4384
4385 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4386 if let Err(e) = &cddl {
4387 println!("{}", e);
4388 }
4389
4390 let cbor = ciborium::value::Value::Map(vec![(
4391 ciborium::value::Value::Integer(61285.into()),
4392 ciborium::value::Value::Map(vec![(
4393 ciborium::value::Value::Integer(1.into()),
4394 ciborium::value::Value::Bytes(b"test".to_vec()),
4395 )]),
4396 )]);
4397
4398 let cddl = cddl.unwrap();
4399
4400 let mut cv = CBORValidator::new(&cddl, cbor, None);
4401 cv.validate()?;
4402
4403 Ok(())
4404 }
4405
4406 #[test]
4407 fn multi_type_choice_type_rule_array_validation(
4408 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
4409 use ciborium::value::Value;
4410
4411 let cddl = indoc!(
4412 r#"
4413 Ref = nil / refShort / refFull
4414
4415 blobSize = uint
4416 hashID = uint .lt 23
4417 hashName = text
4418 hashDigest = bytes
4419
4420 refShort = [ blobSize, hashID, hashDigest ]
4421 refFull = { 1: blobSize, 2: hashName, 3: hashDigest }
4422 "#
4423 );
4424
4425 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4426 if let Err(e) = &cddl {
4427 println!("{}", e);
4428 }
4429
4430 let cbor = Value::Array(vec![
4431 Value::Integer(3.into()),
4432 Value::Integer(2.into()),
4433 Value::Bytes(
4434 base16::decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD").unwrap(),
4435 ),
4436 ]);
4437
4438 let cddl = cddl.unwrap();
4439
4440 let mut cv = CBORValidator::new(&cddl, cbor, None);
4441 cv.validate()?;
4442
4443 Ok(())
4444 }
4445
4446 #[test]
4447 fn tagged_data_in_array_validation() -> std::result::Result<(), Box<dyn std::error::Error>> {
4448 use ciborium::value::Value;
4449
4450 let cddl = indoc!(
4451 r#"
4452 start = [ * help ]
4453
4454 help = #6.123(bstr)
4455 "#
4456 );
4457
4458 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing);
4459 if let Err(e) = &cddl {
4460 println!("{}", e);
4461 }
4462
4463 let cbor = Value::Array(vec![Value::Tag(
4464 123,
4465 Box::from(Value::Bytes(base16::decode("00").unwrap())),
4466 )]);
4467
4468 let cddl = cddl.unwrap();
4469
4470 let mut cv = CBORValidator::new(&cddl, cbor, None);
4471 cv.validate()?;
4472
4473 Ok(())
4474 }
4475
4476 #[test]
4477 fn test_conditional_array_validation() {
4478 let cddl_str = r#"
4479 NestedPart = [
4480 disposition: 0,
4481 language: tstr,
4482 partIndex: uint,
4483 ( NullPart // SinglePart )
4484 ]
4485
4486 NullPart = ( cardinality: 0 )
4487 SinglePart = (
4488 cardinality: 1,
4489 contentType: tstr,
4490 content: bstr
4491 )
4492 "#;
4493
4494 let cddl = cddl_from_str(cddl_str, true).unwrap();
4495
4496 let cbor_data = Value::Array(vec![
4498 Value::Integer(0.into()), Value::Text("en".to_string()), Value::Integer(1.into()), Value::Integer(1.into()), Value::Text("text/plain".to_string()), Value::Bytes(b"hello world".to_vec()), ]);
4505
4506 #[cfg(all(feature = "additional-controls", target_arch = "wasm32"))]
4507 let mut validator = CBORValidator::new(&cddl, cbor_data, None);
4508 #[cfg(all(feature = "additional-controls", not(target_arch = "wasm32")))]
4509 let mut validator = CBORValidator::new(&cddl, cbor_data, None);
4510 #[cfg(not(feature = "additional-controls"))]
4511 let mut validator = CBORValidator::new(&cddl, cbor_data);
4512 let result = validator.validate();
4513
4514 assert!(
4516 result.is_ok(),
4517 "Validation should succeed for SinglePart structure: {:?}",
4518 result
4519 );
4520 }
4521
4522 #[test]
4523 fn extract_cbor() {
4524 use ciborium::value::Value;
4525
4526 let cbor = Value::Float(1.23);
4527 let cddl = cddl_from_str("start = any", true).unwrap();
4528 let cv = CBORValidator::new(&cddl, cbor, None);
4529 assert_eq!(cv.extract_cbor(), Value::Float(1.23));
4530 }
4531
4532 #[test]
4533 fn validate_bstr_size_range() -> std::result::Result<(), Box<dyn std::error::Error>> {
4534 let cddl = indoc!(
4535 r#"
4536 m = { field: bstr .size (16..1000) }
4537 "#
4538 );
4539
4540 let cddl = cddl_from_str(cddl, true)?;
4541
4542 let valid_bytes = vec![0u8; 100];
4544 let valid_cbor = ciborium::value::Value::Map(vec![(
4545 ciborium::value::Value::Text("field".to_string()),
4546 ciborium::value::Value::Bytes(valid_bytes),
4547 )]);
4548
4549 #[cfg(feature = "additional-controls")]
4550 let mut cv = CBORValidator::new(&cddl, valid_cbor, None);
4551 #[cfg(not(feature = "additional-controls"))]
4552 let mut cv = CBORValidator::new(&cddl, valid_cbor);
4553 assert!(cv.validate().is_ok());
4554
4555 let short_bytes = vec![0u8; 10];
4557 let short_cbor = ciborium::value::Value::Map(vec![(
4558 ciborium::value::Value::Text("field".to_string()),
4559 ciborium::value::Value::Bytes(short_bytes),
4560 )]);
4561
4562 #[cfg(feature = "additional-controls")]
4563 let mut cv = CBORValidator::new(&cddl, short_cbor, None);
4564 #[cfg(not(feature = "additional-controls"))]
4565 let mut cv = CBORValidator::new(&cddl, short_cbor);
4566 assert!(cv.validate().is_err());
4567
4568 let long_bytes = vec![0u8; 1500];
4570 let long_cbor = ciborium::value::Value::Map(vec![(
4571 ciborium::value::Value::Text("field".to_string()),
4572 ciborium::value::Value::Bytes(long_bytes),
4573 )]);
4574
4575 #[cfg(feature = "additional-controls")]
4576 let mut cv = CBORValidator::new(&cddl, long_cbor, None);
4577 #[cfg(not(feature = "additional-controls"))]
4578 let mut cv = CBORValidator::new(&cddl, long_cbor);
4579 assert!(cv.validate().is_err());
4580
4581 Ok(())
4582 }
4583
4584 #[test]
4585 fn validate_bstr_size_exclusive_range() -> std::result::Result<(), Box<dyn std::error::Error>> {
4586 let cddl = indoc!(
4587 r#"
4588 m = { field: bstr .size (16...1000) }
4589 "#
4590 );
4591
4592 let cddl = cddl_from_str(cddl, true)?;
4593
4594 let valid_bytes = vec![0u8; 17];
4596 let valid_cbor = ciborium::value::Value::Map(vec![(
4597 ciborium::value::Value::Text("field".to_string()),
4598 ciborium::value::Value::Bytes(valid_bytes),
4599 )]);
4600
4601 #[cfg(feature = "additional-controls")]
4602 let mut cv = CBORValidator::new(&cddl, valid_cbor, None);
4603 #[cfg(not(feature = "additional-controls"))]
4604 let mut cv = CBORValidator::new(&cddl, valid_cbor);
4605 assert!(cv.validate().is_ok());
4606
4607 let boundary_bytes = vec![0u8; 16];
4609 let boundary_cbor = ciborium::value::Value::Map(vec![(
4610 ciborium::value::Value::Text("field".to_string()),
4611 ciborium::value::Value::Bytes(boundary_bytes),
4612 )]);
4613
4614 #[cfg(feature = "additional-controls")]
4615 let mut cv = CBORValidator::new(&cddl, boundary_cbor, None);
4616 #[cfg(not(feature = "additional-controls"))]
4617 let mut cv = CBORValidator::new(&cddl, boundary_cbor);
4618 assert!(cv.validate().is_ok());
4619
4620 Ok(())
4621 }
4622
4623 #[test]
4624 fn validate_nested_cbor() -> std::result::Result<(), Box<dyn std::error::Error>> {
4625 let cddl = indoc!(
4626 r#"
4627 root = {
4628 foo: bstr .cbor bar
4629 }
4630
4631 bar = {
4632 a: text,
4633 b: int,
4634 c: bstr
4635 }
4636 "#
4637 );
4638
4639 let cddl = cddl_from_str(cddl, true)?;
4640
4641 let inner_cbor = ciborium::cbor!({
4643 "a" => "test",
4644 "b" => -42,
4645 "c" => Value::Bytes(b"bytes".to_vec())
4646 })?;
4647
4648 let mut inner_bytes = Vec::new();
4650 ciborium::ser::into_writer(&inner_cbor, &mut inner_bytes)?;
4651
4652 let outer_cbor = Value::Map(vec![(
4654 Value::Text("foo".to_string()),
4655 Value::Bytes(inner_bytes),
4656 )]);
4657
4658 #[cfg(feature = "additional-controls")]
4660 let mut cv = CBORValidator::new(&cddl, outer_cbor.clone(), None);
4661 #[cfg(not(feature = "additional-controls"))]
4662 let mut cv = CBORValidator::new(&cddl, outer_cbor.clone());
4663 assert!(cv.validate().is_ok());
4664
4665 let invalid_inner = ciborium::cbor!({
4667 "a" => "test",
4668 "b" => -42
4669 })?;
4671
4672 let mut invalid_bytes = Vec::new();
4673 ciborium::ser::into_writer(&invalid_inner, &mut invalid_bytes)?;
4674
4675 let invalid_outer = Value::Map(vec![(
4676 Value::Text("foo".to_string()),
4677 Value::Bytes(invalid_bytes),
4678 )]);
4679
4680 #[cfg(feature = "additional-controls")]
4681 let mut cv = CBORValidator::new(&cddl, invalid_outer, None);
4682 #[cfg(not(feature = "additional-controls"))]
4683 let mut cv = CBORValidator::new(&cddl, invalid_outer);
4684 assert!(cv.validate().is_err());
4685
4686 Ok(())
4687 }
4688
4689 #[test]
4690 fn validate_nested_cbor_in_array() -> std::result::Result<(), Box<dyn std::error::Error>> {
4691 let cddl = indoc!(
4692 r#"
4693 root = [
4694 foo: bstr .cbor bar
4695 ]
4696
4697 bar = {
4698 a: text,
4699 b: int,
4700 c: bstr
4701 }
4702 "#
4703 );
4704
4705 let cddl = cddl_from_str(cddl, true)?;
4706
4707 let inner_cbor = ciborium::cbor!({
4709 "a" => "test",
4710 "b" => -42,
4711 "c" => Value::Bytes(b"bytes".to_vec())
4712 })?;
4713
4714 let mut inner_bytes = Vec::new();
4716 ciborium::ser::into_writer(&inner_cbor, &mut inner_bytes)?;
4717
4718 let outer_cbor = Value::Array(vec![Value::Bytes(inner_bytes)]);
4720
4721 #[cfg(feature = "additional-controls")]
4723 let mut cv = CBORValidator::new(&cddl, outer_cbor.clone(), None);
4724 #[cfg(not(feature = "additional-controls"))]
4725 let mut cv = CBORValidator::new(&cddl, outer_cbor.clone());
4726 cv.validate()?;
4727 assert!(
4728 cv.validate().is_ok(),
4729 );
4731
4732 let invalid_inner = ciborium::cbor!({
4734 "a" => "test",
4735 "b" => -42
4736 })?;
4738
4739 let mut invalid_bytes = Vec::new();
4740 ciborium::ser::into_writer(&invalid_inner, &mut invalid_bytes)?;
4741
4742 let invalid_outer = Value::Array(vec![Value::Bytes(invalid_bytes)]);
4743
4744 #[cfg(feature = "additional-controls")]
4745 let mut cv = CBORValidator::new(&cddl, invalid_outer, None);
4746 #[cfg(not(feature = "additional-controls"))]
4747 let mut cv = CBORValidator::new(&cddl, invalid_outer);
4748 assert!(cv.validate().is_err());
4749
4750 Ok(())
4751 }
4752
4753 #[test]
4754 fn validate_nested_arrays() -> std::result::Result<(), Box<dyn std::error::Error>> {
4755 let cddl = indoc!(
4757 r#"
4758 array = [0, [* int]]
4759 "#
4760 );
4761
4762 let cbor = ciborium::cbor!([0, [1, 2]]).unwrap();
4763 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing)?;
4764
4765 let mut cv = CBORValidator::new(&cddl, cbor, None);
4766 cv.validate()?;
4767
4768 let cddl = indoc!(
4770 r#"
4771 root = [0, inner]
4772 inner = [* int]
4773 "#
4774 );
4775
4776 let cbor = ciborium::cbor!([0, [1, 2]]).unwrap();
4777 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing)?;
4778
4779 let mut cv = CBORValidator::new(&cddl, cbor, None);
4780 cv.validate()?;
4781
4782 let cddl = indoc!(
4784 r#"
4785 direct = [1, [2, 3]]
4786 "#
4787 );
4788
4789 let cbor = ciborium::cbor!([1, [2, 3]]).unwrap();
4790 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing)?;
4791
4792 let mut cv = CBORValidator::new(&cddl, cbor, None);
4793 cv.validate()?; Ok(())
4796 }
4797
4798 #[test]
4799 fn validate_direct_nested_array() -> std::result::Result<(), Box<dyn std::error::Error>> {
4800 let cddl = indoc!(
4802 r#"
4803 direct = [1, [2, 3]]
4804 "#
4805 );
4806
4807 let cbor = ciborium::cbor!([1, [2, 3]]).unwrap();
4808 let cddl = cddl_from_str(cddl, true).map_err(json::Error::CDDLParsing)?;
4809
4810 let mut cv = CBORValidator::new(&cddl, cbor, None);
4811
4812 match cv.validate() {
4814 Ok(_) => println!("Validation successful!"),
4815 Err(e) => {
4816 eprintln!("Validation error: {}", e);
4817 if let Error::Validation(errors) = &e {
4818 for (i, err) in errors.iter().enumerate() {
4819 eprintln!("Error {}: {} at {}", i, err.reason, err.cbor_location);
4820 }
4821 }
4822 return Err(e.into());
4823 }
4824 }
4825
4826 Ok(())
4827 }
4828
4829 #[test]
4830 fn validate_recursive_structures() -> std::result::Result<(), Box<dyn std::error::Error>> {
4831 let cddl = indoc!(
4833 r#"
4834 Tree = {
4835 root: Node
4836 }
4837
4838 Node = [
4839 value: text,
4840 children: [* Node]
4841 ]
4842 "#
4843 );
4844
4845 let cddl = cddl_from_str(cddl, true)?;
4846
4847 let cbor = ciborium::cbor!({
4849 "root" => ["value", [["child1", []], ["child2", []]]]
4850 })?;
4851
4852 #[cfg(feature = "additional-controls")]
4854 let mut cv = CBORValidator::new(&cddl, cbor, None);
4855 #[cfg(not(feature = "additional-controls"))]
4856 let mut cv = CBORValidator::new(&cddl, cbor);
4857
4858 let result = cv.validate();
4860
4861 assert!(
4863 result.is_ok(),
4864 "Recursive structure validation should not cause stack overflow"
4865 );
4866
4867 Ok(())
4868 }
4869
4870 #[test]
4871 fn test_issue_221_empty_map_with_extra_keys_cbor() {
4872 let cddl_str = "root = {}";
4878 let cddl = cddl_from_str(cddl_str, true).unwrap();
4879
4880 use ciborium::Value;
4882 let cbor_data = Value::Map(vec![(
4883 Value::Text("x".to_string()),
4884 Value::Text("y".to_string()),
4885 )]);
4886
4887 #[cfg(feature = "additional-controls")]
4888 let mut validator = CBORValidator::new(&cddl, cbor_data, None);
4889 #[cfg(not(feature = "additional-controls"))]
4890 let mut validator = CBORValidator::new(&cddl, cbor_data);
4891
4892 let result = validator.validate();
4894 assert!(
4895 result.is_err(),
4896 "CBOR validation should fail for extra keys in empty map schema"
4897 );
4898
4899 if let Err(Error::Validation(errors)) = result {
4901 assert_eq!(errors.len(), 1);
4902 assert!(errors[0].reason.contains("expected empty map"));
4903 } else {
4904 panic!("Expected validation error but got something else");
4905 }
4906 }
4907
4908 #[test]
4909 fn test_empty_map_schema_with_empty_cbor() -> std::result::Result<(), Box<dyn std::error::Error>>
4910 {
4911 let cddl_str = "root = {}";
4913 let cddl = cddl_from_str(cddl_str, true)?;
4914
4915 use ciborium::Value;
4917 let cbor_data = Value::Map(vec![]);
4918
4919 #[cfg(feature = "additional-controls")]
4920 let mut validator = CBORValidator::new(&cddl, cbor_data, None);
4921 #[cfg(not(feature = "additional-controls"))]
4922 let mut validator = CBORValidator::new(&cddl, cbor_data);
4923
4924 let result = validator.validate();
4925 assert!(
4926 result.is_ok(),
4927 "CBOR validation should pass for empty map with empty map schema"
4928 );
4929
4930 Ok(())
4931 }
4932
4933 #[test]
4934 fn test_issue_221_reproduce_exact_scenario_cbor(
4935 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
4936 let cddl_str = "root = {}";
4938 let cddl = cddl_from_str(cddl_str, true)?;
4939
4940 use ciborium::Value;
4942 let cbor_data = Value::Map(vec![(
4943 Value::Text("x".to_string()),
4944 Value::Text("y".to_string()),
4945 )]);
4946
4947 #[cfg(feature = "additional-controls")]
4948 let mut validator = CBORValidator::new(&cddl, cbor_data, None);
4949 #[cfg(not(feature = "additional-controls"))]
4950 let mut validator = CBORValidator::new(&cddl, cbor_data);
4951
4952 let result = validator.validate();
4953
4954 match result {
4956 Err(Error::Validation(errors)) => {
4957 assert!(!errors.is_empty(), "Should have validation errors");
4958 let error_message = &errors[0].reason;
4959 assert!(
4960 error_message.contains("expected empty map"),
4961 "Error message should indicate expected empty map, got: {}",
4962 error_message
4963 );
4964 }
4965 Ok(_) => panic!(
4966 "Issue #221 bug detected: CBOR validation incorrectly passed for extra keys in empty map"
4967 ),
4968 Err(other) => panic!("Unexpected error type: {:?}", other),
4969 }
4970
4971 Ok(())
4972 }
4973}