Support structure and cell arrays
This commit is contained in:
parent
b0ae15abc9
commit
67905605d6
@ -1,5 +1,6 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
@ -165,6 +166,44 @@ namespace MatFileHandler.Tests
|
|||||||
CheckComplexLimits(array as IArrayOf<ComplexOf<ulong>>, CommonData.UInt64Limits);
|
CheckComplexLimits(array as IArrayOf<ComplexOf<ulong>>, CommonData.UInt64Limits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a structure array.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestStruct()
|
||||||
|
{
|
||||||
|
var matFile = ReadHdfTestFile("struct");
|
||||||
|
var structure = matFile["struct_"].Value as IStructureArray;
|
||||||
|
Assert.That(structure, Is.Not.Null);
|
||||||
|
Assert.That(structure.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
|
var element = structure[0, 0];
|
||||||
|
Assert.That(element.ContainsKey("x"), Is.True);
|
||||||
|
Assert.That(element.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(element.TryGetValue("x", out var _), Is.True);
|
||||||
|
Assert.That(element.TryGetValue("z", out var _), Is.False);
|
||||||
|
Assert.That(element.Keys, Has.Exactly(2).Items);
|
||||||
|
Assert.That(element.Values, Has.Exactly(2).Items);
|
||||||
|
var keys = element.Select(pair => pair.Key);
|
||||||
|
Assert.That(keys, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
|
|
||||||
|
Assert.That((element["x"] as IArrayOf<double>)?[0], Is.EqualTo(12.345));
|
||||||
|
|
||||||
|
Assert.That((structure["x", 0, 0] as IArrayOf<double>)?[0], Is.EqualTo(12.345));
|
||||||
|
Assert.That((structure["y", 0, 0] as ICharArray)?.String, Is.EqualTo("abc"));
|
||||||
|
Assert.That((structure["x", 1, 0] as ICharArray)?.String, Is.EqualTo("xyz"));
|
||||||
|
Assert.That(structure["y", 1, 0].IsEmpty, Is.True);
|
||||||
|
Assert.That((structure["x", 0, 1] as IArrayOf<double>)?[0], Is.EqualTo(2.0));
|
||||||
|
Assert.That((structure["y", 0, 1] as IArrayOf<double>)?[0], Is.EqualTo(13.0));
|
||||||
|
Assert.That(structure["x", 1, 1].IsEmpty, Is.True);
|
||||||
|
Assert.That((structure["y", 1, 1] as ICharArray)?[0, 0], Is.EqualTo('a'));
|
||||||
|
Assert.That(((structure["x", 0, 2] as ICellArray)?[0] as ICharArray)?.String, Is.EqualTo("x"));
|
||||||
|
Assert.That(((structure["x", 0, 2] as ICellArray)?[1] as ICharArray)?.String, Is.EqualTo("yz"));
|
||||||
|
Assert.That((structure["y", 0, 2] as IArrayOf<double>)?.Dimensions, Is.EqualTo(new[] { 2, 3 }));
|
||||||
|
Assert.That((structure["y", 0, 2] as IArrayOf<double>)?[0, 2], Is.EqualTo(3.0));
|
||||||
|
Assert.That((structure["x", 1, 2] as IArrayOf<float>)?[0], Is.EqualTo(1.5f));
|
||||||
|
Assert.That(structure["y", 1, 2].IsEmpty, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
private static void CheckComplexLimits<T>(IArrayOf<ComplexOf<T>> array, T[] limits)
|
private static void CheckComplexLimits<T>(IArrayOf<ComplexOf<T>> array, T[] limits)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
|
BIN
MatFileHandler.Tests/test-data/hdf/struct.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/struct.mat
Normal file
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@ -8,6 +9,23 @@ using HDF.PInvoke;
|
|||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
internal enum HdfMatlabClass
|
||||||
|
{
|
||||||
|
MEmpty,
|
||||||
|
MChar,
|
||||||
|
MInt8,
|
||||||
|
MUInt8,
|
||||||
|
MInt16,
|
||||||
|
MUInt16,
|
||||||
|
MInt32,
|
||||||
|
MUInt32,
|
||||||
|
MInt64,
|
||||||
|
MUInt64,
|
||||||
|
MSingle,
|
||||||
|
MDouble,
|
||||||
|
MCell,
|
||||||
|
}
|
||||||
|
|
||||||
internal class HdfArray : IArray
|
internal class HdfArray : IArray
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,6 +67,25 @@ namespace MatFileHandler
|
|||||||
public bool IsEmpty => Dimensions.Length == 0;
|
public bool IsEmpty => Dimensions.Length == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class HdfCellArray : HdfArray, ICellArray
|
||||||
|
{
|
||||||
|
public HdfCellArray(int[] dimensions, IEnumerable<IArray> elements)
|
||||||
|
: base(dimensions)
|
||||||
|
{
|
||||||
|
Data = elements.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IArray[] Data { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IArray this[params int[] indices]
|
||||||
|
{
|
||||||
|
get => Data[Dimensions.DimFlatten(indices)];
|
||||||
|
set => Data[Dimensions.DimFlatten(indices)] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A numerical array.
|
/// A numerical array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -174,6 +211,139 @@ namespace MatFileHandler
|
|||||||
private string StringData { get; set; }
|
private string StringData { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class HdfStructureArray : HdfArray, IStructureArray
|
||||||
|
{
|
||||||
|
public HdfStructureArray(
|
||||||
|
int[] dimensions,
|
||||||
|
Dictionary<string, List<IArray>> fields)
|
||||||
|
: base(dimensions)
|
||||||
|
{
|
||||||
|
Fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerable<string> FieldNames => Fields.Keys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets null: not implemented.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyDictionary<string, IArray>[] Data => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a dictionary that maps field names to lists of values.
|
||||||
|
/// </summary>
|
||||||
|
internal Dictionary<string, List<IArray>> Fields { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IArray this[string field, params int[] list]
|
||||||
|
{
|
||||||
|
get => Fields[field][Dimensions.DimFlatten(list)];
|
||||||
|
set => Fields[field][Dimensions.DimFlatten(list)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IReadOnlyDictionary<string, IArray> IArrayOf<IReadOnlyDictionary<string, IArray>>.this[params int[] list]
|
||||||
|
{
|
||||||
|
get => ExtractStructure(Dimensions.DimFlatten(list));
|
||||||
|
set => throw new NotSupportedException(
|
||||||
|
"Cannot set structure elements via this[params int[]] indexer. Use this[string, int[]] instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyDictionary<string, IArray> ExtractStructure(int i)
|
||||||
|
{
|
||||||
|
return new HdfStructureArrayElement(this, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to an element of a structure array by fields.
|
||||||
|
/// </summary>
|
||||||
|
internal class HdfStructureArrayElement : IReadOnlyDictionary<string, IArray>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HdfStructureArrayElement"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parent">Parent structure array.</param>
|
||||||
|
/// <param name="index">Index in the structure array.</param>
|
||||||
|
internal HdfStructureArrayElement(HdfStructureArray parent, int index)
|
||||||
|
{
|
||||||
|
Parent = parent;
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of fields.
|
||||||
|
/// </summary>
|
||||||
|
public int Count => Parent.Fields.Count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all fields.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<string> Keys => Parent.Fields.Keys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all values.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IArray> Values => Parent.Fields.Values.Select(array => array[Index]);
|
||||||
|
|
||||||
|
private HdfStructureArray Parent { get; }
|
||||||
|
|
||||||
|
private int Index { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a given field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Field name.</param>
|
||||||
|
/// <returns>The corresponding value.</returns>
|
||||||
|
public IArray this[string key] => Parent.Fields[key][Index];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates fieldstructure/value pairs of the dictionary.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>All field/value pairs in the structure.</returns>
|
||||||
|
public IEnumerator<KeyValuePair<string, IArray>> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (var field in Parent.Fields)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, IArray>(field.Key, field.Value[Index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates field/value pairs of the structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>All field/value pairs in the structure.</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the structure has a given field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Field name</param>
|
||||||
|
/// <returns>True iff the structure has a given field.</returns>
|
||||||
|
public bool ContainsKey(string key) => Parent.Fields.ContainsKey(key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the value of a given field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Field name.</param>
|
||||||
|
/// <param name="value">Value (or null if the field is not present).</param>
|
||||||
|
/// <returns>Success status of the query.</returns>
|
||||||
|
public bool TryGetValue(string key, out IArray value)
|
||||||
|
{
|
||||||
|
var success = Parent.Fields.TryGetValue(key, out var array);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
value = default(IArray);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = array[Index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class HdfFileReader
|
internal class HdfFileReader
|
||||||
{
|
{
|
||||||
private long fileId;
|
private long fileId;
|
||||||
@ -219,6 +389,15 @@ namespace MatFileHandler
|
|||||||
variables.Add(new MatVariable(value, variableName, false));
|
variables.Add(new MatVariable(value, variableName, false));
|
||||||
break;
|
break;
|
||||||
case H5O.type_t.GROUP:
|
case H5O.type_t.GROUP:
|
||||||
|
if (variableName == "#refs#")
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
var groupId = H5G.open(group, variableName);
|
||||||
|
var groupValue = ReadGroup(groupId);
|
||||||
|
variables.Add(new MatVariable(groupValue, variableName, false));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -241,6 +420,7 @@ namespace MatFileHandler
|
|||||||
H5A.read(attributeId, classId, buf);
|
H5A.read(attributeId, classId, buf);
|
||||||
var matlabClassNameBytes = new byte[(int)typeIdSize];
|
var matlabClassNameBytes = new byte[(int)typeIdSize];
|
||||||
Marshal.Copy(buf, matlabClassNameBytes, 0, (int)typeIdSize);
|
Marshal.Copy(buf, matlabClassNameBytes, 0, (int)typeIdSize);
|
||||||
|
Marshal.FreeHGlobal(buf);
|
||||||
return Encoding.ASCII.GetString(matlabClassNameBytes);
|
return Encoding.ASCII.GetString(matlabClassNameBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,30 +434,155 @@ namespace MatFileHandler
|
|||||||
return dims.Select(x => (int)x).ToArray();
|
return dims.Select(x => (int)x).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayType ArrayTypeFromMatlabClassName(string matlabClassName)
|
private static HdfMatlabClass ArrayTypeFromMatlabClassName(string matlabClassName)
|
||||||
{
|
{
|
||||||
switch (matlabClassName)
|
switch (matlabClassName)
|
||||||
{
|
{
|
||||||
|
case "canonical empty":
|
||||||
|
return HdfMatlabClass.MEmpty;
|
||||||
case "char":
|
case "char":
|
||||||
return ArrayType.MxChar;
|
return HdfMatlabClass.MChar;
|
||||||
case "int8":
|
case "int8":
|
||||||
return ArrayType.MxInt8;
|
return HdfMatlabClass.MInt8;
|
||||||
case "uint8":
|
case "uint8":
|
||||||
return ArrayType.MxUInt8;
|
return HdfMatlabClass.MUInt8;
|
||||||
case "int16":
|
case "int16":
|
||||||
return ArrayType.MxInt16;
|
return HdfMatlabClass.MInt16;
|
||||||
case "uint16":
|
case "uint16":
|
||||||
return ArrayType.MxUInt16;
|
return HdfMatlabClass.MUInt16;
|
||||||
case "int32":
|
case "int32":
|
||||||
return ArrayType.MxInt32;
|
return HdfMatlabClass.MInt32;
|
||||||
case "uint32":
|
case "uint32":
|
||||||
return ArrayType.MxUInt32;
|
return HdfMatlabClass.MUInt32;
|
||||||
case "int64":
|
case "int64":
|
||||||
return ArrayType.MxInt64;
|
return HdfMatlabClass.MInt64;
|
||||||
case "uint64":
|
case "uint64":
|
||||||
return ArrayType.MxUInt64;
|
return HdfMatlabClass.MUInt64;
|
||||||
|
case "single":
|
||||||
|
return HdfMatlabClass.MSingle;
|
||||||
case "double":
|
case "double":
|
||||||
return ArrayType.MxDouble;
|
return HdfMatlabClass.MDouble;
|
||||||
|
case "cell":
|
||||||
|
return HdfMatlabClass.MCell;
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GroupFieldNamesIterator(long group, IntPtr name, ref H5L.info_t info, IntPtr data)
|
||||||
|
{
|
||||||
|
var nameString = Marshal.PtrToStringAnsi(name);
|
||||||
|
H5O.info_t objectInfo = default(H5O.info_t);
|
||||||
|
H5O.get_info_by_name(group, nameString, ref objectInfo, H5P.DEFAULT);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadGroup(long groupId)
|
||||||
|
{
|
||||||
|
var matlabClass = GetMatlabClassOfDataset(groupId);
|
||||||
|
if (matlabClass == "struct")
|
||||||
|
{
|
||||||
|
return ReadStruct(groupId);
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] ReadFieldNames(long groupId)
|
||||||
|
{
|
||||||
|
// Try to read fields from MATLAB_fields.
|
||||||
|
var attrId = H5A.open_by_name(groupId, ".", "MATLAB_fields");
|
||||||
|
if (attrId == 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
var spaceId = H5A.get_space(attrId);
|
||||||
|
var rank = H5S.get_simple_extent_ndims(spaceId);
|
||||||
|
var dims = new ulong[rank];
|
||||||
|
H5S.get_simple_extent_dims(spaceId, dims, null);
|
||||||
|
Array.Reverse(dims);
|
||||||
|
var dimensions = dims.Select(x => (int)x).ToArray();
|
||||||
|
var numberOfFields = dimensions.NumberOfElements();
|
||||||
|
|
||||||
|
var field_id = H5A.get_type(attrId);
|
||||||
|
|
||||||
|
var fieldNamePointersSizeInBytes = numberOfFields * Marshal.SizeOf(default(H5T.hvl_t));
|
||||||
|
var fieldNamesBuf = Marshal.AllocHGlobal(fieldNamePointersSizeInBytes);
|
||||||
|
H5A.read(attrId, field_id, fieldNamesBuf);
|
||||||
|
|
||||||
|
var fieldNamePointers = new IntPtr[numberOfFields * 2];
|
||||||
|
Marshal.Copy(fieldNamesBuf, fieldNamePointers, 0, numberOfFields * 2);
|
||||||
|
Marshal.FreeHGlobal(fieldNamesBuf);
|
||||||
|
var fieldNames = new string[numberOfFields];
|
||||||
|
for (var i = 0; i < numberOfFields; i++)
|
||||||
|
{
|
||||||
|
var stringLength = fieldNamePointers[i * 2];
|
||||||
|
var stringPointer = fieldNamePointers[i * 2 + 1];
|
||||||
|
fieldNames[i] = Marshal.PtrToStringAnsi(stringPointer, (int)stringLength);
|
||||||
|
}
|
||||||
|
return fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static H5O.type_t GetObjectType(long groupId, string fieldName)
|
||||||
|
{
|
||||||
|
var objectInfo = default(H5O.info_t);
|
||||||
|
H5O.get_info_by_name(groupId, fieldName, ref objectInfo);
|
||||||
|
return objectInfo.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadStruct(long groupId)
|
||||||
|
{
|
||||||
|
var fieldNames = ReadFieldNames(groupId);
|
||||||
|
var firstObjectType = GetObjectType(groupId, fieldNames[0]);
|
||||||
|
if (firstObjectType == H5O.type_t.DATASET)
|
||||||
|
{
|
||||||
|
var firstFieldId = H5D.open(groupId, fieldNames[0]);
|
||||||
|
var firstFieldTypeId = H5D.get_type(firstFieldId);
|
||||||
|
if (H5T.get_class(firstFieldTypeId) == H5T.class_t.REFERENCE)
|
||||||
|
{
|
||||||
|
if (H5A.exists_by_name(firstFieldId, ".", "MATLAB_class") != 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var dimensions = GetDimensionsOfDataset(firstFieldId);
|
||||||
|
var numberOfElements = dimensions.NumberOfElements();
|
||||||
|
var dictionary = new Dictionary<string, List<IArray>>();
|
||||||
|
foreach (var fieldName in fieldNames)
|
||||||
|
{
|
||||||
|
var fieldType = GetObjectType(groupId, fieldName);
|
||||||
|
dictionary[fieldName] = new List<IArray>();
|
||||||
|
switch (fieldType)
|
||||||
|
{
|
||||||
|
case H5O.type_t.DATASET:
|
||||||
|
var fieldId = H5D.open(groupId, fieldName);
|
||||||
|
var buf = Marshal.AllocHGlobal(Marshal.SizeOf(default(IntPtr)) * numberOfElements);
|
||||||
|
H5D.read(fieldId, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf);
|
||||||
|
for (var i = 0; i < numberOfElements; i++)
|
||||||
|
{
|
||||||
|
var fieldDataSet = H5R.dereference(
|
||||||
|
fieldId,
|
||||||
|
H5P.DEFAULT,
|
||||||
|
H5R.type_t.OBJECT,
|
||||||
|
buf + (i * Marshal.SizeOf(default(IntPtr))));
|
||||||
|
var dataset = ReadDataset(fieldDataSet);
|
||||||
|
dictionary[fieldName].Add(dataset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new HdfStructureArray(dimensions, dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
@ -291,84 +596,107 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
switch (arrayType)
|
switch (arrayType)
|
||||||
{
|
{
|
||||||
case ArrayType.MxChar:
|
case HdfMatlabClass.MEmpty:
|
||||||
|
return HdfArray.Empty();
|
||||||
|
case HdfMatlabClass.MChar:
|
||||||
return ReadCharArray(datasetId, dims);
|
return ReadCharArray(datasetId, dims);
|
||||||
case ArrayType.MxInt8:
|
case HdfMatlabClass.MInt8:
|
||||||
return ReadNumericalArray<sbyte>(datasetId, dims, arrayType);
|
return ReadNumericalArray<sbyte>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxUInt8:
|
case HdfMatlabClass.MUInt8:
|
||||||
return ReadNumericalArray<byte>(datasetId, dims, arrayType);
|
return ReadNumericalArray<byte>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxInt16:
|
case HdfMatlabClass.MInt16:
|
||||||
return ReadNumericalArray<short>(datasetId, dims, arrayType);
|
return ReadNumericalArray<short>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxUInt16:
|
case HdfMatlabClass.MUInt16:
|
||||||
return ReadNumericalArray<ushort>(datasetId, dims, arrayType);
|
return ReadNumericalArray<ushort>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxInt32:
|
case HdfMatlabClass.MInt32:
|
||||||
return ReadNumericalArray<int>(datasetId, dims, arrayType);
|
return ReadNumericalArray<int>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxUInt32:
|
case HdfMatlabClass.MUInt32:
|
||||||
return ReadNumericalArray<uint>(datasetId, dims, arrayType);
|
return ReadNumericalArray<uint>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxInt64:
|
case HdfMatlabClass.MInt64:
|
||||||
return ReadNumericalArray<long>(datasetId, dims, arrayType);
|
return ReadNumericalArray<long>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxUInt64:
|
case HdfMatlabClass.MUInt64:
|
||||||
return ReadNumericalArray<ulong>(datasetId, dims, arrayType);
|
return ReadNumericalArray<ulong>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxSingle:
|
case HdfMatlabClass.MSingle:
|
||||||
return ReadNumericalArray<float>(datasetId, dims, arrayType);
|
return ReadNumericalArray<float>(datasetId, dims, arrayType);
|
||||||
case ArrayType.MxDouble:
|
case HdfMatlabClass.MDouble:
|
||||||
return ReadNumericalArray<double>(datasetId, dims, arrayType);
|
return ReadNumericalArray<double>(datasetId, dims, arrayType);
|
||||||
|
case HdfMatlabClass.MCell:
|
||||||
|
return ReadCellArray(datasetId, dims);
|
||||||
}
|
}
|
||||||
throw new NotImplementedException($"Unknown array type: {arrayType}.");
|
throw new NotImplementedException($"Unknown array type: {arrayType}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SizeOfArrayElement(ArrayType arrayType)
|
private static IArray ReadCellArray(long datasetId, int[] dims)
|
||||||
|
{
|
||||||
|
var numberOfElements = dims.NumberOfElements();
|
||||||
|
var buf = Marshal.AllocHGlobal(Marshal.SizeOf(default(IntPtr)) * numberOfElements);
|
||||||
|
H5D.read(datasetId, H5T.STD_REF_OBJ, H5S.ALL, H5S.ALL, H5P.DEFAULT, buf);
|
||||||
|
var elements = new IArray[numberOfElements];
|
||||||
|
for (var i = 0; i < numberOfElements; i++)
|
||||||
|
{
|
||||||
|
var fieldDataSet = H5R.dereference(
|
||||||
|
datasetId,
|
||||||
|
H5P.DEFAULT,
|
||||||
|
H5R.type_t.OBJECT,
|
||||||
|
buf + (i * Marshal.SizeOf(default(IntPtr))));
|
||||||
|
var dataset = ReadDataset(fieldDataSet);
|
||||||
|
elements[i] = dataset;
|
||||||
|
}
|
||||||
|
return new HdfCellArray(dims, elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int SizeOfArrayElement(HdfMatlabClass arrayType)
|
||||||
{
|
{
|
||||||
switch (arrayType)
|
switch (arrayType)
|
||||||
{
|
{
|
||||||
case ArrayType.MxInt8:
|
case HdfMatlabClass.MInt8:
|
||||||
case ArrayType.MxUInt8:
|
case HdfMatlabClass.MUInt8:
|
||||||
return 1;
|
return 1;
|
||||||
case ArrayType.MxInt16:
|
case HdfMatlabClass.MInt16:
|
||||||
case ArrayType.MxUInt16:
|
case HdfMatlabClass.MUInt16:
|
||||||
return 2;
|
return 2;
|
||||||
case ArrayType.MxInt32:
|
case HdfMatlabClass.MInt32:
|
||||||
case ArrayType.MxUInt32:
|
case HdfMatlabClass.MUInt32:
|
||||||
case ArrayType.MxSingle:
|
case HdfMatlabClass.MSingle:
|
||||||
return 4;
|
return 4;
|
||||||
case ArrayType.MxInt64:
|
case HdfMatlabClass.MInt64:
|
||||||
case ArrayType.MxUInt64:
|
case HdfMatlabClass.MUInt64:
|
||||||
case ArrayType.MxDouble:
|
case HdfMatlabClass.MDouble:
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long H5tTypeFromArrayType(ArrayType arrayType)
|
private static long H5tTypeFromHdfMatlabClass(HdfMatlabClass arrayType)
|
||||||
{
|
{
|
||||||
switch (arrayType)
|
switch (arrayType)
|
||||||
{
|
{
|
||||||
case ArrayType.MxInt8:
|
case HdfMatlabClass.MInt8:
|
||||||
return H5T.NATIVE_INT8;
|
return H5T.NATIVE_INT8;
|
||||||
case ArrayType.MxUInt8:
|
case HdfMatlabClass.MUInt8:
|
||||||
return H5T.NATIVE_UINT8;
|
return H5T.NATIVE_UINT8;
|
||||||
case ArrayType.MxInt16:
|
case HdfMatlabClass.MInt16:
|
||||||
return H5T.NATIVE_INT16;
|
return H5T.NATIVE_INT16;
|
||||||
case ArrayType.MxUInt16:
|
case HdfMatlabClass.MUInt16:
|
||||||
return H5T.NATIVE_UINT16;
|
return H5T.NATIVE_UINT16;
|
||||||
case ArrayType.MxInt32:
|
case HdfMatlabClass.MInt32:
|
||||||
return H5T.NATIVE_INT32;
|
return H5T.NATIVE_INT32;
|
||||||
case ArrayType.MxUInt32:
|
case HdfMatlabClass.MUInt32:
|
||||||
return H5T.NATIVE_UINT32;
|
return H5T.NATIVE_UINT32;
|
||||||
case ArrayType.MxInt64:
|
case HdfMatlabClass.MInt64:
|
||||||
return H5T.NATIVE_INT64;
|
return H5T.NATIVE_INT64;
|
||||||
case ArrayType.MxUInt64:
|
case HdfMatlabClass.MUInt64:
|
||||||
return H5T.NATIVE_UINT64;
|
return H5T.NATIVE_UINT64;
|
||||||
case ArrayType.MxSingle:
|
case HdfMatlabClass.MSingle:
|
||||||
return H5T.NATIVE_FLOAT;
|
return H5T.NATIVE_FLOAT;
|
||||||
case ArrayType.MxDouble:
|
case HdfMatlabClass.MDouble:
|
||||||
return H5T.NATIVE_DOUBLE;
|
return H5T.NATIVE_DOUBLE;
|
||||||
}
|
}
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T[] ConvertDataToProperType<T>(byte[] bytes, ArrayType arrayType)
|
private static T[] ConvertDataToProperType<T>(byte[] bytes, HdfMatlabClass arrayType)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
var length = bytes.Length;
|
var length = bytes.Length;
|
||||||
@ -384,10 +712,11 @@ namespace MatFileHandler
|
|||||||
H5D.read(datasetId, elementType, H5S.ALL, H5S.ALL, H5P.DEFAULT, dataBuffer);
|
H5D.read(datasetId, elementType, H5S.ALL, H5S.ALL, H5P.DEFAULT, dataBuffer);
|
||||||
var data = new byte[dataSize];
|
var data = new byte[dataSize];
|
||||||
Marshal.Copy(dataBuffer, data, 0, dataSize);
|
Marshal.Copy(dataBuffer, data, 0, dataSize);
|
||||||
|
Marshal.FreeHGlobal(dataBuffer);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IArray ReadNumericalArray<T>(long datasetId, int[] dims, ArrayType arrayType)
|
private static IArray ReadNumericalArray<T>(long datasetId, int[] dims, HdfMatlabClass arrayType)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
var numberOfElements = dims.NumberOfElements();
|
var numberOfElements = dims.NumberOfElements();
|
||||||
@ -398,7 +727,7 @@ namespace MatFileHandler
|
|||||||
var isCompound = dataSetTypeClass == H5T.class_t.COMPOUND;
|
var isCompound = dataSetTypeClass == H5T.class_t.COMPOUND;
|
||||||
if (isCompound)
|
if (isCompound)
|
||||||
{
|
{
|
||||||
var h5Type = H5tTypeFromArrayType(arrayType);
|
var h5Type = H5tTypeFromHdfMatlabClass(arrayType);
|
||||||
var h5Size = H5T.get_size(h5Type);
|
var h5Size = H5T.get_size(h5Type);
|
||||||
var h5tComplexReal = H5T.create(H5T.class_t.COMPOUND, h5Size);
|
var h5tComplexReal = H5T.create(H5T.class_t.COMPOUND, h5Size);
|
||||||
H5T.insert(h5tComplexReal, "real", IntPtr.Zero, h5Type);
|
H5T.insert(h5tComplexReal, "real", IntPtr.Zero, h5Type);
|
||||||
@ -408,7 +737,7 @@ namespace MatFileHandler
|
|||||||
H5T.insert(h5tComplexImaginary, "imag", IntPtr.Zero, h5Type);
|
H5T.insert(h5tComplexImaginary, "imag", IntPtr.Zero, h5Type);
|
||||||
var imaginaryData = ReadDataset(datasetId, h5tComplexImaginary, dataSize);
|
var imaginaryData = ReadDataset(datasetId, h5tComplexImaginary, dataSize);
|
||||||
var convertedImaginaryData = ConvertDataToProperType<T>(imaginaryData, arrayType);
|
var convertedImaginaryData = ConvertDataToProperType<T>(imaginaryData, arrayType);
|
||||||
if (arrayType == ArrayType.MxDouble)
|
if (arrayType == HdfMatlabClass.MDouble)
|
||||||
{
|
{
|
||||||
var complexData =
|
var complexData =
|
||||||
(convertedRealData as double[])
|
(convertedRealData as double[])
|
||||||
@ -429,7 +758,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
throw new Exception("Data size mismatch.");
|
throw new Exception("Data size mismatch.");
|
||||||
}
|
}
|
||||||
var data = ReadDataset(datasetId, H5tTypeFromArrayType(arrayType), dataSize);
|
var data = ReadDataset(datasetId, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
|
||||||
var convertedData = ConvertDataToProperType<T>(data, arrayType);
|
var convertedData = ConvertDataToProperType<T>(data, arrayType);
|
||||||
return new HdfNumericalArrayOf<T>(dims, convertedData);
|
return new HdfNumericalArrayOf<T>(dims, convertedData);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user