diff --git a/DbcParserLib.Tests/DbcBuilderTests.cs b/DbcParserLib.Tests/DbcBuilderTests.cs index e21358c..c0b755b 100644 --- a/DbcParserLib.Tests/DbcBuilderTests.cs +++ b/DbcParserLib.Tests/DbcBuilderTests.cs @@ -43,7 +43,7 @@ public void SingleNodeIsAdded() var dbc = builder.Build(); Assert.AreEqual(1, dbc.Nodes.Count()); - Assert.AreEqual(node, dbc.Nodes.First()); + Assert.AreEqual("nodeName", dbc.Nodes.First().Name); } [Test] @@ -60,8 +60,8 @@ public void DuplicatedNodesAreSkipped() var dbc = builder.Build(); Assert.AreEqual(2, dbc.Nodes.Count()); - Assert.AreEqual(node, dbc.Nodes.First()); - Assert.AreEqual(node2, dbc.Nodes.Skip(1).First()); + Assert.AreEqual("nodeName", dbc.Nodes.First().Name); + Assert.AreEqual("nodeName2", dbc.Nodes.Skip(1).First().Name); } [Test] @@ -75,7 +75,7 @@ public void NodeCommentIsAddedToNode() var dbc = builder.Build(); Assert.AreEqual(1, dbc.Nodes.Count()); - Assert.AreEqual(node, dbc.Nodes.First()); + Assert.AreEqual("nodeName", dbc.Nodes.First().Name); Assert.AreEqual("this is a comment", dbc.Nodes.First().Comment); } @@ -90,7 +90,7 @@ public void NodeCommentIsSkippedIfNodeIsNotFound() var dbc = builder.Build(); Assert.AreEqual(1, dbc.Nodes.Count()); - Assert.AreEqual(node, dbc.Nodes.First()); + Assert.AreEqual("nodeName", dbc.Nodes.First().Name); Assert.IsNull(dbc.Nodes.First().Comment); } @@ -104,7 +104,6 @@ public void MessageIsAdded() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); } [Test] @@ -118,7 +117,7 @@ public void CommentIsAddedToMessage() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); Assert.AreEqual("comment", dbc.Messages.First().Comment); } @@ -133,7 +132,7 @@ public void CommentIsNotAddedToMissingMessage() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); Assert.IsNull(dbc.Messages.First().Comment); } @@ -162,14 +161,14 @@ public void SignalIsAddedToCurrentMessage() Assert.AreEqual(2, dbc.Messages.Count()); var messagesToArray = dbc.Messages.ToArray(); - Assert.AreEqual(message1, messagesToArray[0]); + Assert.AreEqual(234, messagesToArray[0].ID); Assert.AreEqual(1, messagesToArray[0].Signals.Count()); - Assert.AreEqual(signal1, messagesToArray[0].Signals.First()); + Assert.AreEqual("name1", messagesToArray[0].Signals.First().Name); - Assert.AreEqual(message2, messagesToArray[1]); + Assert.AreEqual(235, messagesToArray[1].ID); Assert.AreEqual(2, messagesToArray[1].Signals.Count()); - Assert.AreEqual(signal2, messagesToArray[1].Signals.First()); - Assert.AreEqual(signal3, messagesToArray[1].Signals.Skip(1).First()); + Assert.AreEqual("name2", messagesToArray[1].Signals.First().Name); + Assert.AreEqual("name3", messagesToArray[1].Signals.Skip(1).First().Name); } [Test] @@ -197,8 +196,8 @@ public void CommentIsAddedToSignal() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.AreEqual("comment", dbc.Messages.First().Signals.First().Comment); } @@ -216,8 +215,8 @@ public void CommentIsNotAddedToMissingSignalMessageId() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().Comment); } @@ -235,8 +234,8 @@ public void CommentIsNotAddedToMissingSignalName() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().Comment); } @@ -255,8 +254,8 @@ public void TableValuesAreAddedToSignal() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.AreEqual(testValuesDict, dbc.Messages.First().Signals.First().ValueTableMap); Assert.AreEqual("1 fake", dbc.Messages.First().Signals.First().ValueTable); } @@ -277,8 +276,8 @@ public void TableValuesWithExtendedMessageIdAreAddedToSignal() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(message.ID, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.AreEqual(testValuesDict, dbc.Messages.First().Signals.First().ValueTableMap); Assert.AreEqual("1 fake", dbc.Messages.First().Signals.First().ValueTable); } @@ -298,8 +297,8 @@ public void TableValueIsNotAddedToMissingSignalMessageId() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTableMap); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTable); } @@ -319,8 +318,8 @@ public void TableValueIsNotAddedToMissingSignalName() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTableMap); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTable); } @@ -342,8 +341,8 @@ public void NamedTableValuesAreAddedToSignal() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.AreEqual(testValuesDict, dbc.Messages.First().Signals.First().ValueTableMap); Assert.AreEqual("1 fake", dbc.Messages.First().Signals.First().ValueTable); } @@ -365,8 +364,8 @@ public void NamedTableValueIsNotAddedToMissingSignalMessageId() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTableMap); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTable); } @@ -388,8 +387,8 @@ public void NamedTableValueIsNotAddedToMissingSignalName() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTableMap); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTable); } @@ -408,8 +407,8 @@ public void NamedTableValueIsNotAddedIfTableNameDoesNotExist() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.IsNull(dbc.Messages.First().Signals.First().ValueTable); } @@ -462,8 +461,8 @@ public void NamedTablesWithSameNameOverridesPrevious() Assert.IsEmpty(dbc.Nodes); Assert.AreEqual(1, dbc.Messages.Count()); - Assert.AreEqual(message, dbc.Messages.First()); - Assert.AreEqual(signal, dbc.Messages.First().Signals.First()); + Assert.AreEqual(234, dbc.Messages.First().ID); + Assert.AreEqual("name1", dbc.Messages.First().Signals.First().Name); Assert.AreEqual(testValuesDict2, dbc.Messages.First().Signals.First().ValueTableMap); Assert.AreEqual("2 fake2", dbc.Messages.First().Signals.First().ValueTable); } diff --git a/DbcParserLib.Tests/ParserTests.cs b/DbcParserLib.Tests/ParserTests.cs index c248be8..229d719 100644 --- a/DbcParserLib.Tests/ParserTests.cs +++ b/DbcParserLib.Tests/ParserTests.cs @@ -282,5 +282,53 @@ public void ExplicitValTableIsAppliedTest() Assert.IsNotNull(signal); Assert.AreEqual(107, signal.ValueTable.Length); } + + [Test] + public void UserDefinedAttributesTest() + { + // This example is taken from kia_ev6.dbc + var dbcString = @" +BU_: XXX + +BO_ 1043 BLINKERS: 8 XXX + SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] """" XXX + SG_ LEFT_LAMP : 20|1@0+ (1,0) [0|1] """" XXX + SG_ RIGHT_LAMP : 22|1@0+ (1,0) [0|1] """" XXX + +BA_DEF_ BU_ ""HexAttribute"" HEX 0 100; +BA_DEF_ BO_ ""IntegerAttribute"" INT 0 10; +BA_DEF_ BO_ ""FloatAttribute"" FLOAT 0 1; +BA_DEF_ SG_ ""StringAttribute"" STRING; +BA_DEF_ SG_ ""EnumAttributeName"" ENUM ""FirstVal"",""SecondVal"",""ThirdVal""; + +BA_DEF_DEF_ ""HexAttribute"" 50; +BA_DEF_DEF_ ""IntegerAttribute"" 5; +BA_DEF_DEF_ ""FloatAttribute"" 0.5; +BA_DEF_DEF_ ""StringAttribute"" ""DefaultString""; +BA_DEF_DEF_ ""EnumAttributeName"" ""FirstVal""; + +BA_ ""HexAttribute"" BU_ XXX 70; +BA_ ""IntegerAttribute"" BO_ 1043 7; +BA_ ""EnumAttributeName"" SG_ 1043 COUNTER_ALT ""ThirdVal""; "; + + var dbc = Parser.Parse(dbcString); + Assert.AreEqual(1, dbc.Messages.Count()); + Assert.AreEqual(1, dbc.Nodes.Count()); + + var node = dbc.Nodes.First(); + Assert.AreEqual(1, node.CustomProperties.Count()); + Assert.AreEqual(70, node.CustomProperties["HexAttribute"].IntegerCustomProperty.Value); + + var message = dbc.Messages.First(); + Assert.AreEqual(2, message.CustomProperties.Count()); + Assert.AreEqual(7, message.CustomProperties["IntegerAttribute"].IntegerCustomProperty.Value); + Assert.AreEqual(0.5, message.CustomProperties["FloatAttribute"].FloatCustomProperty.Value); + + var signal = dbc.Messages.Single().Signals.FirstOrDefault(x => x.Name.Equals("COUNTER_ALT")); + Assert.IsNotNull(signal); + Assert.AreEqual(2, signal.CustomProperties.Count()); + Assert.AreEqual("ThirdVal", signal.CustomProperties["EnumAttributeName"].EnumCustomProperty.Value); + Assert.AreEqual("DefaultString", signal.CustomProperties["StringAttribute"].StringCustomProperty.Value); + } } } \ No newline at end of file diff --git a/DbcParserLib.Tests/PropertiesLineParserTests.cs b/DbcParserLib.Tests/PropertiesLineParserTests.cs index 0cc764a..59bfd9c 100644 --- a/DbcParserLib.Tests/PropertiesLineParserTests.cs +++ b/DbcParserLib.Tests/PropertiesLineParserTests.cs @@ -4,18 +4,109 @@ using Moq; using System.Linq; using System.IO; +using System.Collections.Generic; namespace DbcParserLib.Tests { public class PropertiesLineParserTests { - private static ILineParser CreateParser() + 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() + { + return new List() { + new PropertiesLineParser(), + new PropertiesDefinitionLineParser() + }; + } + + 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 IntDefinitionCustomPropertyIsParsedTest() + { + var builder = new DbcBuilder(); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" INT 5 10;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" 7;", sigInitialValueLineParser, builder, nextLineProvider)); + } + + [Test] + public void FloatDefinitionCustomPropertyIsParsedTest() { - return new PropertiesLineParser(); + var builder = new DbcBuilder(); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" FLOAT 5 10.5;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" 7.5;", sigInitialValueLineParser, builder, nextLineProvider)); + } + + [Test] + public void ScientificNotationDefinitionCustomPropertyIsParsedTest() + { + var dbcBuilderMock = m_repository.Create(); + var nextLineProviderMock = m_repository.Create(); + + dbcBuilderMock.Setup(mock => mock.AddCustomProperty(It.IsAny(), It.IsAny())) + .Callback((objectType, customProperty) => + { + Assert.AreEqual("AttributeName", customProperty.Name); + Assert.AreEqual(DbcDataType.Float, customProperty.DataType); + Assert.AreEqual(0, customProperty.FloatCustomProperty.Minimum); + Assert.AreEqual(0.1, customProperty.FloatCustomProperty.Maximum); + }); + + var sigInitialValueLineParser = CreateParser(); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" FLOAT 0 1e-1;", sigInitialValueLineParser, dbcBuilderMock.Object, nextLineProviderMock.Object)); + } + + [Test] + public void StringDefinitionCustomPropertyIsParsedTest() + { + var builder = new DbcBuilder(); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" STRING;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" ""DefaultString"";", sigInitialValueLineParser, builder, nextLineProvider)); } [Test] - public void MsgCycleTimeIsParsed() + public void EnumDefinitionCustomPropertyIsParsedTest() + { + var builder = new DbcBuilder(); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" ENUM ""Val1"",""Val2"",""Val3"";", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" ""Val2"";", sigInitialValueLineParser, builder, nextLineProvider)); + } + + [Test] + public void MsgCustomPropertyIsParsedTest() { var builder = new DbcBuilder(); var message = new Message { ID = 2394947585 }; @@ -24,14 +115,16 @@ public void MsgCycleTimeIsParsed() var msgCycleTimeLineParser = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); - Assert.IsTrue(msgCycleTimeLineParser.TryParse(@"BA_ ""GenMsgCycleTime"" BO_ 2394947585 100;", builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BO_ ""GenMsgCycleTime"" INT 0 200;", msgCycleTimeLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""GenMsgCycleTime"" 150;", msgCycleTimeLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_ ""GenMsgCycleTime"" BO_ 2394947585 100;", msgCycleTimeLineParser, builder, nextLineProvider)); var dbc = builder.Build(); Assert.AreEqual(100, dbc.Messages.First().CycleTime); } [Test] - public void SigInitalValueIsParsed() + public void SigCustomPropertyIsParsedTest() { var builder = new DbcBuilder(); var message = new Message { ID = 2394947585 }; @@ -42,11 +135,86 @@ public void SigInitalValueIsParsed() var sigInitialValueLineParser = CreateParser(); var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); - Assert.IsTrue(sigInitialValueLineParser.TryParse(@"BA_ ""GenSigStartValue"" SG_ 2394947585 sig_name 40;", builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_ SG_ ""GenSigStartValue"" INT 0 200;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""GenSigStartValue"" 150;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_ ""GenSigStartValue"" SG_ 2394947585 sig_name 40;", sigInitialValueLineParser, builder, nextLineProvider)); var dbc = builder.Build(); Assert.AreEqual(40, dbc.Messages.First().Signals.First().InitialValue); } + [Test] + public void NodeCustomPropertyIsParsedTest() + { + var builder = new DbcBuilder(); + var node = new Node { Name = "Node1" }; + builder.AddNode(node); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" HEX 0 200;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" 150;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_ ""AttributeName"" BU_ Node1 40;", sigInitialValueLineParser, builder, nextLineProvider)); + } + + [Test] + public void NodeScientificNotationCustomPropertyIsParsedTest() + { + var builder = new DbcBuilder(); + var node = new Node { Name = "Node1" }; + builder.AddNode(node); + + var dbc = builder.Build(); + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" FLOAT 0 10;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" 5;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_ ""AttributeName"" BU_ Node1 0.7e1;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.AreEqual(dbc.Nodes.First().CustomProperties.First().Value.FloatCustomProperty.Value, 7); + } + + [Test] + public void NodeMultipleCustomPropertyAreParsedTest() + { + var builder = new DbcBuilder(); + var node = new Node { Name = "Node1" }; + builder.AddNode(node); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName1"" INT 0 200;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName1"" 100;", sigInitialValueLineParser, builder, nextLineProvider)); + + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName2"" FLOAT 0 10;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName2"" 5.5;", sigInitialValueLineParser, builder, nextLineProvider)); + + Assert.IsTrue(ParseLine(@"BA_ ""AttributeName1"" BU_ Node1 40;", sigInitialValueLineParser, builder, nextLineProvider)); + + var dbc = builder.Build(); + Assert.AreEqual(2, dbc.Nodes.First().CustomProperties.Count); + Assert.AreEqual(5.5, dbc.Nodes.First().CustomProperties["AttributeName2"].FloatCustomProperty.Value); + } + + [Test] + public void CustomPropertyIsAssignedToDifferentNodesTest() + { + var builder = new DbcBuilder(); + var node1 = new Node { Name = "Node1" }; + var node2 = new Node { Name = "Node2" }; + builder.AddNode(node1); + builder.AddNode(node2); + + var sigInitialValueLineParser = CreateParser(); + var nextLineProvider = new NextLineProvider(new StringReader(string.Empty)); + Assert.IsTrue(ParseLine(@"BA_DEF_ BU_ ""AttributeName"" INT 0 200;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_DEF_DEF_ ""AttributeName"" 100;", sigInitialValueLineParser, builder, nextLineProvider)); + + Assert.IsTrue(ParseLine(@"BA_ ""AttributeName"" BU_ Node1 40;", sigInitialValueLineParser, builder, nextLineProvider)); + Assert.IsTrue(ParseLine(@"BA_ ""AttributeName"" BU_ Node2 70;", sigInitialValueLineParser, builder, nextLineProvider)); + + var dbc = builder.Build(); + Assert.AreEqual(40, dbc.Nodes.First().CustomProperties["AttributeName"].IntegerCustomProperty.Value); + Assert.AreEqual(70, dbc.Nodes.ElementAt(1).CustomProperties["AttributeName"].IntegerCustomProperty.Value); + } } } \ No newline at end of file diff --git a/DbcParserLib/Dbc.cs b/DbcParserLib/Dbc.cs index c630091..1d16a60 100644 --- a/DbcParserLib/Dbc.cs +++ b/DbcParserLib/Dbc.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; using DbcParserLib.Model; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("DbcParserLib.Tests")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] namespace DbcParserLib { public class Dbc diff --git a/DbcParserLib/DbcBuilder.cs b/DbcParserLib/DbcBuilder.cs index 12be7cf..0497173 100644 --- a/DbcParserLib/DbcBuilder.cs +++ b/DbcParserLib/DbcBuilder.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using System.Xml.Linq; using DbcParserLib.Model; namespace DbcParserLib @@ -11,12 +13,17 @@ internal class ValuesTable public string ValueTable { get; set; } } - public class DbcBuilder : IDbcBuilder + internal class DbcBuilder : IDbcBuilder { private readonly ISet m_nodes = new HashSet(new NodeEqualityComparer()); private readonly IDictionary m_namedTablesMap = new Dictionary(); private readonly IDictionary m_messages = new Dictionary(); private readonly IDictionary> m_signals = new Dictionary>(); + private readonly IDictionary> m_customProperties = new Dictionary>() { + {DbcObjectType.Node, new Dictionary()}, + {DbcObjectType.Message, new Dictionary()}, + {DbcObjectType.Signal, new Dictionary()}, + }; private Message m_currentMessage; @@ -41,6 +48,64 @@ public void AddSignal(Signal signal) } } + public void AddCustomProperty(DbcObjectType objectType, CustomPropertyDefinition customProperty) + { + m_customProperties[objectType][customProperty.Name] = customProperty; + } + + public void AddCustomPropertyDefaultValue(string propertyName, string value) + { + foreach(var objectType in m_customProperties.Keys) + { + if (m_customProperties[objectType].TryGetValue(propertyName, out var customProperty)) + { + customProperty.SetCustomPropertyDefaultValue(value); + } + } + } + + public void AddNodeCustomProperty(string propertyName, string nodeName, string value) + { + if(m_customProperties[DbcObjectType.Node].TryGetValue(propertyName, out var customProperty)) + { + var node = m_nodes.FirstOrDefault(n => n.Name.Equals(nodeName)); + if (node != null) + { + var property = new CustomProperty(customProperty); + property.SetCustomPropertyValue(value); + node.CustomProperties[propertyName] = property; + } + } + } + + public void AddMessageCustomProperty(string propertyName, uint messageId, string value) + { + if (m_customProperties[DbcObjectType.Message].TryGetValue(propertyName, out var customProperty)) + { + IsExtID(ref messageId); + if (m_messages.TryGetValue(messageId, out var message)) + { + var property = new CustomProperty(customProperty); + property.SetCustomPropertyValue(value); + message.CustomProperties[propertyName] = property; + } + } + } + + public void AddSignalCustomProperty(string propertyName, uint messageId, string signalName, string value) + { + if (m_customProperties[DbcObjectType.Signal].TryGetValue(propertyName, out var customProperty)) + { + IsExtID(ref messageId); + if (TryGetValueMessageSignal(messageId, signalName, out var signal)) + { + var property = new CustomProperty(customProperty); + property.SetCustomPropertyValue(value); + signal.CustomProperties[propertyName] = property; + } + } + } + public void AddSignalComment(uint messageId, string signalName, string comment) { if (TryGetValueMessageSignal(messageId, signalName, out var signal)) @@ -122,6 +187,14 @@ public static bool IsExtID(ref uint id) return false; } + public void LinkNamedTableToSignal(uint messageId, string signalName, string tableName) + { + if (m_namedTablesMap.TryGetValue(tableName, out var valuesTable)) + { + LinkTableValuesToSignal(messageId, signalName, valuesTable.ValueTableMap, valuesTable.ValueTable); + } + } + private bool TryGetValueMessageSignal(uint messageId, string signalName, out Signal signal) { if (m_signals.TryGetValue(messageId, out var signals) && signals.TryGetValue(signalName, out signal)) @@ -133,16 +206,60 @@ private bool TryGetValueMessageSignal(uint messageId, string signalName, out Sig return false; } - public void LinkNamedTableToSignal(uint messageId, string signalName, string tableName) + private void FillNodesNotSetCustomPropertyWithDefault() { - if (m_namedTablesMap.TryGetValue(tableName, out var valuesTable)) + var nodeCustomProperties = m_customProperties[DbcObjectType.Node]; + foreach (var customProperty in nodeCustomProperties) { - LinkTableValuesToSignal(messageId, signalName, valuesTable.ValueTableMap, valuesTable.ValueTable); + foreach (var node in m_nodes) + { + if (!node.CustomProperties.TryGetValue(customProperty.Key, out var property)) + { + node.CustomProperties[customProperty.Key] = new CustomProperty(customProperty.Value); + node.CustomProperties[customProperty.Key].SetCustomPropertyValueFromDefault(); + } + } + } + } + + private void FillMesagesNotSetCustomPropertyWithDefault() + { + var messageCustomProperties = m_customProperties[DbcObjectType.Message]; + foreach (var customProperty in messageCustomProperties) + { + foreach (var message in m_messages.Values) + { + FillSignalsNotSetCustomPropertyWithDefault(message.ID); + if (!message.CustomProperties.TryGetValue(customProperty.Key, out var property)) + { + message.CustomProperties[customProperty.Key] = new CustomProperty(customProperty.Value); + message.CustomProperties[customProperty.Key].SetCustomPropertyValueFromDefault(); + } + } + } + } + + private void FillSignalsNotSetCustomPropertyWithDefault(uint messageId) + { + var signalCustomProperties = m_customProperties[DbcObjectType.Signal]; + foreach (var customProperty in signalCustomProperties) + { + foreach (var signal in m_signals[messageId].Values) + { + if (!signal.CustomProperties.TryGetValue(customProperty.Key, out var property)) + { + signal.CustomProperties[customProperty.Key] = new CustomProperty(customProperty.Value); + signal.CustomProperties[customProperty.Key].SetCustomPropertyValueFromDefault(); + } + } } } public Dbc Build() { + FillNodesNotSetCustomPropertyWithDefault(); + FillMesagesNotSetCustomPropertyWithDefault(); + foreach (var message in m_messages) { message.Value.Signals.Clear(); @@ -153,7 +270,7 @@ public Dbc Build() } } - internal class NodeEqualityComparer : IEqualityComparer +internal class NodeEqualityComparer : IEqualityComparer { public bool Equals(Node b1, Node b2) { diff --git a/DbcParserLib/IDbcBuilder.cs b/DbcParserLib/IDbcBuilder.cs index 81404a7..b5b5aab 100644 --- a/DbcParserLib/IDbcBuilder.cs +++ b/DbcParserLib/IDbcBuilder.cs @@ -3,7 +3,7 @@ namespace DbcParserLib { - public interface IDbcBuilder + internal interface IDbcBuilder { void AddMessage(Message message); void AddMessageComment(uint messageId, string comment); @@ -17,5 +17,10 @@ public interface IDbcBuilder void AddSignalValueType(uint messageId, string signalName, DbcValueType valueType); void LinkNamedTableToSignal(uint messageId, string signalName, string tableName); void LinkTableValuesToSignal(uint messageId, string signalName, IReadOnlyDictionary dictValues, string stringValues); + void AddCustomProperty(DbcObjectType objectType, CustomPropertyDefinition customProperty); + void AddCustomPropertyDefaultValue(string propertyName, string value); + void AddNodeCustomProperty(string propertyName, string nodeName, string value); + void AddMessageCustomProperty(string propertyName, uint messageId, string value); + void AddSignalCustomProperty(string propertyName, uint messageId, string signalName, string value); } } \ No newline at end of file diff --git a/DbcParserLib/Model/CustomProperty.cs b/DbcParserLib/Model/CustomProperty.cs new file mode 100644 index 0000000..9aefd89 --- /dev/null +++ b/DbcParserLib/Model/CustomProperty.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace DbcParserLib.Model +{ + public class CustomProperty + { + public readonly CustomPropertyDefinition m_customPropertyDefinition; + + public CustomProperty(CustomPropertyDefinition customPropertyDefinition) + { + m_customPropertyDefinition = customPropertyDefinition; + } + + public CustomPropertyValue IntegerCustomProperty { get; set; } + public CustomPropertyValue HexCustomProperty { get; set; } + public CustomPropertyValue FloatCustomProperty { get; set; } + public CustomPropertyValue StringCustomProperty { get; set; } + public CustomPropertyValue EnumCustomProperty { get; set; } + + public void SetCustomPropertyValue(string value) + { + switch (m_customPropertyDefinition.DataType) + { + case DbcDataType.Integer: + IntegerCustomProperty = new CustomPropertyValue() + { + Value = int.Parse(value, CultureInfo.InvariantCulture) + }; + break; + case DbcDataType.Hex: + HexCustomProperty = new CustomPropertyValue() + { + Value = int.Parse(value, CultureInfo.InvariantCulture) + }; + break; + case DbcDataType.Float: + FloatCustomProperty = new CustomPropertyValue() + { + Value = float.Parse(value, CultureInfo.InvariantCulture) + }; + break; + case DbcDataType.String: + StringCustomProperty = new CustomPropertyValue() + { + Value = value + }; + break; + case DbcDataType.Enum: + EnumCustomProperty = new CustomPropertyValue() + { + Value = value + }; + break; + } + } + + public void SetCustomPropertyValueFromDefault() + { + switch (m_customPropertyDefinition.DataType) + { + case DbcDataType.Integer: + IntegerCustomProperty = new CustomPropertyValue() + { + Value = m_customPropertyDefinition.IntegerCustomProperty.Default + }; + break; + case DbcDataType.Hex: + HexCustomProperty = new CustomPropertyValue() + { + Value = m_customPropertyDefinition.HexCustomProperty.Default + }; + break; + case DbcDataType.Float: + FloatCustomProperty = new CustomPropertyValue() + { + Value = m_customPropertyDefinition.FloatCustomProperty.Default + }; + break; + case DbcDataType.String: + StringCustomProperty = new CustomPropertyValue() + { + Value = m_customPropertyDefinition.StringCustomProperty.Default + }; + break; + case DbcDataType.Enum: + EnumCustomProperty = new CustomPropertyValue() + { + Value = m_customPropertyDefinition.EnumCustomProperty.Default + }; + break; + } + } + } + + public class CustomPropertyValue + { + public T Value { get; set; } + } +} diff --git a/DbcParserLib/Model/CustomPropertyDefinition.cs b/DbcParserLib/Model/CustomPropertyDefinition.cs new file mode 100644 index 0000000..2cbbc30 --- /dev/null +++ b/DbcParserLib/Model/CustomPropertyDefinition.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace DbcParserLib.Model +{ + public class CustomPropertyDefinition + { + public string Name { get; set; } + public DbcDataType DataType { get; set; } + public NumericCustomPropertyDefinition IntegerCustomProperty { get; set; } + public NumericCustomPropertyDefinition HexCustomProperty { get; set; } + public NumericCustomPropertyDefinition FloatCustomProperty { get; set; } + public StringCustomPropertyDefinition StringCustomProperty { get; set; } + public EnumCustomPropertyDefinition EnumCustomProperty { get; set; } + + public void SetCustomPropertyDefaultValue(string value) + { + switch (DataType) + { + case DbcDataType.Integer: + IntegerCustomProperty.Default = int.Parse(value, CultureInfo.InvariantCulture); + break; + case DbcDataType.Hex: + HexCustomProperty.Default = int.Parse(value, CultureInfo.InvariantCulture); + break; + case DbcDataType.Float: + FloatCustomProperty.Default = float.Parse(value, CultureInfo.InvariantCulture); + break; + case DbcDataType.String: + StringCustomProperty.Default = value; + break; + case DbcDataType.Enum: + EnumCustomProperty.Default = value; + break; + } + } + } + + public class NumericCustomPropertyDefinition + { + public T Maximum { get; set; } + public T Minimum { get; set; } + public T Default { get; set; } + } + + public class StringCustomPropertyDefinition + { + public string Default { get; set; } + } + + public class EnumCustomPropertyDefinition + { + public string Default { get; set; } + public string[] Values { get; set; } + } + + public enum DbcObjectType + { + Node, Message, Signal, Environment + } + + public enum DbcDataType + { + Integer, Hex, Float, String, Enum + } +} diff --git a/DbcParserLib/Model/Message.cs b/DbcParserLib/Model/Message.cs new file mode 100644 index 0000000..99babbc --- /dev/null +++ b/DbcParserLib/Model/Message.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DbcParserLib.Model +{ + internal class ImmutableMessage + { + public uint ID { get; } + public bool IsExtID { get; } + public string Name { get; } + public ushort DLC { get; } + public string Transmitter { get; } + public string Comment { get; } + public int CycleTime { get; } + public IReadOnlyList Signals { get; } + public IReadOnlyDictionary CustomProperties { get; } + + internal ImmutableMessage(Message message, IReadOnlyList signals) + { + ID = message.ID; + IsExtID = message.IsExtID; + Name = message.Name; + DLC = message.DLC; + Transmitter = message.Transmitter; + Comment = message.Comment; + CycleTime= message.CycleTime; + Signals = signals; + //TODO: remove explicit cast (CustomProperty in Message class should be Dictionary instead IDictionary) + CustomProperties = (IReadOnlyDictionary)message.CustomProperties; + } + } + + public class Message + { + public uint ID; + public bool IsExtID; + public string Name; + public ushort DLC; + public string Transmitter; + public string Comment; + public int CycleTime; + public List Signals = new List(); + public IDictionary CustomProperties = new Dictionary(); + + internal ImmutableMessage CreateMessage() + { + var signals = new List(); + foreach(var signal in Signals) + { + signals.Add(signal.CreateSignal()); + } + return new ImmutableMessage(this, signals); + } + } +} diff --git a/DbcParserLib/Model/Node.cs b/DbcParserLib/Model/Node.cs index 5488931..8829400 100644 --- a/DbcParserLib/Model/Node.cs +++ b/DbcParserLib/Model/Node.cs @@ -1,72 +1,33 @@ using System; +using System.Collections; using System.Collections.Generic; namespace DbcParserLib.Model { - public class Node + internal class ImmutableNode { - public string Name; - public string Comment; - } + public string Name { get; } + public string Comment { get; } + public IReadOnlyDictionary CustomProperties { get; } - public class Message - { - public uint ID; - public bool IsExtID; - public string Name; - public ushort DLC; - public string Transmitter; - public string Comment; - public int CycleTime; - public List Signals = new List(); + internal ImmutableNode(Node node) + { + Name = node.Name; + Comment = node.Comment; + //TODO: remove explicit cast (CustomProperty in Node class should be Dictionary instead IDictionary) + CustomProperties = (IReadOnlyDictionary)node.CustomProperties; + } } - public class Signal + public class Node { - private DbcValueType m_ValueType = DbcValueType.Signed; - - public uint ID; public string Name; - public ushort StartBit; - public ushort Length; - public byte ByteOrder = 1; - [Obsolete("Please use ValueType instead. IsSigned will be removed in future releases")] - public byte IsSigned { get; private set; } = 1; - public DbcValueType ValueType - { - get - { - return m_ValueType; - } - set - { - m_ValueType = value; - IsSigned = (byte)(value == DbcValueType.Unsigned ? 0 : 1); - } - } - public double InitialValue; - public double Factor = 1; - public bool IsInteger = false; - public double Offset; - public double Minimum; - public double Maximum; - public string Unit; - public string[] Receiver; - [Obsolete("Please use ValueTableMap instead. ValueTable will be removed in future releases")] - public string ValueTable { get; private set; } - public IReadOnlyDictionary ValueTableMap { get; private set; } public string Comment; - public string Multiplexing; + public IDictionary CustomProperties = new Dictionary(); - internal void SetValueTable(IReadOnlyDictionary dictValues, string stringValues) + internal ImmutableNode CreateNode() { - ValueTableMap = dictValues; - ValueTable = stringValues; + return new ImmutableNode(this); } } - - public enum DbcValueType - { - Signed, Unsigned, IEEEFloat, IEEEDouble - } } \ No newline at end of file diff --git a/DbcParserLib/Model/Signal.cs b/DbcParserLib/Model/Signal.cs new file mode 100644 index 0000000..74d955e --- /dev/null +++ b/DbcParserLib/Model/Signal.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DbcParserLib.Model +{ + internal class ImmutableSignal + { + public uint ID { get; } + public string Name { get; } + public ushort StartBit { get; } + public ushort Length { get; } + public byte ByteOrder { get; } + [Obsolete("Please use ValueType instead. IsSigned will be removed in future releases")] + public byte IsSigned { get; } + public DbcValueType ValueType { get; } + + public double InitialValue { get; } + public double Factor { get; } + public bool IsInteger { get; } + public double Offset { get; } + public double Minimum { get; } + public double Maximum { get; } + public string Unit { get; } + public string[] Receiver { get; } + [Obsolete("Please use ValueTableMap instead. ValueTable will be removed in future releases")] + public string ValueTable { get; } + public IReadOnlyDictionary ValueTableMap { get; } + public string Comment { get; } + public string Multiplexing { get; } + public IReadOnlyDictionary CustomProperties { get; } + + internal ImmutableSignal(Signal signal) + { + ID = signal.ID; + Name = signal.Name; + StartBit = signal.StartBit; + Length = signal.Length; + ByteOrder = signal.ByteOrder; + IsSigned = signal.IsSigned; + ValueType = signal.ValueType; + InitialValue = signal.InitialValue; + Factor = signal.Factor; + IsInteger = signal.IsInteger; + Offset = signal.Offset; + Minimum = signal.Minimum; + Maximum = signal.Maximum; + Unit = signal.Unit; + Receiver = signal.Receiver; + ValueTable = signal.ValueTable; + ValueTableMap = signal.ValueTableMap; + Comment = signal.Comment; + Multiplexing = signal.Multiplexing; + //TODO: remove explicit cast (CustomProperty in Signal class should be Dictionary instead IDictionary) + CustomProperties = (IReadOnlyDictionary)signal.CustomProperties; + } + } + + public class Signal + { + private DbcValueType m_ValueType = DbcValueType.Signed; + + public uint ID; + public string Name; + public ushort StartBit; + public ushort Length; + public byte ByteOrder = 1; + [Obsolete("Please use ValueType instead. IsSigned will be removed in future releases")] + public byte IsSigned { get; private set; } = 1; + public DbcValueType ValueType + { + get + { + return m_ValueType; + } + set + { + m_ValueType = value; + IsSigned = (byte)(value == DbcValueType.Unsigned ? 0 : 1); + } + } + public double InitialValue; + public double Factor = 1; + public bool IsInteger = false; + public double Offset; + public double Minimum; + public double Maximum; + public string Unit; + public string[] Receiver; + [Obsolete("Please use ValueTableMap instead. ValueTable will be removed in future releases")] + public string ValueTable { get; private set; } + public IReadOnlyDictionary ValueTableMap { get; private set; } + public string Comment; + public string Multiplexing; + public readonly IDictionary CustomProperties = new Dictionary(); + + internal void SetValueTable(IReadOnlyDictionary dictValues, string stringValues) + { + ValueTableMap = dictValues; + ValueTable = stringValues; + } + + internal ImmutableSignal CreateSignal() + { + return new ImmutableSignal(this); + } + } + + public enum DbcValueType + { + Signed, Unsigned, IEEEFloat, IEEEDouble + } +} diff --git a/DbcParserLib/Parser.cs b/DbcParserLib/Parser.cs index 520b2e9..5dd51bb 100644 --- a/DbcParserLib/Parser.cs +++ b/DbcParserLib/Parser.cs @@ -18,6 +18,7 @@ public static class Parser new SignalValueTypeLineParser(), new ValueTableLineParser(), new PropertiesLineParser(), + new PropertiesDefinitionLineParser(), new UnknownLineParser() // Used as a catch all }; diff --git a/DbcParserLib/Parsers/CommentLineParser.cs b/DbcParserLib/Parsers/CommentLineParser.cs index 0332e15..c6a3046 100644 --- a/DbcParserLib/Parsers/CommentLineParser.cs +++ b/DbcParserLib/Parsers/CommentLineParser.cs @@ -6,7 +6,7 @@ namespace DbcParserLib.Parsers { - public class CommentLineParser : ILineParser + internal class CommentLineParser : ILineParser { private const string CommentLineStarter = "CM_ "; private const string NodeParsingRegex = @"CM_ BU_\s+([a-zA-Z_][\w]*)\s+""*([^""]*)""*\s*;"; diff --git a/DbcParserLib/Parsers/ILineParser.cs b/DbcParserLib/Parsers/ILineParser.cs index 6427729..1f0bc83 100644 --- a/DbcParserLib/Parsers/ILineParser.cs +++ b/DbcParserLib/Parsers/ILineParser.cs @@ -1,6 +1,6 @@ namespace DbcParserLib.Parsers { - public interface ILineParser + internal interface ILineParser { bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider); } diff --git a/DbcParserLib/Parsers/IgnoreLineParser.cs b/DbcParserLib/Parsers/IgnoreLineParser.cs index c47f163..859b5b9 100644 --- a/DbcParserLib/Parsers/IgnoreLineParser.cs +++ b/DbcParserLib/Parsers/IgnoreLineParser.cs @@ -1,6 +1,6 @@ namespace DbcParserLib.Parsers { - public class IgnoreLineParser : ILineParser + internal class IgnoreLineParser : ILineParser { public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { diff --git a/DbcParserLib/Parsers/MessageLineParser.cs b/DbcParserLib/Parsers/MessageLineParser.cs index dfc168f..0c660c6 100644 --- a/DbcParserLib/Parsers/MessageLineParser.cs +++ b/DbcParserLib/Parsers/MessageLineParser.cs @@ -4,7 +4,7 @@ namespace DbcParserLib.Parsers { - public class MessageLineParser : ILineParser + internal class MessageLineParser : ILineParser { private const string MessageLineStarter = "BO_ "; private const string MessageRegex = @"BO_ (\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)"; diff --git a/DbcParserLib/Parsers/NodeLineParser.cs b/DbcParserLib/Parsers/NodeLineParser.cs index d3c018d..d399b6a 100644 --- a/DbcParserLib/Parsers/NodeLineParser.cs +++ b/DbcParserLib/Parsers/NodeLineParser.cs @@ -3,7 +3,7 @@ namespace DbcParserLib.Parsers { - public class NodeLineParser : ILineParser + internal class NodeLineParser : ILineParser { private const string NodeLineStarter = "BU_:"; diff --git a/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs new file mode 100644 index 0000000..be78eff --- /dev/null +++ b/DbcParserLib/Parsers/PropertiesDefinitionLineParser.cs @@ -0,0 +1,96 @@ +using DbcParserLib.Model; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace DbcParserLib.Parsers +{ + internal class PropertiesDefinitionLineParser : ILineParser + { + private const string PropertiesDefinitionLineStarter = "BA_DEF_ "; + private const string PropertiesDefinitionDefaultLineStarter = "BA_DEF_DEF_ "; + private const string PropertyDefinitionParsingRegex = @"BA_DEF_\s+(?:(BU_|BO_|SG_|EV_)\s+)?""([a-zA-Z_][\w]*)""\s+(?:(?:(INT|HEX)\s+(-?\d+)\s+(-?\d+))|(?:(FLOAT)\s+([\d\+\-eE.]+)\s+([\d\+\-eE.]+))|(STRING)|(ENUM\s+(?:""[^""]*"",*){1,100}))\s*;"; + private const string PropertyDefinitionDefaultParsingRegex = @"BA_DEF_DEF_\s+""([a-zA-Z_][\w]*)""\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"")\s*;"; + + public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) + { + var cleanLine = line.Trim(' '); + + if (cleanLine.StartsWith(PropertiesDefinitionLineStarter) == false + && cleanLine.StartsWith(PropertiesDefinitionDefaultLineStarter) == false) + return false; + + if (cleanLine.StartsWith(PropertiesDefinitionDefaultLineStarter)) + { + var match = Regex.Match(cleanLine, PropertyDefinitionDefaultParsingRegex); + if (match.Success) + { + builder.AddCustomPropertyDefaultValue(match.Groups[1].Value, match.Groups[2].Value.Replace("\"", "")); + } + return true; + } + + if (cleanLine.StartsWith(PropertiesDefinitionLineStarter)) + { + var match = Regex.Match(cleanLine, PropertyDefinitionParsingRegex); + if (match.Success) + { + var customProperty = new CustomPropertyDefinition + { + Name = match.Groups[2].Value, + }; + + DbcObjectType objectType = DbcObjectType.Node; + switch (match.Groups[1].Value) + { + case "BO_": + objectType = DbcObjectType.Message; break; + case "SG_": + objectType = DbcObjectType.Signal; break; + case "EV_": + objectType = DbcObjectType.Environment; break; + } + + DbcDataType dataType = DbcDataType.Integer; + if (match.Groups[3].Value == "INT" || match.Groups[3].Value == "HEX") + { + customProperty.IntegerCustomProperty = new NumericCustomPropertyDefinition + { + Minimum = int.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture), + Maximum = int.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), + }; + } + else if (match.Groups[6].Value == "FLOAT") + { + dataType = DbcDataType.Float; + customProperty.FloatCustomProperty = new NumericCustomPropertyDefinition + { + Minimum = double.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), + Maximum = double.Parse(match.Groups[8].Value, CultureInfo.InvariantCulture), + }; + } + else if (match.Groups[9].Value == "STRING") + { + dataType = DbcDataType.String; + customProperty.StringCustomProperty = new StringCustomPropertyDefinition(); + } + else if (match.Groups[10].Value.StartsWith("ENUM ")) + { + dataType = DbcDataType.Enum; + var enumDefinition = match.Groups[10].Value.Replace("\"", "").Split(' ')[1]; + customProperty.EnumCustomProperty = new EnumCustomPropertyDefinition + { + Values = enumDefinition.Split(','), + }; + } + customProperty.DataType = dataType; + builder.AddCustomProperty(objectType, customProperty); + } + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/DbcParserLib/Parsers/PropertiesLineParser.cs b/DbcParserLib/Parsers/PropertiesLineParser.cs index 5190c06..1159edb 100644 --- a/DbcParserLib/Parsers/PropertiesLineParser.cs +++ b/DbcParserLib/Parsers/PropertiesLineParser.cs @@ -2,51 +2,45 @@ using System; using System.Globalization; using System.Linq; +using System.Text.RegularExpressions; namespace DbcParserLib.Parsers { - public class PropertiesLineParser : ILineParser + internal class PropertiesLineParser : ILineParser { private const string PropertiesLineStarter = "BA_ "; + private const string PropertyParsingRegex = @"BA_\s+""([a-zA-Z_][\w]*)""(?:\s+(?:(BU_|EV_)\s+([a-zA-Z_][\w]*))|\s+(?:(BO_)\s+(\d+))|\s+(?:(SG_)\s+(\d+)\s+([a-zA-Z_][\w]*)))?\s+(-?\d+|[\d\+\-eE.]+|""[^""]*"");"; public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { - var cleanLine = line.Trim(' ', ';'); + var cleanLine = line.Trim(' '); if (cleanLine.StartsWith(PropertiesLineStarter) == false) return false; - if (cleanLine.StartsWith("BA_ \"GenMsgCycleTime\" BO_")) + if (cleanLine.StartsWith(PropertiesLineStarter)) { - SetMessageCycleTime(cleanLine, builder); + var match = Regex.Match(cleanLine, PropertyParsingRegex); + if (match.Success) + { + if (match.Groups[2].Value == "BU_") + builder.AddNodeCustomProperty(match.Groups[1].Value, match.Groups[3].Value, match.Groups[9].Value.Replace("\"", "")); + else if (match.Groups[4].Value == "BO_") + { + builder.AddMessageCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), match.Groups[9].Value.Replace("\"", "")); + if (match.Groups[1].Value == "GenMsgCycleTime") + builder.AddMessageCycleTime(uint.Parse(match.Groups[5].Value, CultureInfo.InvariantCulture), int.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); + } + else if (match.Groups[6].Value == "SG_") + { + builder.AddSignalCustomProperty(match.Groups[1].Value, uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, match.Groups[9].Value.Replace("\"", "")); + if (match.Groups[1].Value == "GenSigStartValue") + builder.AddSignalInitialValue(uint.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture), match.Groups[8].Value, double.Parse(match.Groups[9].Value, CultureInfo.InvariantCulture)); + } + } return true; } - - if (cleanLine.StartsWith("BA_ \"GenSigStartValue\" SG_")) - { - SetSignalInitialValue(cleanLine, builder); - return true; - } - return false; } - - private static void SetMessageCycleTime(string msgCycleTimeStr, IDbcBuilder builder) - { - string[] records = msgCycleTimeStr.SplitBySpace(); - if (records.Length > 4 && uint.TryParse(records[3], out var messageId)) - { - builder.AddMessageCycleTime(messageId, int.Parse(records[4], CultureInfo.InvariantCulture)); - } - } - - private static void SetSignalInitialValue(string sigInitialValueStr, IDbcBuilder builder) - { - string[] records = sigInitialValueStr.SplitBySpace(); - if (records.Length > 4 && uint.TryParse(records[3], out var messageId)) - { - builder.AddSignalInitialValue(messageId, records[4], double.Parse(records[5], CultureInfo.InvariantCulture)); - } - } } } \ No newline at end of file diff --git a/DbcParserLib/Parsers/SignalLineParser.cs b/DbcParserLib/Parsers/SignalLineParser.cs index 845e737..b523713 100644 --- a/DbcParserLib/Parsers/SignalLineParser.cs +++ b/DbcParserLib/Parsers/SignalLineParser.cs @@ -6,7 +6,7 @@ namespace DbcParserLib.Parsers { - public class SignalLineParser : ILineParser + internal class SignalLineParser : ILineParser { private delegate void ParsingStrategy(string line, IDbcBuilder builder); diff --git a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs index d4c78b6..1ebf482 100644 --- a/DbcParserLib/Parsers/SignalValueTypeLineParser.cs +++ b/DbcParserLib/Parsers/SignalValueTypeLineParser.cs @@ -3,7 +3,7 @@ namespace DbcParserLib.Parsers { - public class SignalValueTypeLineParser : ILineParser + internal class SignalValueTypeLineParser : ILineParser { private const string SignalValueTypeStarter = "SIG_VALTYPE_ "; diff --git a/DbcParserLib/Parsers/UnknownLineParser.cs b/DbcParserLib/Parsers/UnknownLineParser.cs index 7149e6a..636b263 100644 --- a/DbcParserLib/Parsers/UnknownLineParser.cs +++ b/DbcParserLib/Parsers/UnknownLineParser.cs @@ -1,6 +1,6 @@ namespace DbcParserLib.Parsers { - public class UnknownLineParser : ILineParser + internal class UnknownLineParser : ILineParser { public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLineProvider) { diff --git a/DbcParserLib/Parsers/ValueTableLineParser.cs b/DbcParserLib/Parsers/ValueTableLineParser.cs index fb28f68..c71a6f5 100644 --- a/DbcParserLib/Parsers/ValueTableLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableLineParser.cs @@ -7,7 +7,7 @@ namespace DbcParserLib.Parsers { - public class ValueTableLineParser : ILineParser + internal class ValueTableLineParser : ILineParser { private const string ValueTableLineStarter = "VAL_";