diff --git a/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs b/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs index 6c02f169de..cf1e55ad86 100644 --- a/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs +++ b/Stack/Opc.Ua.Core/Types/Utils/RelativePath.cs @@ -354,6 +354,12 @@ public void TranslateNamespaceIndexes(NamespaceTable currentTable, NamespaceTabl { element.ReferenceTypeName = new QualifiedName(qname.Name, (ushort)mappings[qname.NamespaceIndex]); } + else + { + throw new ServiceResultException( + StatusCodes.BadIndexRangeInvalid, + Utils.Format("Cannot translate namespace index '{0}' to target namespace table.", qname.NamespaceIndex)); + } } qname = element.TargetName; @@ -364,6 +370,12 @@ public void TranslateNamespaceIndexes(NamespaceTable currentTable, NamespaceTabl { element.TargetName = new QualifiedName(qname.Name, (ushort)mappings[qname.NamespaceIndex]); } + else + { + throw new ServiceResultException( + StatusCodes.BadIndexRangeInvalid, + Utils.Format("Cannot translate namespace index '{0}' to target namespace table.", qname.NamespaceIndex)); + } } } } diff --git a/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilsTests.cs b/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilsTests.cs index 0fd8f272a6..2ba538b993 100644 --- a/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilsTests.cs +++ b/Tests/Opc.Ua.Core.Tests/Types/Utils/UtilsTests.cs @@ -298,6 +298,55 @@ public void RelativePathParseAlphanumericWithNamespaceIndexStringPath() Assert.AreEqual(str, RelativePath.Parse(str, typeTable).Format(typeTable)); } + /// + /// Parse path string containing two Namespaces, translate indexes + /// + [Theory] + [TestCase("<#2:HasChild>", "<#3:HasChild>")] + [TestCase("", "")] + [TestCase(".2:NodeVersion", ".3:NodeVersion")] + [TestCase("/1:abc/2:def", "/1:abc/3:def")] + public void RelativePathParseTranslateNamespaceIndexReferenceType(string input, string output) + { + var currentTable = new NamespaceTable(new List() { Namespaces.OpcUa, "1", Namespaces.OpcUaGds }); + var targetTable = new NamespaceTable(new List() { Namespaces.OpcUa, "1", "2", Namespaces.OpcUaGds }); + + TypeTable typeTable = new TypeTable(new NamespaceTable()); + typeTable.AddReferenceSubtype(Opc.Ua.ReferenceTypeIds.HasChild, NodeId.Null, new QualifiedName("HasChild", 3)); + Assert.AreEqual(output, RelativePath.Parse(input, typeTable, currentTable, targetTable).Format(typeTable)); + } + + + /// + /// Parse path string containing two Namespaces with missing namespace indexes in either currentTable or targetTable. + /// + [Theory] + [TestCase( + new string[] { Namespaces.OpcUa, "2", Namespaces.OpcUaGds }, + new string[] { Namespaces.OpcUa, "2", "3" }, + "/1:abc/2:def" + )] + [TestCase( + new string[] { Namespaces.OpcUa, "2", Namespaces.OpcUaGds }, + new string[] { Namespaces.OpcUa, "2", "3" }, + "<#2:HasChild>" + )] + [TestCase( + new string[] { Namespaces.OpcUa, "2", Namespaces.OpcUaGds }, + new string[] { Namespaces.OpcUa, "2", "3", "4", "5" }, + "/1:abc/4:def" + )] + public void RelativePathParseInvalidNamespaceIndex(string[] currentNamespaces, string[] targetNamespaces, string path) + { + var currentTable = new NamespaceTable(new List(currentNamespaces)); + var targetTable = new NamespaceTable(new List(targetNamespaces)); + + TypeTable typeTable = new TypeTable(new NamespaceTable()); + var sre = Assert.Throws(() => RelativePath.Parse(path, typeTable, currentTable, targetTable).Format(typeTable)); + Assert.AreEqual((StatusCode)StatusCodes.BadIndexRangeInvalid, (StatusCode)sre.StatusCode); + } + + /// /// Validate that XmlDocument DtdProcessing is protected against /// exponential entity expansion in this version of .NET.