From 5a2226629a45c9adef0fb6b83484a7b3c2eaf172 Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Sat, 15 Mar 2025 09:04:47 +0100 Subject: [PATCH] Implement EnumAdapter #17 --- MatFileHandler.Tests/ArrayHandlingTests.cs | 11 +++- MatFileHandler.Tests/MatFileReaderTests.cs | 25 +++++++- MatFileHandler.Tests/test-data/good/enum.mat | Bin 0 -> 569 bytes MatFileHandler/DataElementReader.cs | 2 +- MatFileHandler/EnumAdapter.cs | 60 +++++++++++++++++++ MatFileHandler/Opaque.cs | 9 ++- MatFileHandler/OpaqueLink.cs | 15 ++--- MatFileHandler/SubsystemData.cs | 18 ++++++ MatFileHandler/SubsystemDataReader.cs | 12 ++-- 9 files changed, 130 insertions(+), 22 deletions(-) create mode 100644 MatFileHandler.Tests/test-data/good/enum.mat create mode 100644 MatFileHandler/EnumAdapter.cs diff --git a/MatFileHandler.Tests/ArrayHandlingTests.cs b/MatFileHandler.Tests/ArrayHandlingTests.cs index f15599e..7ac644b 100755 --- a/MatFileHandler.Tests/ArrayHandlingTests.cs +++ b/MatFileHandler.Tests/ArrayHandlingTests.cs @@ -10,8 +10,11 @@ namespace MatFileHandler.Tests /// /// Tests of Matlab array manipulation. /// - public class ArrayHandlingTests : IDisposable + public sealed class ArrayHandlingTests : IDisposable { + /// + /// Setup for array handling tests. + /// public ArrayHandlingTests() { Builder = new DataBuilder(); @@ -108,7 +111,7 @@ namespace MatFileHandler.Tests var file = Builder.NewFile(new List()); Assert.NotNull(file); } - + private static void TestCreateArrayOf() where T : struct { @@ -116,8 +119,12 @@ namespace MatFileHandler.Tests Assert.NotNull(array); } + /// + /// Cleanup. + /// public void Dispose() { + } } } \ No newline at end of file diff --git a/MatFileHandler.Tests/MatFileReaderTests.cs b/MatFileHandler.Tests/MatFileReaderTests.cs index 8645b82..a06ad71 100755 --- a/MatFileHandler.Tests/MatFileReaderTests.cs +++ b/MatFileHandler.Tests/MatFileReaderTests.cs @@ -164,6 +164,23 @@ namespace MatFileHandler.Tests Assert.Null(array.ConvertToComplexArray()); } + /// + /// Test reading an enumeration. + /// + [Fact] + public void TestEnum() + { + var matFile = GetTests("good")["enum"]; + var days = matFile["days"].Value; + var enumeration = new EnumAdapter(days); + Assert.Equal(5, enumeration.Values.Count); + Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[0]]); + Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[1]]); + Assert.Equal("Monday", enumeration.ValueNames[enumeration.Values[2]]); + Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[3]]); + Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[4]]); + } + /// /// Test reading a structure array. /// @@ -487,6 +504,9 @@ namespace MatFileHandler.Tests Assert.Null(d0); } + /// + /// Test 3-dimensional arrays. + /// [Fact] public void Test_3DArrays() { @@ -518,7 +538,10 @@ namespace MatFileHandler.Tests Assert.Equal(expected, obj.ConvertToMultidimensionalDoubleArray()); Assert.Null(obj.ConvertTo2dDoubleArray()); } - + + /// + /// Test four-dimensional arrays. + /// [Fact] public void Test_4DArrays() { diff --git a/MatFileHandler.Tests/test-data/good/enum.mat b/MatFileHandler.Tests/test-data/good/enum.mat new file mode 100644 index 0000000000000000000000000000000000000000..8450715eaf3a8a9b046f80c2d75e6cb48db1d1bd GIT binary patch literal 569 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3vZ$Vn_o%P-2cQV4Jk_w+L}(NSJWftX&`3y1 zNMODs>QRMT*KgX-5Y&>NH*3~gCXwgNn{+39F?9U8(dlQ8hlJ9( zLkfIP%NaLj$7SYa1txi>)y+$fEA&i?E6VanvT82&ODfzLpOmM?%*Ek-M$?y-Q#_e# zG1tLX+s{EplLJ-edKnjc8GYUm&G@OGk@=AQ9+p3c*}m`#+);IxSH5D$Zu4t~;TJ=L z4+aj0Bvp<#J;~!$DVDf+Cegu|eaXG%hU&w8 zeASjH_`RFS*H$>Bhqa5jVFv>{+e&VK-?L?&YjoI*f<6Ux2McLSHVJ!sbvy9f|6?Q2 zDr}G>`1tU{ypnpO#E;8ang9JrOmOIxk9zf7@j=`Si%t96XVqIve0aW`gY8O*D5IIc U#Q8QHH~e$zm>3y)Ua2tx04TQ1-~a#s literal 0 HcmV?d00001 diff --git a/MatFileHandler/DataElementReader.cs b/MatFileHandler/DataElementReader.cs index a116c80..c5e2679 100755 --- a/MatFileHandler/DataElementReader.cs +++ b/MatFileHandler/DataElementReader.cs @@ -258,7 +258,7 @@ namespace MatFileHandler } else { - return new Opaque(name, typeDescription, className, new int[] { }, data); + return new Opaque(name, typeDescription, className, new int[] { }, data, subsystemData); } } diff --git a/MatFileHandler/EnumAdapter.cs b/MatFileHandler/EnumAdapter.cs new file mode 100644 index 0000000..ada3cba --- /dev/null +++ b/MatFileHandler/EnumAdapter.cs @@ -0,0 +1,60 @@ +// Copyright 2017-2018 Alexander Luzgarev + +namespace MatFileHandler +{ + /// + /// A better interface for using enum adapter. + /// + public class EnumAdapter + { + /// + /// Initializes a new instance of the class. + /// + /// Source enum object. + public EnumAdapter(IArray array) + { + var matObject = array as Opaque; + if (matObject?.RawData is not IStructureArray rawData) + { + throw new HandlerException("Cannot extract data for the enum adapter."); + } + + if (rawData["ValueNames"] is not IArrayOf valueNamesData) + { + throw new HandlerException("Cannot extract data for the enum adapter."); + } + + var numberOfNames = valueNamesData.Count; + var valueNames = new string[numberOfNames]; + var names = matObject.SubsystemData.FieldNames; + for (var i = 0; i < numberOfNames; i++) + { + valueNames[i] = names[valueNamesData[i] - 1]; + } + + if (rawData["ValueIndices"] is not IArrayOf valueIndices) + { + throw new HandlerException("Cannot extract data for the enum adapter."); + } + + ClassName = matObject.ClassName; + ValueNames = valueNames; + Values = valueIndices; + } + + /// + /// Gets name of the enumeration class. + /// + public string ClassName { get; } + + /// + /// Gets names of the enumeration values. + /// + public string[] ValueNames { get; } + + /// + /// Gets indices of values stored in the variable. + /// + public IArrayOf Values { get; } + } +} \ No newline at end of file diff --git a/MatFileHandler/Opaque.cs b/MatFileHandler/Opaque.cs index 9ce69b7..ba5711a 100644 --- a/MatFileHandler/Opaque.cs +++ b/MatFileHandler/Opaque.cs @@ -26,12 +26,14 @@ namespace MatFileHandler /// Class name. /// Dimensions of the object. /// Raw object's data. - public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData) + /// Subsystem data. + public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData, SubsystemData subsystemData) : base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name) { TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription)); ClassName = className ?? throw new ArgumentNullException(nameof(className)); RawData = rawData ?? throw new ArgumentNullException(nameof(rawData)); + SubsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData)); } /// @@ -49,6 +51,11 @@ namespace MatFileHandler /// public string TypeDescription { get; } + /// + /// Gets subsystem data. + /// + public SubsystemData SubsystemData { get; } + /// public override Complex[]? ConvertToComplexArray() => null; diff --git a/MatFileHandler/OpaqueLink.cs b/MatFileHandler/OpaqueLink.cs index da69fc1..003b4dc 100644 --- a/MatFileHandler/OpaqueLink.cs +++ b/MatFileHandler/OpaqueLink.cs @@ -12,8 +12,6 @@ namespace MatFileHandler /// internal class OpaqueLink : Opaque, IMatObject { - private readonly SubsystemData subsystemData; - /// /// Initializes a new instance of the class. /// @@ -34,11 +32,10 @@ namespace MatFileHandler int[] indexToObjectId, int classIndex, SubsystemData subsystemData) - : base(name, typeDescription, className, dimensions, data) + : base(name, typeDescription, className, dimensions, data, subsystemData) { IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId)); ClassIndex = classIndex; - this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData)); } /// @@ -74,9 +71,9 @@ namespace MatFileHandler /// /// Gets name of this object's class. /// - public override string ClassName => subsystemData.ClassInformation[ClassIndex].Name; + public override string ClassName => SubsystemData.ClassInformation[ClassIndex].Name; - private string[] FieldNamesArray => subsystemData.ClassInformation[ClassIndex].FieldNames.ToArray(); + private string[] FieldNamesArray => SubsystemData.ClassInformation[ClassIndex].FieldNames.ToArray(); /// public IArray this[string field, params int[] list] @@ -108,7 +105,7 @@ namespace MatFileHandler private bool TryGetValue(string field, out IArray? output, params int[] list) { var index = Dimensions.DimFlatten(list); - var maybeFieldIndex = subsystemData.ClassInformation[ClassIndex].FindField(field); + var maybeFieldIndex = SubsystemData.ClassInformation[ClassIndex].FindField(field); if (!(maybeFieldIndex is int fieldIndex)) { output = default; @@ -122,9 +119,9 @@ namespace MatFileHandler } var objectId = IndexToObjectId[index]; - var objectInfo = subsystemData.ObjectInformation[objectId]; + var objectInfo = SubsystemData.ObjectInformation[objectId]; var fieldId = objectInfo.FieldLinks[fieldIndex]; - output = subsystemData.Data[fieldId]; + output = SubsystemData.Data[fieldId]; return true; } diff --git a/MatFileHandler/SubsystemData.cs b/MatFileHandler/SubsystemData.cs index f14ffae..fe1947e 100644 --- a/MatFileHandler/SubsystemData.cs +++ b/MatFileHandler/SubsystemData.cs @@ -29,15 +29,18 @@ namespace MatFileHandler /// /// Information about the classes. /// Information about the objects. + /// Field names. /// Field values. public SubsystemData( Dictionary classInformation, Dictionary objectInformation, + string[] fieldNames, Dictionary data) { _realData = new RealSubsystemData( classInformation, objectInformation, + fieldNames, data); } @@ -59,6 +62,12 @@ namespace MatFileHandler public Dictionary ObjectInformation => _realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing."); + /// + /// Gets field names. + /// + public string[] FieldNames => + _realData?.FieldNames ?? throw new HandlerException("Subsystem data missing."); + /// /// Initialize this object from another object. /// This ugly hack allows us to read the opaque objects and store references to @@ -71,6 +80,7 @@ namespace MatFileHandler _realData = new RealSubsystemData( data.ClassInformation, data.ObjectInformation, + data.FieldNames, data.Data); } @@ -147,14 +157,17 @@ namespace MatFileHandler /// /// Class information. /// Object information. + /// Field names. /// Data. public RealSubsystemData( Dictionary classInformation, Dictionary objectInformation, + string[] fieldNames, IReadOnlyDictionary data) { ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation)); ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation)); + FieldNames = fieldNames; Data = data ?? throw new ArgumentNullException(nameof(data)); } @@ -172,6 +185,11 @@ namespace MatFileHandler /// Gets information about all the objects occurring in the file. /// public Dictionary ObjectInformation { get; } + + /// + /// Gets field names. + /// + public string[] FieldNames { get; } } } } \ No newline at end of file diff --git a/MatFileHandler/SubsystemDataReader.cs b/MatFileHandler/SubsystemDataReader.cs index 39ee74b..b6141d8 100644 --- a/MatFileHandler/SubsystemDataReader.cs +++ b/MatFileHandler/SubsystemDataReader.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -58,7 +59,7 @@ namespace MatFileHandler data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData); } - return new SubsystemData(classInformation, objectInformation, data); + return new SubsystemData(classInformation, objectInformation, fieldNames, data); } private static Dictionary> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions) @@ -303,20 +304,15 @@ namespace MatFileHandler { var next = BitConverter.ToInt32(bytes, position); position += 4; - if (next == 0) + if (next == bytes.Length) { - if (position % 8 != 0) - { - position += 4; - } - break; } offsets.Add(next); } - return (offsets.ToArray(), position); + return (offsets.ToArray(), 40); } private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)