parent
d41020c6b8
commit
5a2226629a
@ -10,8 +10,11 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests of Matlab array manipulation.
|
/// Tests of Matlab array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArrayHandlingTests : IDisposable
|
public sealed class ArrayHandlingTests : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Setup for array handling tests.
|
||||||
|
/// </summary>
|
||||||
public ArrayHandlingTests()
|
public ArrayHandlingTests()
|
||||||
{
|
{
|
||||||
Builder = new DataBuilder();
|
Builder = new DataBuilder();
|
||||||
@ -108,7 +111,7 @@ namespace MatFileHandler.Tests
|
|||||||
var file = Builder.NewFile(new List<IVariable>());
|
var file = Builder.NewFile(new List<IVariable>());
|
||||||
Assert.NotNull(file);
|
Assert.NotNull(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TestCreateArrayOf<T>()
|
private static void TestCreateArrayOf<T>()
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
@ -116,8 +119,12 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.NotNull(array);
|
Assert.NotNull(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cleanup.
|
||||||
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -164,6 +164,23 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.Null(array.ConvertToComplexArray());
|
Assert.Null(array.ConvertToComplexArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading an enumeration.
|
||||||
|
/// </summary>
|
||||||
|
[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]]);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a structure array.
|
/// Test reading a structure array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -487,6 +504,9 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.Null(d0);
|
Assert.Null(d0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test 3-dimensional arrays.
|
||||||
|
/// </summary>
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Test_3DArrays()
|
public void Test_3DArrays()
|
||||||
{
|
{
|
||||||
@ -518,7 +538,10 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.Equal(expected, obj.ConvertToMultidimensionalDoubleArray());
|
Assert.Equal(expected, obj.ConvertToMultidimensionalDoubleArray());
|
||||||
Assert.Null(obj.ConvertTo2dDoubleArray());
|
Assert.Null(obj.ConvertTo2dDoubleArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test four-dimensional arrays.
|
||||||
|
/// </summary>
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Test_4DArrays()
|
public void Test_4DArrays()
|
||||||
{
|
{
|
||||||
|
BIN
MatFileHandler.Tests/test-data/good/enum.mat
Normal file
BIN
MatFileHandler.Tests/test-data/good/enum.mat
Normal file
Binary file not shown.
@ -258,7 +258,7 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Opaque(name, typeDescription, className, new int[] { }, data);
|
return new Opaque(name, typeDescription, className, new int[] { }, data, subsystemData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
MatFileHandler/EnumAdapter.cs
Normal file
60
MatFileHandler/EnumAdapter.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
namespace MatFileHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A better interface for using enum adapter.
|
||||||
|
/// </summary>
|
||||||
|
public class EnumAdapter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnumAdapter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Source enum object.</param>
|
||||||
|
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<uint> 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<uint> valueIndices)
|
||||||
|
{
|
||||||
|
throw new HandlerException("Cannot extract data for the enum adapter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassName = matObject.ClassName;
|
||||||
|
ValueNames = valueNames;
|
||||||
|
Values = valueIndices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets name of the enumeration class.
|
||||||
|
/// </summary>
|
||||||
|
public string ClassName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets names of the enumeration values.
|
||||||
|
/// </summary>
|
||||||
|
public string[] ValueNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets indices of values stored in the variable.
|
||||||
|
/// </summary>
|
||||||
|
public IArrayOf<uint> Values { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -26,12 +26,14 @@ namespace MatFileHandler
|
|||||||
/// <param name="className">Class name.</param>
|
/// <param name="className">Class name.</param>
|
||||||
/// <param name="dimensions">Dimensions of the object.</param>
|
/// <param name="dimensions">Dimensions of the object.</param>
|
||||||
/// <param name="rawData">Raw object's data.</param>
|
/// <param name="rawData">Raw object's data.</param>
|
||||||
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData)
|
/// <param name="subsystemData">Subsystem data.</param>
|
||||||
|
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData, SubsystemData subsystemData)
|
||||||
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
|
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
|
||||||
{
|
{
|
||||||
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
||||||
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
||||||
RawData = rawData ?? throw new ArgumentNullException(nameof(rawData));
|
RawData = rawData ?? throw new ArgumentNullException(nameof(rawData));
|
||||||
|
SubsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,6 +51,11 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string TypeDescription { get; }
|
public string TypeDescription { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets subsystem data.
|
||||||
|
/// </summary>
|
||||||
|
public SubsystemData SubsystemData { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Complex[]? ConvertToComplexArray() => null;
|
public override Complex[]? ConvertToComplexArray() => null;
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class OpaqueLink : Opaque, IMatObject
|
internal class OpaqueLink : Opaque, IMatObject
|
||||||
{
|
{
|
||||||
private readonly SubsystemData subsystemData;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -34,11 +32,10 @@ namespace MatFileHandler
|
|||||||
int[] indexToObjectId,
|
int[] indexToObjectId,
|
||||||
int classIndex,
|
int classIndex,
|
||||||
SubsystemData subsystemData)
|
SubsystemData subsystemData)
|
||||||
: base(name, typeDescription, className, dimensions, data)
|
: base(name, typeDescription, className, dimensions, data, subsystemData)
|
||||||
{
|
{
|
||||||
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
||||||
ClassIndex = classIndex;
|
ClassIndex = classIndex;
|
||||||
this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -74,9 +71,9 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets name of this object's class.
|
/// Gets name of this object's class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IArray this[string field, params int[] list]
|
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)
|
private bool TryGetValue(string field, out IArray? output, params int[] list)
|
||||||
{
|
{
|
||||||
var index = Dimensions.DimFlatten(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))
|
if (!(maybeFieldIndex is int fieldIndex))
|
||||||
{
|
{
|
||||||
output = default;
|
output = default;
|
||||||
@ -122,9 +119,9 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
var objectId = IndexToObjectId[index];
|
var objectId = IndexToObjectId[index];
|
||||||
var objectInfo = subsystemData.ObjectInformation[objectId];
|
var objectInfo = SubsystemData.ObjectInformation[objectId];
|
||||||
var fieldId = objectInfo.FieldLinks[fieldIndex];
|
var fieldId = objectInfo.FieldLinks[fieldIndex];
|
||||||
output = subsystemData.Data[fieldId];
|
output = SubsystemData.Data[fieldId];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,15 +29,18 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="classInformation">Information about the classes.</param>
|
/// <param name="classInformation">Information about the classes.</param>
|
||||||
/// <param name="objectInformation">Information about the objects.</param>
|
/// <param name="objectInformation">Information about the objects.</param>
|
||||||
|
/// <param name="fieldNames">Field names.</param>
|
||||||
/// <param name="data">Field values.</param>
|
/// <param name="data">Field values.</param>
|
||||||
public SubsystemData(
|
public SubsystemData(
|
||||||
Dictionary<int, ClassInfo> classInformation,
|
Dictionary<int, ClassInfo> classInformation,
|
||||||
Dictionary<int, ObjectInfo> objectInformation,
|
Dictionary<int, ObjectInfo> objectInformation,
|
||||||
|
string[] fieldNames,
|
||||||
Dictionary<int, IArray> data)
|
Dictionary<int, IArray> data)
|
||||||
{
|
{
|
||||||
_realData = new RealSubsystemData(
|
_realData = new RealSubsystemData(
|
||||||
classInformation,
|
classInformation,
|
||||||
objectInformation,
|
objectInformation,
|
||||||
|
fieldNames,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +62,12 @@ namespace MatFileHandler
|
|||||||
public Dictionary<int, ObjectInfo> ObjectInformation =>
|
public Dictionary<int, ObjectInfo> ObjectInformation =>
|
||||||
_realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing.");
|
_realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets field names.
|
||||||
|
/// </summary>
|
||||||
|
public string[] FieldNames =>
|
||||||
|
_realData?.FieldNames ?? throw new HandlerException("Subsystem data missing.");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize this object from another object.
|
/// Initialize this object from another object.
|
||||||
/// This ugly hack allows us to read the opaque objects and store references to
|
/// This ugly hack allows us to read the opaque objects and store references to
|
||||||
@ -71,6 +80,7 @@ namespace MatFileHandler
|
|||||||
_realData = new RealSubsystemData(
|
_realData = new RealSubsystemData(
|
||||||
data.ClassInformation,
|
data.ClassInformation,
|
||||||
data.ObjectInformation,
|
data.ObjectInformation,
|
||||||
|
data.FieldNames,
|
||||||
data.Data);
|
data.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,14 +157,17 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="classInformation">Class information.</param>
|
/// <param name="classInformation">Class information.</param>
|
||||||
/// <param name="objectInformation">Object information.</param>
|
/// <param name="objectInformation">Object information.</param>
|
||||||
|
/// <param name="fieldNames">Field names.</param>
|
||||||
/// <param name="data">Data.</param>
|
/// <param name="data">Data.</param>
|
||||||
public RealSubsystemData(
|
public RealSubsystemData(
|
||||||
Dictionary<int, ClassInfo> classInformation,
|
Dictionary<int, ClassInfo> classInformation,
|
||||||
Dictionary<int, ObjectInfo> objectInformation,
|
Dictionary<int, ObjectInfo> objectInformation,
|
||||||
|
string[] fieldNames,
|
||||||
IReadOnlyDictionary<int, IArray> data)
|
IReadOnlyDictionary<int, IArray> data)
|
||||||
{
|
{
|
||||||
ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation));
|
ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation));
|
||||||
ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation));
|
ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation));
|
||||||
|
FieldNames = fieldNames;
|
||||||
Data = data ?? throw new ArgumentNullException(nameof(data));
|
Data = data ?? throw new ArgumentNullException(nameof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +185,11 @@ namespace MatFileHandler
|
|||||||
/// Gets information about all the objects occurring in the file.
|
/// Gets information about all the objects occurring in the file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<int, ObjectInfo> ObjectInformation { get; }
|
public Dictionary<int, ObjectInfo> ObjectInformation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets field names.
|
||||||
|
/// </summary>
|
||||||
|
public string[] FieldNames { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -58,7 +59,7 @@ namespace MatFileHandler
|
|||||||
data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData);
|
data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SubsystemData(classInformation, objectInformation, data);
|
return new SubsystemData(classInformation, objectInformation, fieldNames, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions)
|
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions)
|
||||||
@ -303,20 +304,15 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
var next = BitConverter.ToInt32(bytes, position);
|
var next = BitConverter.ToInt32(bytes, position);
|
||||||
position += 4;
|
position += 4;
|
||||||
if (next == 0)
|
if (next == bytes.Length)
|
||||||
{
|
{
|
||||||
if (position % 8 != 0)
|
|
||||||
{
|
|
||||||
position += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
offsets.Add(next);
|
offsets.Add(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offsets.ToArray(), position);
|
return (offsets.ToArray(), 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)
|
private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user