From 6534f92544367346d762bd88626545f1410f434c Mon Sep 17 00:00:00 2001 From: Benny <206253318+BennyLieb@users.noreply.github.com> Date: Wed, 29 Jul 2026 09:20:06 -0400 Subject: [PATCH 1/4] Add support for Vector BA_DEF_REL_ attributes - Add parser support for Vector relation attribute definitions - Support BU_SG_REL_, BU_BO_REL_ and BU_EV_REL_ relation types - Extend DbcBuilder to store relation custom property definitions - Handle duplicate relation property definitions -Edit Regex in BA_ to Allow "-" in Name -Test --- ...ertiesRelationDefinitionLineParserTests.cs | 267 ++++++++++++++++++ DbcParserLib/DbcBuilder.cs | 34 +++ DbcParserLib/IDbcBuilder.cs | 2 + DbcParserLib/Model/RelationObjectType.cs | 13 + DbcParserLib/Parser.cs | 1 + .../Parsers/PropertiesDefinitionLineParser.cs | 4 +- DbcParserLib/Parsers/PropertiesLineParser.cs | 2 +- .../PropertiesRelationDefinitionLineParser.cs | 198 +++++++++++++ Demo/Form1.Designer.cs | 195 +++++++------ Demo/Form1.cs | 13 +- Demo/Form1.resx | 62 +++- 11 files changed, 697 insertions(+), 94 deletions(-) create mode 100644 DbcParserLib.Tests/PropertiesRelationDefinitionLineParserTests.cs create mode 100644 DbcParserLib/Model/RelationObjectType.cs create mode 100644 DbcParserLib/Parsers/PropertiesRelationDefinitionLineParser.cs diff --git a/DbcParserLib.Tests/PropertiesRelationDefinitionLineParserTests.cs b/DbcParserLib.Tests/PropertiesRelationDefinitionLineParserTests.cs new file mode 100644 index 0000000..998d889 --- /dev/null +++ b/DbcParserLib.Tests/PropertiesRelationDefinitionLineParserTests.cs @@ -0,0 +1,267 @@ +using NUnit.Framework; +using DbcParserLib.Model; +using DbcParserLib.Observers; +using DbcParserLib.Parsers; +using Moq; +using System.Collections.Generic; +using System.IO; + +namespace DbcParserLib.Tests +{ + public class PropertiesRelationDefinitionLineParserTests + { + private MockRepository m_repository; + + [SetUp] + public void Setup() + { + m_repository = new MockRepository(MockBehavior.Strict); + } + + [TearDown] + public void Teardown() + { + m_repository.VerifyAll(); + } + + private static List CreateParser() + { + var observer = new SilentFailureObserver(); + + return new List() + { + new PropertiesRelationDefinitionLineParser(observer) + }; + } + + + private static bool ParseLine( + string line, + List lineParser, + IDbcBuilder builder, + INextLineProvider nextLineProvider) + { + foreach (var parser in lineParser) + { + if (parser.TryParse(line, builder, nextLineProvider)) + return true; + } + + return false; + } + + + [Test] + public void IntRelationDefinitionCustomPropertyIsParsedTest() + { + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + builderMock + .Setup(x => x.AddRelationCustomProperty( + It.IsAny(), + It.IsAny())) + .Callback((relationType, property) => + { + Assert.Multiple(() => + { + Assert.That(relationType, Is.EqualTo(RelationObjectType.NodeSignal)); + Assert.That(property.Name, Is.EqualTo("GenSigTimeoutTime")); + Assert.That(property.DataType, Is.EqualTo(CustomPropertyDataType.Integer)); + + Assert.That(property.IntegerCustomProperty.Minimum, Is.EqualTo(0)); + Assert.That(property.IntegerCustomProperty.Maximum, Is.EqualTo(65535)); + }); + }); + + + var parsers = CreateParser(); + + + Assert.That( + ParseLine( + @"BA_DEF_REL_ BU_SG_REL_ ""GenSigTimeoutTime"" INT 0 65535;", + parsers, + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + } + + + [Test] + public void HexRelationDefinitionCustomPropertyIsParsedTest() + { + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + builderMock + .Setup(x => x.AddRelationCustomProperty( + It.IsAny(), + It.IsAny())) + .Callback((relationType, property) => + { + Assert.Multiple(() => + { + Assert.That(relationType, Is.EqualTo(RelationObjectType.NodeMessage)); + Assert.That(property.Name, Is.EqualTo("TestHex")); + Assert.That(property.DataType, Is.EqualTo(CustomPropertyDataType.Hex)); + + Assert.That(property.HexCustomProperty.Minimum, Is.EqualTo(0)); + Assert.That(property.HexCustomProperty.Maximum, Is.EqualTo(4095)); + }); + }); + + + var parsers = CreateParser(); + + + Assert.That( + ParseLine( + @"BA_DEF_REL_ BU_BO_REL_ ""TestHex"" HEX 0 4095;", + parsers, + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + } + + + [Test] + public void FloatRelationDefinitionCustomPropertyIsParsedTest() + { + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + builderMock + .Setup(x => x.AddRelationCustomProperty( + It.IsAny(), + It.IsAny())) + .Callback((relationType, property) => + { + Assert.Multiple(() => + { + Assert.That(relationType, Is.EqualTo(RelationObjectType.NodeEnvironment)); + Assert.That(property.Name, Is.EqualTo("FloatRelation")); + Assert.That(property.DataType, Is.EqualTo(CustomPropertyDataType.Float)); + + Assert.That(property.FloatCustomProperty.Minimum, Is.EqualTo(0)); + Assert.That(property.FloatCustomProperty.Maximum, Is.EqualTo(10.5)); + }); + }); + + + var parsers = CreateParser(); + + + Assert.That( + ParseLine( + @"BA_DEF_REL_ BU_EV_REL_ ""FloatRelation"" FLOAT 0 10.5;", + parsers, + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + } + + + [Test] + public void StringRelationDefinitionCustomPropertyIsParsedTest() + { + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + builderMock + .Setup(x => x.AddRelationCustomProperty( + It.IsAny(), + It.IsAny())) + .Callback((relationType, property) => + { + Assert.Multiple(() => + { + Assert.That(relationType, Is.EqualTo(RelationObjectType.NodeSignal)); + Assert.That(property.Name, Is.EqualTo("RelationString")); + Assert.That(property.DataType, Is.EqualTo(CustomPropertyDataType.String)); + }); + }); + + + var parsers = CreateParser(); + + + Assert.That( + ParseLine( + @"BA_DEF_REL_ BU_SG_REL_ ""RelationString"" STRING;", + parsers, + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + } + + + [Test] + public void EnumRelationDefinitionCustomPropertyIsParsedTest() + { + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + builderMock + .Setup(x => x.AddRelationCustomProperty( + It.IsAny(), + It.IsAny())) + .Callback((relationType, property) => + { + Assert.Multiple(() => + { + Assert.That(relationType, Is.EqualTo(RelationObjectType.NodeSignal)); + Assert.That(property.Name, Is.EqualTo("RelationEnum")); + Assert.That(property.DataType, Is.EqualTo(CustomPropertyDataType.Enum)); + + Assert.That(property.EnumCustomProperty.Values.Length, Is.EqualTo(3)); + Assert.That(property.EnumCustomProperty.Values[0], Is.EqualTo("A")); + Assert.That(property.EnumCustomProperty.Values[1], Is.EqualTo("B")); + Assert.That(property.EnumCustomProperty.Values[2], Is.EqualTo("C")); + }); + }); + + + var parsers = CreateParser(); + + + Assert.That( + ParseLine( + @"BA_DEF_REL_ BU_SG_REL_ ""RelationEnum"" ENUM ""A"",""B"",""C"";", + parsers, + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + } + + + [Test] + public void InvalidRelationDefinitionReturnsSyntaxErrorTest() + { + var observer = new Mock(); + + observer + .Setup(x => x.PropertyDefinitionSyntaxError()); + + + var parser = new PropertiesRelationDefinitionLineParser(observer.Object); + + + var builderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + + Assert.That( + parser.TryParse( + @"BA_DEF_REL_ UNKNOWN ""Invalid"" INT 0 10;", + builderMock.Object, + nextLineProviderMock.Object), + Is.True); + + + observer.Verify( + x => x.PropertyDefinitionSyntaxError(), + Times.Once); + } + } +} \ No newline at end of file diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index fb20f3c..9189a74 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -11,6 +11,13 @@ internal class ValuesTable public IReadOnlyDictionary ValueTableMap { get; set; } } + internal class RelationCustomPropertyDefinition + { + public RelationObjectType RelationType { get; set; } + + public CustomPropertyDefinition Property { get; set; } + } + internal class DbcBuilder : IDbcBuilder { private readonly IParseFailureObserver m_observer; @@ -29,8 +36,12 @@ internal class DbcBuilder : IDbcBuilder {CustomPropertyObjectType.Signal, new Dictionary()}, {CustomPropertyObjectType.Environment, new Dictionary()}, {CustomPropertyObjectType.Global, new Dictionary()}, + }; + private readonly IList m_relationCustomProperties = new List(); + + private Message m_currentMessage; public DbcBuilder(IParseFailureObserver observer) @@ -481,6 +492,29 @@ public Dbc Build() return new Dbc(m_nodes.ToArray(), m_messages.Values.ToArray(), m_environmentVariables.Values.ToArray(), m_globalCustomProperties.Values); } + + public void AddRelationCustomProperty( + RelationObjectType relationType, + CustomPropertyDefinition property) + { + var existing = m_relationCustomProperties + .FirstOrDefault(x => + x.RelationType == relationType && + x.Property.Name == property.Name); + + if (existing != null) + { + m_observer.DuplicatedProperty(property.Name); + return; + } + + m_relationCustomProperties.Add( + new RelationCustomPropertyDefinition + { + RelationType = relationType, + Property = property + }); + } } internal class NodeEqualityComparer : IEqualityComparer diff --git a/DbcParserLib/IDbcBuilder.cs b/DbcParserLib/IDbcBuilder.cs index e1148d1..47e340e 100644 --- a/DbcParserLib/IDbcBuilder.cs +++ b/DbcParserLib/IDbcBuilder.cs @@ -30,5 +30,7 @@ internal interface IDbcBuilder void AddEnvironmentDataVariable(string variableName, uint dataSize); void AddNodeEnvironmentVariable(string nodeName, string variableName); void AddSignalExtendedMultiplexingInfo(uint messageId, string signalName, string multiplexorSignal, List> multiplexorRanges); + void AddRelationCustomProperty(RelationObjectType relationType, CustomPropertyDefinition property); + } } \ No newline at end of file diff --git a/DbcParserLib/Model/RelationObjectType.cs b/DbcParserLib/Model/RelationObjectType.cs new file mode 100644 index 0000000..32a6b18 --- /dev/null +++ b/DbcParserLib/Model/RelationObjectType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DbcParserLib.Model +{ + public enum RelationObjectType + { + NodeSignal, + NodeMessage, + NodeEnvironment + } +} diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index 482dca6..41ce659 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -22,6 +22,7 @@ private static void CreateLineParsers() new SignalValueTypeLineParser(m_parseObserver), new ValueTableDefinitionLineParser(m_parseObserver), new ValueTableLineParser(m_parseObserver), + new PropertiesRelationDefinitionLineParser(m_parseObserver), new PropertiesDefinitionLineParser(m_parseObserver), new PropertiesLineParser(m_parseObserver), new EnvironmentVariableLineParser(m_parseObserver), diff --git a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs index 660d8d4..3e5a885 100644 --- a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs @@ -23,12 +23,12 @@ internal class PropertiesDefinitionLineParser : ILineParser private const string PropertiesDefinitionLineStarter = "BA_DEF_ "; private const string PropertiesDefinitionDefaultLineStarter = "BA_DEF_DEF_ "; - private readonly string m_propertyDefinitionParsingRegex = $@"BA_DEF_(?:\s+(?<{ObjectTypeGroup}>BU_|BO_|SG_|EV_))?\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""\s+" + + private readonly string m_propertyDefinitionParsingRegex = $@"BA_DEF_(?:\s+(?<{ObjectTypeGroup}>BU_|BO_|SG_|EV_))?\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-\.@]*)""\s+" + $@"(?:(?:(?<{IsIntegerValueGroup}>INT|HEX)\s+(?<{MinIntGroup}>-?[\d\+eE]+)\s+(?<{MaxIntGroup}>-?[\d\+eE]+))|" + $@"(?:(?<{IsFloatValueGroup}>FLOAT)\s+(?<{MinFloatGroup}>[\d\+\-eE.]+)\s+(?<{MaxFloatGroup}>[\d\+\-eE.]+))" + $@"|(?<{IsStringValueGroup}>STRING)|(?:(?<{IsEnumValueGroup}>ENUM)\s+(?<{EnumValueGroup}>(?:""[^""]*"",\s*)*(?:""[^""]*""))))\s*;"; - private readonly string m_propertyDefinitionDefaultParsingRegex = $@"BA_DEF_DEF_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""\s+(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + private readonly string m_propertyDefinitionDefaultParsingRegex = $@"BA_DEF_DEF_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-\.@]*)""\s+(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; private readonly IParseFailureObserver m_observer; diff --git a/DbcParserLib/Parsers/PropertiesLineParser.cs b/DbcParserLib/Parsers/PropertiesLineParser.cs index 031f0b9..effe9e2 100644 --- a/DbcParserLib/Parsers/PropertiesLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesLineParser.cs @@ -17,7 +17,7 @@ internal class PropertiesLineParser : ILineParser private const string SignalNameGroup = "SignalName"; private const string PropertiesLineStarter = "BA_ "; - private readonly string m_propertyParsingRegex = $@"BA_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w]*)""(?:\s+(?:(?<{IsNodeEnvGroup}>BU_|EV_)\s+(?<{NodeEnvNameGroup}>[a-zA-Z_][\w]*))|\s+" + + private readonly string m_propertyParsingRegex = $@"BA_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-]*)""(?:\s+(?:(?<{IsNodeEnvGroup}>BU_|EV_)\s+(?<{NodeEnvNameGroup}>[a-zA-Z_][\w]*))|\s+" + $@"(?:(?<{IsMessageGroup}>BO_)\s+(?<{MessageIdGroup}>\d+))|\s+(?:(?<{IsSignalGroup}>SG_)\s+(?<{MessageSignalIdGroup}>\d+)\s+" + $@"(?<{SignalNameGroup}>[a-zA-Z_][\w]*)))?\s+(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"");"; private readonly IParseFailureObserver m_observer; diff --git a/DbcParserLib/Parsers/PropertiesRelationDefinitionLineParser.cs b/DbcParserLib/Parsers/PropertiesRelationDefinitionLineParser.cs new file mode 100644 index 0000000..5e5051e --- /dev/null +++ b/DbcParserLib/Parsers/PropertiesRelationDefinitionLineParser.cs @@ -0,0 +1,198 @@ +using DbcParserLib.Model; +using DbcParserLib.Observers; +using System; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace DbcParserLib.Parsers +{ + internal class PropertiesRelationDefinitionLineParser : ILineParser + { + private const string RelationTypeGroup = "RelationType"; + private const string AttributeNameGroup = "AttributeName"; + private const string MinIntGroup = "MinInt"; + private const string MaxIntGroup = "MaxInt"; + private const string MinFloatGroup = "MinFloat"; + private const string MaxFloatGroup = "MaxFloat"; + private const string IsIntegerValueGroup = "IsIntegerValue"; + private const string IsFloatValueGroup = "IsFloatValue"; + private const string IsStringValueGroup = "IsStringValue"; + private const string IsEnumValueGroup = "IsEnumValue"; + private const string EnumValueGroup = "EnumValue"; + + private const string PropertiesDefinitionRelationLineStarter = "BA_DEF_REL_"; + + private readonly string m_propertyDefinitionRelationParsingRegex = + $@"BA_DEF_REL_\s+" + + $@"(?<{RelationTypeGroup}>BU_SG_REL_|BU_BO_REL_|BU_EV_REL_)\s+" + + $@"""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-]*)""\s+" + + $@"(?:" + + $@"(?:(?<" + IsIntegerValueGroup + @">INT|HEX)\s+" + + $@"(?<" + MinIntGroup + @">-?[\d\+eE]+)\s+" + + $@"(?<" + MaxIntGroup + @">-?[\d\+eE]+))" + + "|" + + $@"(?:(?<" + IsFloatValueGroup + @">FLOAT)\s+" + + $@"(?<" + MinFloatGroup + @">[\d\+\-eE.]+)\s+" + + $@"(?<" + MaxFloatGroup + @">[\d\+\-eE.]+))" + + "|" + + $@"(?<" + IsStringValueGroup + @">STRING)" + + "|" + + $@"(?:(?<" + IsEnumValueGroup + @">ENUM)\s+" + + $@"(?<" + EnumValueGroup + @">(?:""[^""]*"",\s*)*(?:""[^""]*"")))" + + @")\s*;"; + + + private readonly IParseFailureObserver m_observer; + + + public PropertiesRelationDefinitionLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + + + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) + { + var cleanLine = line.Trim(); + + if (cleanLine.StartsWith(PropertiesDefinitionRelationLineStarter) == false) + return false; + + + var match = Regex.Match( + cleanLine, + m_propertyDefinitionRelationParsingRegex); + + + if (match.Success == false) + { + m_observer.PropertyDefinitionSyntaxError(); + return true; + } + + + var relationType = + ParseRelationType( + match.Groups[RelationTypeGroup].Value); + + + var customProperty = new CustomPropertyDefinition(m_observer) + { + Name = match.Groups[AttributeNameGroup].Value + }; + + + CustomPropertyDataType dataType = CustomPropertyDataType.Integer; + + + if (match.Groups[IsIntegerValueGroup].Value.Equals("INT")) + { + if (double.TryParse( + match.Groups[MinIntGroup].Value, + NumberStyles.Float, + CultureInfo.InvariantCulture, + out var minValue) == false || + double.TryParse( + match.Groups[MaxIntGroup].Value, + NumberStyles.Float, + CultureInfo.InvariantCulture, + out var maxValue) == false) + { + m_observer.PropertyDefinitionSyntaxError(); + return true; + } + + + customProperty.IntegerCustomProperty = + new NumericCustomPropertyDefinition + { + Minimum = Convert.ToInt32(minValue), + Maximum = Convert.ToInt32(maxValue) + }; + } + else if (match.Groups[IsIntegerValueGroup].Value.Equals("HEX")) + { + dataType = CustomPropertyDataType.Hex; + + customProperty.HexCustomProperty = + new NumericCustomPropertyDefinition + { + Minimum = int.Parse( + match.Groups[MinIntGroup].Value, + CultureInfo.InvariantCulture), + + Maximum = int.Parse( + match.Groups[MaxIntGroup].Value, + CultureInfo.InvariantCulture) + }; + } + else if (match.Groups[IsFloatValueGroup].Success) + { + dataType = CustomPropertyDataType.Float; + + customProperty.FloatCustomProperty = + new NumericCustomPropertyDefinition + { + Minimum = double.Parse( + match.Groups[MinFloatGroup].Value, + CultureInfo.InvariantCulture), + + Maximum = double.Parse( + match.Groups[MaxFloatGroup].Value, + CultureInfo.InvariantCulture) + }; + } + else if (match.Groups[IsStringValueGroup].Success) + { + dataType = CustomPropertyDataType.String; + + customProperty.StringCustomProperty = + new StringCustomPropertyDefinition(); + } + else if (match.Groups[IsEnumValueGroup].Success) + { + dataType = CustomPropertyDataType.Enum; + + customProperty.EnumCustomProperty = + new EnumCustomPropertyDefinition + { + Values = match.Groups[EnumValueGroup] + .Value + .Replace(Helpers.DoubleQuotes, string.Empty) + .Split(',') + }; + } + + + customProperty.DataType = dataType; + + + builder.AddRelationCustomProperty( + relationType, + customProperty); + + + return true; + } + + + private RelationObjectType ParseRelationType(string value) + { + switch (value) + { + case "BU_SG_REL_": + return RelationObjectType.NodeSignal; + + case "BU_BO_REL_": + return RelationObjectType.NodeMessage; + + case "BU_EV_REL_": + return RelationObjectType.NodeEnvironment; + + default: + throw new InvalidOperationException( + $"Unknown relation type {value}"); + } + } + } +} \ No newline at end of file diff --git a/Demo/Form1.Designer.cs b/Demo/Form1.Designer.cs index c35c88b..1111302 100644 --- a/Demo/Form1.Designer.cs +++ b/Demo/Form1.Designer.cs @@ -29,117 +29,142 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.buttonLoadDbc = new System.Windows.Forms.Button(); - this.textBoxPath = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.textBoxNodes = new System.Windows.Forms.TextBox(); - this.label2 = new System.Windows.Forms.Label(); - this.dataGridViewMsg = new System.Windows.Forms.DataGridView(); - this.label3 = new System.Windows.Forms.Label(); - this.dataGridViewSig = new System.Windows.Forms.DataGridView(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridViewMsg)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridViewSig)).BeginInit(); - this.SuspendLayout(); + buttonLoadDbc = new System.Windows.Forms.Button(); + textBoxPath = new System.Windows.Forms.TextBox(); + label1 = new System.Windows.Forms.Label(); + textBoxNodes = new System.Windows.Forms.TextBox(); + label2 = new System.Windows.Forms.Label(); + dataGridViewMsg = new System.Windows.Forms.DataGridView(); + label3 = new System.Windows.Forms.Label(); + dataGridViewSig = new System.Windows.Forms.DataGridView(); + richTextBoxLog = new System.Windows.Forms.RichTextBox(); + label4 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)dataGridViewMsg).BeginInit(); + ((System.ComponentModel.ISupportInitialize)dataGridViewSig).BeginInit(); + SuspendLayout(); // // buttonLoadDbc // - this.buttonLoadDbc.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonLoadDbc.Location = new System.Drawing.Point(760, 20); - this.buttonLoadDbc.Name = "buttonLoadDbc"; - this.buttonLoadDbc.Size = new System.Drawing.Size(113, 25); - this.buttonLoadDbc.TabIndex = 0; - this.buttonLoadDbc.Text = "Load DBC"; - this.buttonLoadDbc.UseVisualStyleBackColor = true; - this.buttonLoadDbc.Click += new System.EventHandler(this.buttonLoadDbc_Click); + buttonLoadDbc.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; + buttonLoadDbc.Location = new System.Drawing.Point(869, 27); + buttonLoadDbc.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + buttonLoadDbc.Name = "buttonLoadDbc"; + buttonLoadDbc.Size = new System.Drawing.Size(129, 33); + buttonLoadDbc.TabIndex = 0; + buttonLoadDbc.Text = "Load DBC"; + buttonLoadDbc.UseVisualStyleBackColor = true; + buttonLoadDbc.Click += buttonLoadDbc_Click; // // textBoxPath // - this.textBoxPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxPath.Location = new System.Drawing.Point(12, 21); - this.textBoxPath.Name = "textBoxPath"; - this.textBoxPath.Size = new System.Drawing.Size(740, 23); - this.textBoxPath.TabIndex = 1; + textBoxPath.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + textBoxPath.Location = new System.Drawing.Point(14, 28); + textBoxPath.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + textBoxPath.Name = "textBoxPath"; + textBoxPath.Size = new System.Drawing.Size(845, 27); + textBoxPath.TabIndex = 1; // // label1 // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(11, 56); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(44, 15); - this.label1.TabIndex = 3; - this.label1.Text = "Nodes:"; + label1.AutoSize = true; + label1.Location = new System.Drawing.Point(13, 75); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(55, 20); + label1.TabIndex = 3; + label1.Text = "Nodes:"; // // textBoxNodes // - this.textBoxNodes.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxNodes.Location = new System.Drawing.Point(11, 74); - this.textBoxNodes.Name = "textBoxNodes"; - this.textBoxNodes.Size = new System.Drawing.Size(861, 23); - this.textBoxNodes.TabIndex = 4; + textBoxNodes.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + textBoxNodes.Location = new System.Drawing.Point(13, 99); + textBoxNodes.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + textBoxNodes.Name = "textBoxNodes"; + textBoxNodes.Size = new System.Drawing.Size(983, 27); + textBoxNodes.TabIndex = 4; // // label2 // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(11, 109); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(61, 15); - this.label2.TabIndex = 5; - this.label2.Text = "Messages:"; + label2.AutoSize = true; + label2.Location = new System.Drawing.Point(13, 145); + label2.Name = "label2"; + label2.Size = new System.Drawing.Size(76, 20); + label2.TabIndex = 5; + label2.Text = "Messages:"; // // dataGridViewMsg // - this.dataGridViewMsg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.dataGridViewMsg.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.dataGridViewMsg.Location = new System.Drawing.Point(11, 128); - this.dataGridViewMsg.Name = "dataGridViewMsg"; - this.dataGridViewMsg.RowTemplate.Height = 25; - this.dataGridViewMsg.Size = new System.Drawing.Size(861, 126); - this.dataGridViewMsg.TabIndex = 6; + dataGridViewMsg.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + dataGridViewMsg.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGridViewMsg.Location = new System.Drawing.Point(13, 171); + dataGridViewMsg.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + dataGridViewMsg.Name = "dataGridViewMsg"; + dataGridViewMsg.RowHeadersWidth = 51; + dataGridViewMsg.RowTemplate.Height = 25; + dataGridViewMsg.Size = new System.Drawing.Size(984, 168); + dataGridViewMsg.TabIndex = 6; // // label3 // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(11, 274); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(47, 15); - this.label3.TabIndex = 7; - this.label3.Text = "Signals:"; + label3.AutoSize = true; + label3.Location = new System.Drawing.Point(13, 348); + label3.Name = "label3"; + label3.Size = new System.Drawing.Size(59, 20); + label3.TabIndex = 7; + label3.Text = "Signals:"; // // dataGridViewSig // - this.dataGridViewSig.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.dataGridViewSig.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.dataGridViewSig.Location = new System.Drawing.Point(11, 292); - this.dataGridViewSig.Name = "dataGridViewSig"; - this.dataGridViewSig.RowTemplate.Height = 25; - this.dataGridViewSig.Size = new System.Drawing.Size(861, 307); - this.dataGridViewSig.TabIndex = 8; + dataGridViewSig.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + dataGridViewSig.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + dataGridViewSig.Location = new System.Drawing.Point(13, 372); + dataGridViewSig.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + dataGridViewSig.Name = "dataGridViewSig"; + dataGridViewSig.RowHeadersWidth = 51; + dataGridViewSig.RowTemplate.Height = 25; + dataGridViewSig.Size = new System.Drawing.Size(984, 391); + dataGridViewSig.TabIndex = 8; + // + // richTextBoxLog + // + richTextBoxLog.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + richTextBoxLog.Location = new System.Drawing.Point(12, 805); + richTextBoxLog.Name = "richTextBoxLog"; + richTextBoxLog.Size = new System.Drawing.Size(982, 153); + richTextBoxLog.TabIndex = 10; + richTextBoxLog.Text = ""; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new System.Drawing.Point(15, 782); + label4.Name = "labelLog"; + label4.Size = new System.Drawing.Size(37, 20); + label4.TabIndex = 11; + label4.Text = "Log:"; // // Form1 // - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(884, 611); - this.Controls.Add(this.dataGridViewSig); - this.Controls.Add(this.label3); - this.Controls.Add(this.dataGridViewMsg); - this.Controls.Add(this.label2); - this.Controls.Add(this.textBoxNodes); - this.Controls.Add(this.label1); - this.Controls.Add(this.textBoxPath); - this.Controls.Add(this.buttonLoadDbc); - this.Name = "Form1"; - this.Text = "Form1"; - this.Load += new System.EventHandler(this.Form1_Load); - ((System.ComponentModel.ISupportInitialize)(this.dataGridViewMsg)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridViewSig)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); + AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + ClientSize = new System.Drawing.Size(1010, 971); + Controls.Add(label4); + Controls.Add(richTextBoxLog); + Controls.Add(dataGridViewSig); + Controls.Add(label3); + Controls.Add(dataGridViewMsg); + Controls.Add(label2); + Controls.Add(textBoxNodes); + Controls.Add(label1); + Controls.Add(textBoxPath); + Controls.Add(buttonLoadDbc); + Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + Name = "Form1"; + Text = "Form1"; + Load += Form1_Load; + ((System.ComponentModel.ISupportInitialize)dataGridViewMsg).EndInit(); + ((System.ComponentModel.ISupportInitialize)dataGridViewSig).EndInit(); + ResumeLayout(false); + PerformLayout(); } @@ -153,6 +178,8 @@ private void InitializeComponent() private System.Windows.Forms.DataGridView dataGridViewMsg; private System.Windows.Forms.Label label3; private System.Windows.Forms.DataGridView dataGridViewSig; + private System.Windows.Forms.RichTextBox richTextBoxLog; + private System.Windows.Forms.Label label4; } } diff --git a/Demo/Form1.cs b/Demo/Form1.cs index db8e689..09f2774 100644 --- a/Demo/Form1.cs +++ b/Demo/Form1.cs @@ -73,7 +73,7 @@ public void LoadDbc(string filePath) // Comment this line to remove parsing failure management (errors will be silent) // You can provide your own IParseObserver implementation to customize parsing failure management Parser.SetParsingFailuresObserver(m_failureObserver); - + var dbc = Parser.ParseFromPath(filePath); ShowErrors(); @@ -82,6 +82,7 @@ public void LoadDbc(string filePath) } catch (Exception ex) { + MessageBox.Show($"Failed to read dbc file!\n\n{ex}", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } @@ -92,8 +93,9 @@ private void ShowErrors() var errors = m_failureObserver.GetErrorList(); if (errors.Count > 0) { - MessageBox.Show(string.Join(Environment.NewLine, errors), "Parsing failures!", MessageBoxButtons.OK, - MessageBoxIcon.Error); + + richTextBoxLog.Clear(); + richTextBoxLog.AppendText(string.Join(Environment.NewLine, errors)); } } @@ -178,10 +180,9 @@ public void PopulateView(Dbc dbc) static void SetDoubleBuffer(Control dgv, bool DoubleBuffered) { - typeof(Control).InvokeMember("DoubleBuffered", - BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, + typeof(Control).InvokeMember("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, dgv, new object[] { DoubleBuffered }); } - } } diff --git a/Demo/Form1.resx b/Demo/Form1.resx index f298a7b..8b2ff64 100644 --- a/Demo/Form1.resx +++ b/Demo/Form1.resx @@ -1,4 +1,64 @@ - + + + From 595f78326021e46a965d274012c2cfc9d793f9f8 Mon Sep 17 00:00:00 2001 From: Benny <206253318+BennyLieb@users.noreply.github.com> Date: Wed, 29 Jul 2026 09:30:09 -0400 Subject: [PATCH 2/4] Add support for Vector BA_DEF_DEF_REL_ attributes - Add parser support for Vector relation attribute definitions "BA_DEF_DEF_REL_" --- DbcParserLib/DbcBuilder.cs | 49 ++++++++-------- DbcParserLib/IDbcBuilder.cs | 2 +- DbcParserLib/Parser.cs | 8 ++- .../PropertiesRelationDefaultLineParser.cs | 57 +++++++++++++++++++ 4 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 DbcParserLib/Parsers/PropertiesRelationDefaultLineParser.cs diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index 9189a74..acc13f5 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -352,6 +352,32 @@ public void AddSignalExtendedMultiplexingInfo(uint messageId, string signalName, { // ToDo: Define what to do with the data } + public void AddRelationCustomProperty(RelationObjectType relationType, CustomPropertyDefinition property) + { + var existing = m_relationCustomProperties + .FirstOrDefault(x => + x.RelationType == relationType && + x.Property.Name == property.Name); + + if (existing != null) + { + m_observer.DuplicatedProperty(property.Name); + return; + } + + m_relationCustomProperties.Add( + new RelationCustomPropertyDefinition + { + RelationType = relationType, + Property = property + }); + } + + public void AddRelationCustomPropertyDefaultValue(string propertyName, string value, bool isNumeric) + { + //TODO: Needs Implementation + } + private bool TryGetValueMessageSignal(uint messageId, string signalName, out Signal signal) { @@ -492,29 +518,6 @@ public Dbc Build() return new Dbc(m_nodes.ToArray(), m_messages.Values.ToArray(), m_environmentVariables.Values.ToArray(), m_globalCustomProperties.Values); } - - public void AddRelationCustomProperty( - RelationObjectType relationType, - CustomPropertyDefinition property) - { - var existing = m_relationCustomProperties - .FirstOrDefault(x => - x.RelationType == relationType && - x.Property.Name == property.Name); - - if (existing != null) - { - m_observer.DuplicatedProperty(property.Name); - return; - } - - m_relationCustomProperties.Add( - new RelationCustomPropertyDefinition - { - RelationType = relationType, - Property = property - }); - } } internal class NodeEqualityComparer : IEqualityComparer diff --git a/DbcParserLib/IDbcBuilder.cs b/DbcParserLib/IDbcBuilder.cs index 47e340e..8700a1e 100644 --- a/DbcParserLib/IDbcBuilder.cs +++ b/DbcParserLib/IDbcBuilder.cs @@ -31,6 +31,6 @@ internal interface IDbcBuilder void AddNodeEnvironmentVariable(string nodeName, string variableName); void AddSignalExtendedMultiplexingInfo(uint messageId, string signalName, string multiplexorSignal, List> multiplexorRanges); void AddRelationCustomProperty(RelationObjectType relationType, CustomPropertyDefinition property); - + void AddRelationCustomPropertyDefaultValue( string propertyName,string value, bool isNumeric); } } \ No newline at end of file diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index 41ce659..19a28ce 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -1,7 +1,8 @@ -using System.IO; -using System.Collections.Generic; -using DbcParserLib.Parsers; using DbcParserLib.Observers; +using DbcParserLib.Parsers; +using System; +using System.Collections.Generic; +using System.IO; namespace DbcParserLib { @@ -23,6 +24,7 @@ private static void CreateLineParsers() new ValueTableDefinitionLineParser(m_parseObserver), new ValueTableLineParser(m_parseObserver), new PropertiesRelationDefinitionLineParser(m_parseObserver), + new PropertiesRelationDefaultLineParser(m_parseObserver), new PropertiesDefinitionLineParser(m_parseObserver), new PropertiesLineParser(m_parseObserver), new EnvironmentVariableLineParser(m_parseObserver), diff --git a/DbcParserLib/Parsers/PropertiesRelationDefaultLineParser.cs b/DbcParserLib/Parsers/PropertiesRelationDefaultLineParser.cs new file mode 100644 index 0000000..0666e5b --- /dev/null +++ b/DbcParserLib/Parsers/PropertiesRelationDefaultLineParser.cs @@ -0,0 +1,57 @@ +using DbcParserLib.Model; +using DbcParserLib.Observers; +using System.Text.RegularExpressions; + +namespace DbcParserLib.Parsers +{ + internal class PropertiesRelationDefaultLineParser : ILineParser + { + private const string AttributeNameGroup = "AttributeName"; + private const string AttributeValueGroup = "AttributeValue"; + + private const string PropertiesDefinitionRelationDefaultLineStarter = "BA_DEF_DEF_REL_ "; + + private readonly string m_propertyDefinitionRelationDefaultParsingRegex = + $@"BA_DEF_DEF_REL_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-]*)""\s+" + + $@"(?<{AttributeValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + + + private readonly IParseFailureObserver m_observer; + + + public PropertiesRelationDefaultLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + + + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) + { + var cleanLine = line.Trim(' '); + + if (!cleanLine.StartsWith(PropertiesDefinitionRelationDefaultLineStarter)) + return false; + + + var match = Regex.Match( + cleanLine, + m_propertyDefinitionRelationDefaultParsingRegex); + + + if (!match.Success) + { + m_observer.PropertyDefaultSyntaxError(); + return true; + } + + + builder.AddRelationCustomPropertyDefaultValue( + match.Groups[AttributeNameGroup].Value, + match.Groups[AttributeValueGroup].Value.Replace(Helpers.DoubleQuotes, ""), + !match.Groups[AttributeValueGroup].Value.StartsWith("\"")); + + + return true; + } + } +} \ No newline at end of file From be5c4acf0dad659150f80e2610e8760d4a2075c2 Mon Sep 17 00:00:00 2001 From: Benny <206253318+BennyLieb@users.noreply.github.com> Date: Wed, 29 Jul 2026 09:40:12 -0400 Subject: [PATCH 3/4] Add support for Vector BA_REL_ attributes - Add parser support for Vector relation attribute definitions "BA_REL_" - Add Field to IDbcBuilder and DbcBuilder --- DbcParserLib/DbcBuilder.cs | 7 ++ DbcParserLib/IDbcBuilder.cs | 6 ++ DbcParserLib/Parser.cs | 7 ++ .../Parsers/PropertiesRelationLineParser.cs | 66 +++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 DbcParserLib/Parsers/PropertiesRelationLineParser.cs diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index acc13f5..e7b09f5 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -378,6 +378,11 @@ public void AddRelationCustomPropertyDefaultValue(string propertyName, string va //TODO: Needs Implementation } + public void AddRelationCustomPropertyValue(string propertyName, string relationType, string nodeName, uint messageId, string signalName, string value) + { + //TODO: Needs Implementation + } + private bool TryGetValueMessageSignal(uint messageId, string signalName, out Signal signal) { @@ -518,6 +523,8 @@ public Dbc Build() return new Dbc(m_nodes.ToArray(), m_messages.Values.ToArray(), m_environmentVariables.Values.ToArray(), m_globalCustomProperties.Values); } + + } internal class NodeEqualityComparer : IEqualityComparer diff --git a/DbcParserLib/IDbcBuilder.cs b/DbcParserLib/IDbcBuilder.cs index 8700a1e..94e00b4 100644 --- a/DbcParserLib/IDbcBuilder.cs +++ b/DbcParserLib/IDbcBuilder.cs @@ -32,5 +32,11 @@ internal interface IDbcBuilder void AddSignalExtendedMultiplexingInfo(uint messageId, string signalName, string multiplexorSignal, List> multiplexorRanges); void AddRelationCustomProperty(RelationObjectType relationType, CustomPropertyDefinition property); void AddRelationCustomPropertyDefaultValue( string propertyName,string value, bool isNumeric); + + void AddRelationCustomPropertyValue(string propertyName,string relationType, + string nodeName, + uint messageId, + string signalName, + string value); } } \ No newline at end of file diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index 19a28ce..94352be 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -16,17 +16,24 @@ private static void CreateLineParsers() LineParsers = new List() { new IgnoreLineParser(m_parseObserver), // Used to skip line we know we want to skip + new NodeLineParser(m_parseObserver), new MessageLineParser(m_parseObserver), new CommentLineParser(m_parseObserver), new SignalLineParser(m_parseObserver), + // Signal / value handling new SignalValueTypeLineParser(m_parseObserver), new ValueTableDefinitionLineParser(m_parseObserver), new ValueTableLineParser(m_parseObserver), + // Relation attribute definitions (must be BEFORE normal BA_DEF_) new PropertiesRelationDefinitionLineParser(m_parseObserver), new PropertiesRelationDefaultLineParser(m_parseObserver), + new PropertiesRelationLineParser(m_parseObserver), + + // Normal attribute definitions and assignments new PropertiesDefinitionLineParser(m_parseObserver), new PropertiesLineParser(m_parseObserver), + new EnvironmentVariableLineParser(m_parseObserver), new EnvironmentDataVariableLineParser(m_parseObserver), new ExtraMessageTransmitterLineParser(m_parseObserver), diff --git a/DbcParserLib/Parsers/PropertiesRelationLineParser.cs b/DbcParserLib/Parsers/PropertiesRelationLineParser.cs new file mode 100644 index 0000000..8a8ba0e --- /dev/null +++ b/DbcParserLib/Parsers/PropertiesRelationLineParser.cs @@ -0,0 +1,66 @@ +using DbcParserLib.Model; +using DbcParserLib.Observers; +using System.Text.RegularExpressions; + +namespace DbcParserLib.Parsers +{ + internal class PropertiesRelationLineParser : ILineParser + { + private const string AttributeNameGroup = "AttributeName"; + private const string RelationTypeGroup = "RelationType"; + private const string NodeNameGroup = "NodeName"; + private const string MessageIdGroup = "MessageId"; + private const string SignalNameGroup = "SignalName"; + private const string ValueGroup = "Value"; + + private const string PropertiesRelationLineStarter = "BA_REL_ "; + + + private readonly string m_relationRegex = + $@"BA_REL_\s+""(?<{AttributeNameGroup}>[a-zA-Z_][\w\-]*)""\s+" + + $@"(?<{RelationTypeGroup}>BU_SG_REL_|BU_BO_REL_|BU_EV_REL_)\s+" + + $@"(?<{NodeNameGroup}>[a-zA-Z_][\w]*)\s+" + + $@"(?:SG_\s+(?<{MessageIdGroup}>\d+)\s+(?<{SignalNameGroup}>[a-zA-Z_][\w]*))\s+" + + $@"(?<{ValueGroup}>-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + + + private readonly IParseFailureObserver m_observer; + + + public PropertiesRelationLineParser(IParseFailureObserver observer) + { + m_observer = observer; + } + + + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) + { + var cleanLine = line.Trim(' '); + + if (!cleanLine.StartsWith(PropertiesRelationLineStarter)) + return false; + + + var match = Regex.Match(cleanLine, m_relationRegex); + + + if (!match.Success) + { + m_observer.PropertySyntaxError(); + return true; + } + + + builder.AddRelationCustomPropertyValue( + match.Groups[AttributeNameGroup].Value, + match.Groups[RelationTypeGroup].Value, + match.Groups[NodeNameGroup].Value, + uint.Parse(match.Groups[MessageIdGroup].Value), + match.Groups[SignalNameGroup].Value, + match.Groups[ValueGroup].Value); + + + return true; + } + } +} \ No newline at end of file From 7870d9ce3fa7da8cb301bb9fe464b04e5e1dc3d3 Mon Sep 17 00:00:00 2001 From: Benny <206253318+BennyLieb@users.noreply.github.com> Date: Wed, 29 Jul 2026 09:58:57 -0400 Subject: [PATCH 4/4] Add Model for VectorExtensions + Support .Net10 - Add Builder Functions -Add Dbc Properties --- DbcParserLib/Dbc.cs | 6 +- DbcParserLib/DbcBuilder.cs | 63 +++++++++++++------ DbcParserLib/DbcParserLib.csproj | 2 +- DbcParserLib/Model/RelationObjectType.cs | 13 ---- DbcParserLib/Model/VectorExtensions.cs | 78 ++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 32 deletions(-) delete mode 100644 DbcParserLib/Model/RelationObjectType.cs create mode 100644 DbcParserLib/Model/VectorExtensions.cs diff --git a/DbcParserLib/Dbc.cs b/DbcParserLib/Dbc.cs index 56ecb1e..473faa9 100644 --- a/DbcParserLib/Dbc.cs +++ b/DbcParserLib/Dbc.cs @@ -13,13 +13,17 @@ public class Dbc public IEnumerable EnvironmentVariables { get; } public IEnumerable GlobalProperties { get; } + public VectorExtensions VectorExtensions { get; } + public Dbc(IEnumerable nodes, IEnumerable messages, IEnumerable environmentVariables, - IEnumerable globalProperties) + IEnumerable globalProperties, VectorExtensions vectorExtensions = null) { Nodes = nodes; Messages = messages; EnvironmentVariables = environmentVariables; GlobalProperties = globalProperties; + //TODO: Null Reference check + VectorExtensions = vectorExtensions; } } } \ No newline at end of file diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index e7b09f5..cd04b7e 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -11,13 +11,6 @@ internal class ValuesTable public IReadOnlyDictionary ValueTableMap { get; set; } } - internal class RelationCustomPropertyDefinition - { - public RelationObjectType RelationType { get; set; } - - public CustomPropertyDefinition Property { get; set; } - } - internal class DbcBuilder : IDbcBuilder { private readonly IParseFailureObserver m_observer; @@ -39,7 +32,9 @@ internal class DbcBuilder : IDbcBuilder }; - private readonly IList m_relationCustomProperties = new List(); + private readonly IList m_relationCustomProperties = new List(); + + private readonly IList m_relationCustomPropertyValues = new List(); private Message m_currentMessage; @@ -365,22 +360,49 @@ public void AddRelationCustomProperty(RelationObjectType relationType, CustomPro return; } - m_relationCustomProperties.Add( - new RelationCustomPropertyDefinition - { - RelationType = relationType, - Property = property - }); + m_relationCustomProperties.Add( new RelationCustomPropertyDefinition(relationType, property)); } public void AddRelationCustomPropertyDefaultValue(string propertyName, string value, bool isNumeric) { - //TODO: Needs Implementation + //TODO: Need Tests + var property = m_relationCustomProperties + .FirstOrDefault(x => + x.Property.Name == propertyName); + + if (property == null) + { + m_observer.PropertyNameNotFound(propertyName); + return; + } + + property.Property.SetCustomPropertyDefaultValue( + value, + isNumeric); } public void AddRelationCustomPropertyValue(string propertyName, string relationType, string nodeName, uint messageId, string signalName, string value) { - //TODO: Needs Implementation + //TODO: Need Tests + var propertyExists = m_relationCustomProperties.Any(x => + x.Property.Name == propertyName); + + + if (!propertyExists) + { + m_observer.PropertyNameNotFound(propertyName); + return; + } + + //TODO: Better Enum parsing + m_relationCustomPropertyValues.Add( + new RelationCustomPropertyValue( + propertyName, + (RelationObjectType)Enum.Parse(typeof(RelationObjectType), relationType), + nodeName, + messageId, + signalName, + value)); } @@ -521,7 +543,14 @@ public Dbc Build() //} //return new Dbc(nodes, messages, environmentVariables); - return new Dbc(m_nodes.ToArray(), m_messages.Values.ToArray(), m_environmentVariables.Values.ToArray(), m_globalCustomProperties.Values); + return new Dbc( + m_nodes.ToArray(), + m_messages.Values.ToArray(), + m_environmentVariables.Values.ToArray(), + m_globalCustomProperties.Values, + new VectorExtensions( + m_relationCustomProperties, + m_relationCustomPropertyValues)); } diff --git a/DbcParserLib/DbcParserLib.csproj b/DbcParserLib/DbcParserLib.csproj index 3564024..1ed88d0 100644 --- a/DbcParserLib/DbcParserLib.csproj +++ b/DbcParserLib/DbcParserLib.csproj @@ -2,7 +2,7 @@ Library - netstandard2.0;net462;net6.0;net8.0 + netstandard2.0;net462;net6.0;net8.0;net10.0 Emanuel Feru DbcParserLib is a .NET dbc file parser library for CAN bus network signals. This library can also be used to pack and unpack CAN signals. MIT diff --git a/DbcParserLib/Model/RelationObjectType.cs b/DbcParserLib/Model/RelationObjectType.cs deleted file mode 100644 index 32a6b18..0000000 --- a/DbcParserLib/Model/RelationObjectType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DbcParserLib.Model -{ - public enum RelationObjectType - { - NodeSignal, - NodeMessage, - NodeEnvironment - } -} diff --git a/DbcParserLib/Model/VectorExtensions.cs b/DbcParserLib/Model/VectorExtensions.cs new file mode 100644 index 0000000..9918063 --- /dev/null +++ b/DbcParserLib/Model/VectorExtensions.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DbcParserLib.Model +{ + public class VectorExtensions + { + public IEnumerable RelationProperties { get; } + + public IEnumerable RelationPropertyValues { get; } + + + public VectorExtensions( + IEnumerable relationProperties, + IEnumerable relationPropertyValues) + { + RelationProperties = relationProperties; + RelationPropertyValues = relationPropertyValues; + } + } + + public enum RelationObjectType + { + NodeSignal, + NodeMessage, + NodeEnvironment + } + + + public class RelationCustomPropertyValue + { + public string PropertyName { get; } + + public RelationObjectType RelationType { get; } + + public string NodeName { get; } + + public uint MessageId { get; } + + public string SignalName { get; } + + public string Value { get; } + + + public RelationCustomPropertyValue( + string propertyName, + RelationObjectType relationType, + string nodeName, + uint messageId, + string signalName, + string value) + { + PropertyName = propertyName; + RelationType = relationType; + NodeName = nodeName; + MessageId = messageId; + SignalName = signalName; + Value = value; + } + } + + public class RelationCustomPropertyDefinition + { + public RelationObjectType RelationType { get; } + + public CustomPropertyDefinition Property { get; } + + + public RelationCustomPropertyDefinition( + RelationObjectType relationType, + CustomPropertyDefinition property) + { + RelationType = relationType; + Property = property; + } + } +}