1use crate::{
2 Dbc, Error, MAX_MESSAGES, MAX_SIGNALS_PER_MESSAGE, Message, Nodes, Parser, Result, Signal,
3 Version,
4 compat::Vec,
5 dbc::{Messages, Validate},
6};
7#[cfg(feature = "std")]
8use crate::{ValueDescriptions, dbc::ValueDescriptionsMap};
9#[cfg(feature = "std")]
10use std::collections::BTreeMap;
11
12impl Dbc {
13 pub fn parse(data: &str) -> Result<Self> {
32 let mut parser = Parser::new(data.as_bytes())?;
33
34 let mut messages_buffer: Vec<Message, { MAX_MESSAGES }> = Vec::new();
35
36 let mut message_count_actual = 0;
37
38 use crate::{
40 BA_, BA_DEF_, BA_DEF_DEF_, BO_, BO_TX_BU_, BS_, BU_, CM_, EV_, NS_, SG_, SIG_GROUP_,
41 SIG_VALTYPE_, VAL_, VAL_TABLE_, VERSION,
42 };
43
44 let mut version: Option<Version> = None;
45 let mut nodes: Option<Nodes> = None;
46
47 #[cfg(feature = "std")]
49 type ValueDescriptionsBufferEntry = (
50 Option<u32>,
51 std::string::String,
52 std::vec::Vec<(u64, std::string::String)>,
53 );
54 #[cfg(feature = "std")]
55 let mut value_descriptions_buffer: std::vec::Vec<ValueDescriptionsBufferEntry> =
56 std::vec::Vec::new();
57
58 loop {
59 parser.skip_newlines_and_spaces();
61 if parser.starts_with(b"//") {
62 parser.skip_to_end_of_line();
63 continue;
64 }
65
66 let keyword_result = parser.peek_next_keyword();
67 let keyword = match keyword_result {
68 Ok(kw) => kw,
69 Err(Error::UnexpectedEof) => break,
70 Err(Error::Expected(_)) => {
71 if parser.starts_with(b"//") {
72 parser.skip_to_end_of_line();
73 continue;
74 }
75 return Err(keyword_result.unwrap_err());
76 }
77 Err(e) => return Err(e),
78 };
79
80 let pos_at_keyword = parser.pos();
82
83 match keyword {
84 NS_ => {
85 parser
87 .expect(crate::NS_.as_bytes())
88 .map_err(|_| Error::Expected("Failed to consume NS_ keyword"))?;
89 parser.skip_newlines_and_spaces();
90 let _ = parser.expect(b":").ok();
91 loop {
92 parser.skip_newlines_and_spaces();
93 if parser.is_empty() {
94 break;
95 }
96 if parser.starts_with(b" ") || parser.starts_with(b"\t") {
97 parser.skip_to_end_of_line();
98 continue;
99 }
100 if parser.starts_with(b"//") {
101 parser.skip_to_end_of_line();
102 continue;
103 }
104 if parser.starts_with(BS_.as_bytes())
105 || parser.starts_with(BU_.as_bytes())
106 || parser.starts_with(BO_.as_bytes())
107 || parser.starts_with(SG_.as_bytes())
108 || parser.starts_with(VERSION.as_bytes())
109 {
110 break;
111 }
112 parser.skip_to_end_of_line();
113 }
114 continue;
115 }
116 CM_ | BS_ | VAL_TABLE_ | BA_DEF_ | BA_DEF_DEF_ | BA_ | SIG_GROUP_
117 | SIG_VALTYPE_ | EV_ | BO_TX_BU_ => {
118 let _ = parser.expect(keyword.as_bytes()).ok();
120 parser.skip_to_end_of_line();
121 continue;
122 }
123 VAL_ => {
124 #[cfg(feature = "std")]
125 {
126 let _ = parser.expect(crate::VAL_.as_bytes()).ok();
128 parser.skip_newlines_and_spaces();
132 let message_id = match parser.parse_i64() {
133 Ok(id) => {
134 if id == -1 {
136 None
137 } else if id >= 0 && id <= u32::MAX as i64 {
138 Some(id as u32)
139 } else {
140 parser.skip_to_end_of_line();
141 continue;
142 }
143 }
144 Err(_) => {
145 parser.skip_to_end_of_line();
146 continue;
147 }
148 };
149 parser.skip_newlines_and_spaces();
150 let signal_name = match parser.parse_identifier() {
151 Ok(name) => name.to_string(),
152 Err(_) => {
153 parser.skip_to_end_of_line();
154 continue;
155 }
156 };
157 let mut entries: std::vec::Vec<(u64, std::string::String)> =
159 std::vec::Vec::new();
160 loop {
161 parser.skip_newlines_and_spaces();
162 if parser.starts_with(b";") {
164 parser.expect(b";").ok();
165 break;
166 }
167 let value = match parser.parse_i64() {
171 Ok(v) => {
172 if v == -1 { 0xFFFF_FFFFu64 } else { v as u64 }
174 }
175 Err(_) => {
176 parser.skip_to_end_of_line();
177 break;
178 }
179 };
180 parser.skip_newlines_and_spaces();
181 if parser.expect(b"\"").is_err() {
183 parser.skip_to_end_of_line();
184 break;
185 }
186 let description_bytes = match parser.take_until_quote(false, 1024) {
187 Ok(bytes) => bytes,
188 Err(_) => {
189 parser.skip_to_end_of_line();
190 break;
191 }
192 };
193 let description = match core::str::from_utf8(description_bytes) {
194 Ok(s) => s.to_string(),
195 Err(_) => {
196 parser.skip_to_end_of_line();
197 break;
198 }
199 };
200 entries.push((value, description));
201 }
202 if !entries.is_empty() {
203 value_descriptions_buffer.push((message_id, signal_name, entries));
204 }
205 }
206 #[cfg(not(feature = "std"))]
207 {
208 let _ = parser.expect(crate::VAL_.as_bytes()).ok();
210 parser.skip_to_end_of_line();
211 }
212 continue;
213 }
214 VERSION => {
215 version = Some(Version::parse(&mut parser)?);
217 continue;
218 }
219 BU_ => {
220 parser.skip_to_end_of_line();
222 let bu_input = &data.as_bytes()[pos_at_keyword..parser.pos()];
223 let mut bu_parser = Parser::new(bu_input)?;
224 nodes = Some(Nodes::parse(&mut bu_parser)?);
225 continue;
226 }
227 BO_ => {
228 if message_count_actual >= MAX_MESSAGES {
230 return Err(Error::Nodes(Error::NODES_TOO_MANY));
231 }
232
233 let message_start_pos = pos_at_keyword;
235
236 let header_line_end = {
239 let mut temp_parser = Parser::new(&data.as_bytes()[pos_at_keyword..])?;
241 temp_parser.expect(crate::BO_.as_bytes()).ok();
243 temp_parser.skip_whitespace().ok();
244 temp_parser.parse_u32().ok(); temp_parser.skip_whitespace().ok();
246 temp_parser.parse_identifier().ok(); temp_parser.skip_whitespace().ok();
248 temp_parser.expect(b":").ok(); temp_parser.skip_whitespace().ok();
250 temp_parser.parse_u8().ok(); temp_parser.skip_whitespace().ok();
252 temp_parser.parse_identifier().ok(); pos_at_keyword + temp_parser.pos()
254 };
255
256 parser.skip_to_end_of_line(); let mut signals_array: Vec<Signal, { MAX_SIGNALS_PER_MESSAGE }> = Vec::new();
260
261 loop {
262 parser.skip_newlines_and_spaces();
263 if parser.starts_with(crate::SG_.as_bytes()) {
264 if let Some(next_byte) = parser.peek_byte_at(3) {
265 if matches!(next_byte, b' ' | b'\n' | b'\r' | b'\t') {
266 if signals_array.len() >= MAX_SIGNALS_PER_MESSAGE {
267 return Err(Error::Receivers(
268 Error::SIGNAL_RECEIVERS_TOO_MANY,
269 ));
270 }
271 let signal = Signal::parse(&mut parser)?;
273 signals_array.push(signal).map_err(|_| {
274 Error::Receivers(Error::SIGNAL_RECEIVERS_TOO_MANY)
275 })?;
276 continue;
277 }
278 }
279 }
280 break;
281 }
282
283 let message_input = &data.as_bytes()[message_start_pos..header_line_end];
287 let mut message_parser = Parser::new(message_input)?;
288
289 let message = Message::parse(&mut message_parser, signals_array.as_slice())?;
291
292 messages_buffer
293 .push(message)
294 .map_err(|_| Error::Message(Error::NODES_TOO_MANY))?;
295 message_count_actual += 1;
296 continue;
297 }
298 SG_ => {
299 parser.skip_to_end_of_line();
301 continue;
302 }
303 _ => {
304 parser.skip_to_end_of_line();
305 continue;
306 }
307 }
308 }
309
310 let nodes = nodes.unwrap_or_default();
312
313 let version = version.or_else(|| {
315 static EMPTY_VERSION: &[u8] = b"VERSION \"\"";
316 let mut parser = Parser::new(EMPTY_VERSION).ok()?;
317 Version::parse(&mut parser).ok()
318 });
319
320 #[cfg(feature = "std")]
322 let value_descriptions_map = {
323 let mut map: BTreeMap<(Option<u32>, std::string::String), ValueDescriptions> =
324 BTreeMap::new();
325 for (message_id, signal_name, entries) in value_descriptions_buffer {
326 let key = (message_id, signal_name);
327 let value_descriptions = ValueDescriptions::from_slice(&entries);
328 map.insert(key, value_descriptions);
329 }
330 ValueDescriptionsMap::from_map(map)
331 };
332
333 let messages_slice: &[Message] = messages_buffer.as_slice();
335
336 #[cfg(feature = "std")]
338 Validate::validate(&nodes, messages_slice, Some(&value_descriptions_map)).map_err(|e| {
339 crate::error::map_val_error(e, Error::Message, || {
340 Error::Message(Error::MESSAGE_ERROR_PREFIX)
341 })
342 })?;
343 #[cfg(not(feature = "std"))]
344 Validate::validate(&nodes, messages_slice).map_err(|e| {
345 crate::error::map_val_error(e, Error::Message, || {
346 Error::Message(Error::MESSAGE_ERROR_PREFIX)
347 })
348 })?;
349
350 let messages = Messages::new(messages_slice)?;
352 #[cfg(feature = "std")]
353 let dbc = Dbc::new(version, nodes, messages, value_descriptions_map);
354 #[cfg(not(feature = "std"))]
355 let dbc = Dbc::new(version, nodes, messages);
356 Ok(dbc)
357 }
358
359 pub fn parse_bytes(data: &[u8]) -> Result<Dbc> {
372 let content =
373 core::str::from_utf8(data).map_err(|_e| Error::Expected(Error::INVALID_UTF8))?;
374 Dbc::parse(content)
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use crate::Dbc;
381
382 #[test]
383 fn test_parse_basic() {
384 let dbc_content = r#"VERSION "1.0"
385
386BU_: ECM
387
388BO_ 256 Engine : 8 ECM
389 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
390"#;
391 let dbc = Dbc::parse(dbc_content).unwrap();
392 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
393 assert!(dbc.nodes().contains("ECM"));
394 assert_eq!(dbc.messages().len(), 1);
395 }
396
397 #[test]
398 fn test_parse_bytes() {
399 let dbc_bytes = b"VERSION \"1.0\"\n\nBU_: ECM\n\nBO_ 256 Engine : 8 ECM";
400 let dbc = Dbc::parse_bytes(dbc_bytes).unwrap();
401 assert_eq!(dbc.version().map(|v| v.as_str()), Some("1.0"));
402 assert!(dbc.nodes().contains("ECM"));
403 assert_eq!(dbc.messages().len(), 1);
404 }
405
406 #[test]
407 fn test_parse_empty_nodes() {
408 let dbc_content = r#"VERSION "1.0"
409
410BU_:
411
412BO_ 256 Engine : 8 ECM
413"#;
414 let dbc = Dbc::parse(dbc_content).unwrap();
415 assert!(dbc.nodes().is_empty());
416 }
417
418 #[test]
419 fn test_parse_no_version() {
420 let dbc_content = r#"BU_: ECM
421
422BO_ 256 Engine : 8 ECM
423"#;
424 let dbc = Dbc::parse(dbc_content).unwrap();
425 assert!(dbc.version().is_some());
427 }
428
429 #[test]
430 fn parses_real_dbc() {
431 let data = r#"VERSION "1.0"
432
433BU_: ECM TCM
434
435BO_ 256 Engine : 8 ECM
436 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
437 SG_ Temp : 16|8@0- (1,-40) [-40|215] "°C"
438
439BO_ 512 Brake : 4 TCM
440 SG_ Pressure : 0|16@1+ (0.1,0) [0|1000] "bar""#;
441
442 let dbc = Dbc::parse(data).unwrap();
443 assert_eq!(dbc.messages().len(), 2);
444 let mut messages_iter = dbc.messages().iter();
445 let msg0 = messages_iter.next().unwrap();
446 assert_eq!(msg0.signals().len(), 2);
447 let mut signals_iter = msg0.signals().iter();
448 assert_eq!(signals_iter.next().unwrap().name(), "RPM");
449 assert_eq!(signals_iter.next().unwrap().name(), "Temp");
450 let msg1 = messages_iter.next().unwrap();
451 assert_eq!(msg1.signals().len(), 1);
452 assert_eq!(msg1.signals().iter().next().unwrap().name(), "Pressure");
453 }
454
455 #[test]
456 fn test_parse_duplicate_message_id() {
457 use crate::Error;
458 let data = r#"VERSION "1.0"
460
461BU_: ECM
462
463BO_ 256 EngineData1 : 8 ECM
464 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
465
466BO_ 256 EngineData2 : 8 ECM
467 SG_ Temp : 16|8@0- (1,-40) [-40|215] "°C"
468"#;
469
470 let result = Dbc::parse(data);
471 assert!(result.is_err());
472 match result.unwrap_err() {
473 Error::Message(msg) => {
474 assert!(msg.contains(Error::DUPLICATE_MESSAGE_ID));
475 }
476 _ => panic!("Expected Error::Message"),
477 }
478 }
479
480 #[test]
481 fn test_parse_sender_not_in_nodes() {
482 use crate::Error;
483 let data = r#"VERSION "1.0"
485
486BU_: ECM
487
488BO_ 256 EngineData : 8 TCM
489 SG_ RPM : 0|16@0+ (0.25,0) [0|8000] "rpm"
490"#;
491
492 let result = Dbc::parse(data);
493 assert!(result.is_err());
494 match result.unwrap_err() {
495 Error::Message(msg) => {
496 assert!(msg.contains(Error::SENDER_NOT_IN_NODES));
497 }
498 _ => panic!("Expected Error::Message"),
499 }
500 }
501
502 #[test]
503 fn test_parse_empty_file() {
504 use crate::Error;
505 let result = Dbc::parse("");
507 assert!(result.is_err());
508 match result.unwrap_err() {
509 Error::UnexpectedEof => {
510 }
512 _ => panic!("Expected Error::UnexpectedEof"),
513 }
514 }
515
516 #[test]
517 fn test_parse_bytes_invalid_utf8() {
518 use crate::Error;
519 let invalid_bytes = &[0xFF, 0xFE, 0xFD];
521 let result = Dbc::parse_bytes(invalid_bytes);
522 assert!(result.is_err());
523 match result.unwrap_err() {
524 Error::Expected(msg) => {
525 assert_eq!(msg, Error::INVALID_UTF8);
526 }
527 _ => panic!("Expected Error::Expected with INVALID_UTF8"),
528 }
529 }
530
531 #[test]
532 fn test_parse_without_version_with_comment() {
533 let data = r#"// This is a comment
535BU_: ECM
536
537BO_ 256 Engine : 8 ECM
538 SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm"
539"#;
540 let dbc = Dbc::parse(data).unwrap();
541 assert_eq!(dbc.version().map(|v| v.as_str()), Some(""));
542 }
543
544 #[test]
545 fn test_parse_with_strict_boundary_check() {
546 let data = r#"VERSION "1.0"
548
549BU_: ECM
550
551BO_ 256 Test : 8 ECM
552 SG_ CHECKSUM : 63|8@1+ (1,0) [0|255] ""
553"#;
554
555 let result = Dbc::parse(data);
557 assert!(result.is_err());
558 }
559
560 #[cfg(feature = "std")]
561 #[test]
562 fn test_parse_val_value_descriptions() {
563 let data = r#"VERSION ""
564
565NS_ :
566
567BS_:
568
569BU_: Node1 Node2
570
571BO_ 100 Message1 : 8 Node1
572 SG_ Signal : 32|8@1- (1,0) [-1|4] "Gear" Node2
573
574VAL_ 100 Signal -1 "Reverse" 0 "Neutral" 1 "First" 2 "Second" 3 "Third" 4 "Fourth" ;
575"#;
576
577 let dbc = match Dbc::parse(data) {
578 Ok(dbc) => dbc,
579 Err(e) => panic!("Failed to parse DBC: {:?}", e),
580 };
581
582 assert_eq!(dbc.messages().len(), 1);
584 let message = dbc.messages().iter().find(|m| m.id() == 100).unwrap();
585 assert_eq!(message.name(), "Message1");
586 assert_eq!(message.sender(), "Node1");
587
588 let value_descriptions = dbc
590 .value_descriptions_for_signal(100, "Signal")
591 .expect("Value descriptions should exist");
592 assert_eq!(value_descriptions.get(0xFFFFFFFF), Some("Reverse")); assert_eq!(value_descriptions.get(0), Some("Neutral"));
594 assert_eq!(value_descriptions.get(1), Some("First"));
595 assert_eq!(value_descriptions.get(2), Some("Second"));
596 assert_eq!(value_descriptions.get(3), Some("Third"));
597 assert_eq!(value_descriptions.get(4), Some("Fourth"));
598 }
599
600 #[cfg(feature = "std")]
601 #[test]
602 fn test_parse_val_global_value_descriptions() {
603 let data = r#"VERSION "1.0"
605
606NS_ :
607
608 VAL_
609
610BS_:
611
612BU_: ECU DASH
613
614BO_ 256 EngineData: 8 ECU
615 SG_ EngineRPM : 0|16@1+ (0.125,0) [0|8000] "rpm" Vector__XXX
616 SG_ DI_gear : 24|3@1+ (1,0) [0|7] "" Vector__XXX
617
618BO_ 512 DashboardDisplay: 8 DASH
619 SG_ DI_gear : 0|3@1+ (1,0) [0|7] "" Vector__XXX
620 SG_ SpeedDisplay : 8|16@1+ (0.01,0) [0|300] "km/h" Vector__XXX
621
622VAL_ -1 DI_gear 0 "INVALID" 1 "P" 2 "R" 3 "N" 4 "D" 5 "S" 6 "L" 7 "SNA" ;
623"#;
624
625 let dbc = match Dbc::parse(data) {
626 Ok(dbc) => dbc,
627 Err(e) => panic!("Failed to parse DBC: {:?}", e),
628 };
629
630 assert_eq!(dbc.messages().len(), 2);
632
633 let engine_msg = dbc.messages().iter().find(|m| m.id() == 256).unwrap();
635 assert_eq!(engine_msg.name(), "EngineData");
636 assert_eq!(engine_msg.sender(), "ECU");
637 let di_gear_signal1 = engine_msg.signals().find("DI_gear").unwrap();
638 assert_eq!(di_gear_signal1.name(), "DI_gear");
639 assert_eq!(di_gear_signal1.start_bit(), 24);
640
641 let dash_msg = dbc.messages().iter().find(|m| m.id() == 512).unwrap();
643 assert_eq!(dash_msg.name(), "DashboardDisplay");
644 assert_eq!(dash_msg.sender(), "DASH");
645 let di_gear_signal2 = dash_msg.signals().find("DI_gear").unwrap();
646 assert_eq!(di_gear_signal2.name(), "DI_gear");
647 assert_eq!(di_gear_signal2.start_bit(), 0);
648
649 let value_descriptions1 = dbc
651 .value_descriptions_for_signal(256, "DI_gear")
652 .expect("Global value descriptions should exist for DI_gear in message 256");
653
654 assert_eq!(value_descriptions1.get(0), Some("INVALID"));
655 assert_eq!(value_descriptions1.get(1), Some("P"));
656 assert_eq!(value_descriptions1.get(2), Some("R"));
657 assert_eq!(value_descriptions1.get(3), Some("N"));
658 assert_eq!(value_descriptions1.get(4), Some("D"));
659 assert_eq!(value_descriptions1.get(5), Some("S"));
660 assert_eq!(value_descriptions1.get(6), Some("L"));
661 assert_eq!(value_descriptions1.get(7), Some("SNA"));
662
663 let value_descriptions2 = dbc
665 .value_descriptions_for_signal(512, "DI_gear")
666 .expect("Global value descriptions should exist for DI_gear in message 512");
667
668 assert_eq!(value_descriptions2.get(0), Some("INVALID"));
670 assert_eq!(value_descriptions2.get(1), Some("P"));
671 assert_eq!(value_descriptions2.get(2), Some("R"));
672 assert_eq!(value_descriptions2.get(3), Some("N"));
673 assert_eq!(value_descriptions2.get(4), Some("D"));
674 assert_eq!(value_descriptions2.get(5), Some("S"));
675 assert_eq!(value_descriptions2.get(6), Some("L"));
676 assert_eq!(value_descriptions2.get(7), Some("SNA"));
677
678 assert_eq!(value_descriptions1.len(), value_descriptions2.len());
681 assert_eq!(value_descriptions1.len(), 8);
682
683 assert_eq!(dbc.value_descriptions_for_signal(256, "EngineRPM"), None);
685 assert_eq!(dbc.value_descriptions_for_signal(512, "SpeedDisplay"), None);
686 }
687}