From e6d236139ca4786fc50e0e86dc9a1209b5240363 Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Thu, 21 Mar 2019 21:30:30 +0100 Subject: [PATCH] Add XML documentation --- MatFileHandler.Tests/MatFileReaderHdfTests.cs | 7 +- .../MatFileReaderLevel5Tests.cs | 2 +- MatFileHandler/DataElementReader.cs | 150 +++++++++-------- MatFileHandler/DataElementWithArrayFlags.cs | 28 ---- MatFileHandler/DataElementWithMetadata.cs | 54 +++++++ MatFileHandler/DataExtraction.cs | 8 + MatFileHandler/Hdf/Attribute.cs | 57 +++++-- MatFileHandler/Hdf/Class.cs | 51 ++++-- MatFileHandler/Hdf/Dataset.cs | 81 +++++++--- MatFileHandler/Hdf/Group.cs | 40 ++++- MatFileHandler/Hdf/MatlabClass.cs | 62 ++++++- MatFileHandler/Hdf/MemoryHandle.cs | 14 +- MatFileHandler/Hdf/ReferenceArray.cs | 59 +++++-- MatFileHandler/Hdf/Space.cs | 22 ++- MatFileHandler/Hdf/Type.cs | 153 +++++++++++++----- MatFileHandler/HdfFileReader.cs | 71 ++++---- MatFileHandler/Header.cs | 3 + MatFileHandler/MatFileHdfReader.cs | 13 +- MatFileHandler/MatFileLevel5Reader.cs | 10 +- MatFileHandler/MatFileReader.cs | 10 +- MatFileHandler/MatSparseArrayOf.cs | 2 +- MatFileHandler/RawVariable.cs | 8 + 22 files changed, 651 insertions(+), 254 deletions(-) delete mode 100644 MatFileHandler/DataElementWithArrayFlags.cs create mode 100644 MatFileHandler/DataElementWithMetadata.cs diff --git a/MatFileHandler.Tests/MatFileReaderHdfTests.cs b/MatFileHandler.Tests/MatFileReaderHdfTests.cs index 6e0a81a..5434423 100644 --- a/MatFileHandler.Tests/MatFileReaderHdfTests.cs +++ b/MatFileHandler.Tests/MatFileReaderHdfTests.cs @@ -1,10 +1,15 @@ -using System.IO; +// Copyright 2017-2018 Alexander Luzgarev + +using System.IO; using System.Linq; using System.Numerics; using NUnit.Framework; namespace MatFileHandler.Tests { + /// + /// Tests of file reading API (HDF cases). + /// [TestFixture] public class MatFileReaderHdfTests { diff --git a/MatFileHandler.Tests/MatFileReaderLevel5Tests.cs b/MatFileHandler.Tests/MatFileReaderLevel5Tests.cs index 76689bf..188be0f 100644 --- a/MatFileHandler.Tests/MatFileReaderLevel5Tests.cs +++ b/MatFileHandler.Tests/MatFileReaderLevel5Tests.cs @@ -9,7 +9,7 @@ using NUnit.Framework; namespace MatFileHandler.Tests { /// - /// Tests of file reading API. + /// Tests of file reading API (Level 5 cases). /// [TestFixture] public class MatFileReaderLevel5Tests diff --git a/MatFileHandler/DataElementReader.cs b/MatFileHandler/DataElementReader.cs index 9138b7b..407fa22 100755 --- a/MatFileHandler/DataElementReader.cs +++ b/MatFileHandler/DataElementReader.cs @@ -25,60 +25,15 @@ namespace MatFileHandler this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData)); } - private DataElement ReadElementWithoutFlags(Tag tag, BinaryReader reader) - { - switch (tag.Type) - { - case DataType.MiInt8: - return ReadNum(tag, reader); - case DataType.MiUInt8: - case DataType.MiUtf8: - return ReadNum(tag, reader); - case DataType.MiInt16: - return ReadNum(tag, reader); - case DataType.MiUInt16: - case DataType.MiUtf16: - return ReadNum(tag, reader); - case DataType.MiInt32: - return ReadNum(tag, reader); - case DataType.MiUInt32: - return ReadNum(tag, reader); - case DataType.MiSingle: - return ReadNum(tag, reader); - case DataType.MiDouble: - return ReadNum(tag, reader); - case DataType.MiInt64: - return ReadNum(tag, reader); - case DataType.MiUInt64: - return ReadNum(tag, reader); - default: - throw new NotSupportedException("Unknown element."); - } - } - - private DataElementWithArrayFlags ReadElementWithFlags(Tag tag, BinaryReader reader) - { - switch (tag.Type) - { - case DataType.MiMatrix: - return ReadMatrix(tag, reader); - case DataType.MiCompressed: - return ReadCompressed(tag, reader); - default: - var element = ReadElementWithoutFlags(tag, reader); - return new DataElementWithArrayFlags(element); - } - } - /// /// Read a data element. /// /// Input reader. /// Data element. - public DataElementWithArrayFlags Read(BinaryReader reader) + public DataElementWithMetadata Read(BinaryReader reader) { var (dataReader, tag) = ReadTag(reader); - DataElementWithArrayFlags result = ReadElementWithFlags(tag, dataReader); + DataElementWithMetadata result = ReadElementWithFlags(tag, dataReader); if (tag.Type != DataType.MiCompressed) { var position = reader.BaseStream.Position; @@ -211,9 +166,7 @@ namespace MatFileHandler private DataElement ContinueReadingCellArray( BinaryReader reader, - ArrayFlags flags, - int[] dimensions, - string name) + int[] dimensions) { var numberOfElements = dimensions.NumberOfElements(); var elements = new List(); @@ -226,7 +179,7 @@ namespace MatFileHandler return new MatCellArray(dimensions, elements); } - private DataElementWithArrayFlags ContinueReadingOpaque(BinaryReader reader) + private DataElementWithMetadata ContinueReadingOpaque(BinaryReader reader) { var nameElement = Read(reader).Element as MiNum ?? throw new HandlerException("Unexpected type in object name."); @@ -242,7 +195,7 @@ namespace MatFileHandler if (data is MatNumericalArrayOf linkElement) { var (dimensions, indexToObjectId, classIndex) = ParseOpaqueData(linkElement.Data); - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( new OpaqueLink( typeDescription, className, @@ -256,7 +209,7 @@ namespace MatFileHandler } else { - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( new Opaque( typeDescription, className, @@ -267,7 +220,7 @@ namespace MatFileHandler } } - private DataElementWithArrayFlags ContinueReadingSparseArray( + private DataElementWithMetadata ContinueReadingSparseArray( BinaryReader reader, DataElement firstElement, int[] dimensions, @@ -281,7 +234,7 @@ namespace MatFileHandler var data = Read(reader).Element; if (arrayFlags.Variable.HasFlag(Variable.IsLogical)) { - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatSparseArrayOf( arrayFlags, dimensions, @@ -296,7 +249,7 @@ namespace MatFileHandler if (arrayFlags.Variable.HasFlag(Variable.IsComplex)) { var imaginaryData = Read(reader).Element; - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatSparseArrayOfComplex( dimensions, rowIndex.Data, @@ -311,7 +264,7 @@ namespace MatFileHandler switch (data) { case MiNum _: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatSparseArrayOf( arrayFlags, dimensions, @@ -352,7 +305,7 @@ namespace MatFileHandler return new MatStructureArray(dimensions, fields); } - private DataElementWithArrayFlags Read(Stream stream) + private DataElementWithMetadata Read(Stream stream) { using (var reader = new BinaryReader(stream)) { @@ -360,7 +313,7 @@ namespace MatFileHandler } } - private DataElementWithArrayFlags ReadCompressed(Tag tag, BinaryReader reader) + private DataElementWithMetadata ReadCompressed(Tag tag, BinaryReader reader) { reader.ReadBytes(2); var compressedData = new byte[tag.Length - 6]; @@ -379,11 +332,56 @@ namespace MatFileHandler return Read(resultStream); } - private DataElementWithArrayFlags ReadMatrix(Tag tag, BinaryReader reader) + private DataElementWithMetadata ReadElementWithFlags(Tag tag, BinaryReader reader) + { + switch (tag.Type) + { + case DataType.MiMatrix: + return ReadMatrix(tag, reader); + case DataType.MiCompressed: + return ReadCompressed(tag, reader); + default: + var element = ReadElementWithoutFlags(tag, reader); + return new DataElementWithMetadata(element); + } + } + + private DataElement ReadElementWithoutFlags(Tag tag, BinaryReader reader) + { + switch (tag.Type) + { + case DataType.MiInt8: + return ReadNum(tag, reader); + case DataType.MiUInt8: + case DataType.MiUtf8: + return ReadNum(tag, reader); + case DataType.MiInt16: + return ReadNum(tag, reader); + case DataType.MiUInt16: + case DataType.MiUtf16: + return ReadNum(tag, reader); + case DataType.MiInt32: + return ReadNum(tag, reader); + case DataType.MiUInt32: + return ReadNum(tag, reader); + case DataType.MiSingle: + return ReadNum(tag, reader); + case DataType.MiDouble: + return ReadNum(tag, reader); + case DataType.MiInt64: + return ReadNum(tag, reader); + case DataType.MiUInt64: + return ReadNum(tag, reader); + default: + throw new NotSupportedException("Unknown element."); + } + } + + private DataElementWithMetadata ReadMatrix(Tag tag, BinaryReader reader) { if (tag.Length == 0) { - return new DataElementWithArrayFlags(MatArray.Empty()); + return new DataElementWithMetadata(MatArray.Empty()); } var element1 = Read(reader).Element; @@ -403,7 +401,7 @@ namespace MatFileHandler var name = ReadName(element3); if (flags.Class == ArrayType.MxCell) { - return new DataElementWithArrayFlags(ContinueReadingCellArray(reader, flags, dimensions, name)); + return new DataElementWithMetadata(ContinueReadingCellArray(reader, dimensions)); } if (flags.Class == ArrayType.MxSparse) @@ -425,7 +423,7 @@ namespace MatFileHandler var fieldNameLengthElement = data as MiNum ?? throw new HandlerException( "Unexpected type in structure field name length."); - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( ContinueReadingStructure(reader, dimensions, fieldNameLengthElement.Data[0]), flags, name); @@ -437,7 +435,7 @@ namespace MatFileHandler switch (data) { case MiNum _: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -446,7 +444,7 @@ namespace MatFileHandler flags, name); case MiNum _: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -459,7 +457,7 @@ namespace MatFileHandler $"This type of char array ({data.GetType()}) is not supported."); } case ArrayType.MxInt8: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -470,7 +468,7 @@ namespace MatFileHandler case ArrayType.MxUInt8: if (flags.Variable.HasFlag(Variable.IsLogical)) { - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -480,7 +478,7 @@ namespace MatFileHandler name); } - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -489,7 +487,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxInt16: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -498,7 +496,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxUInt16: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -507,7 +505,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxInt32: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -516,7 +514,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxUInt32: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -525,7 +523,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxInt64: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -534,7 +532,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxUInt64: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -543,7 +541,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxSingle: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, @@ -552,7 +550,7 @@ namespace MatFileHandler flags, name); case ArrayType.MxDouble: - return new DataElementWithArrayFlags( + return new DataElementWithMetadata( DataElementConverter.ConvertToMatNumericalArrayOf( flags, dimensions, diff --git a/MatFileHandler/DataElementWithArrayFlags.cs b/MatFileHandler/DataElementWithArrayFlags.cs deleted file mode 100644 index ce48154..0000000 --- a/MatFileHandler/DataElementWithArrayFlags.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace MatFileHandler -{ - internal class DataElementWithArrayFlags - { - public DataElementWithArrayFlags(DataElement element, ArrayFlags flags, string name, uint nzMax = 0) - { - Element = element; - Flags = flags; - Name = name; - NzMax = nzMax; - } - - public DataElementWithArrayFlags(DataElement element) - { - Element = element; - Flags = default; - Name = default; - } - - public DataElement Element { get; } - - public ArrayFlags Flags { get; } - - public string Name { get; } - - public uint NzMax { get; } - } -} \ No newline at end of file diff --git a/MatFileHandler/DataElementWithMetadata.cs b/MatFileHandler/DataElementWithMetadata.cs new file mode 100644 index 0000000..9ae5fc0 --- /dev/null +++ b/MatFileHandler/DataElementWithMetadata.cs @@ -0,0 +1,54 @@ +// Copyright 2017-2018 Alexander Luzgarev + +namespace MatFileHandler +{ + /// + /// Data element together with array flags, variable name, and sparse array's nzMax value. + /// + internal class DataElementWithMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// Data element. + /// Array flags. + /// Variable name. + /// nzMax (for sparse arrays). + public DataElementWithMetadata(DataElement element, ArrayFlags flags, string name, uint nzMax = 0) + { + Element = element; + Flags = flags; + Name = name; + NzMax = nzMax; + } + + /// + /// Initializes a new instance of the class. + /// + /// Data element. + public DataElementWithMetadata(DataElement element) + { + Element = element; + } + + /// + /// Gets data element. + /// + public DataElement Element { get; } + + /// + /// Gets array flags. + /// + public ArrayFlags Flags { get; } + + /// + /// Gets variable name. + /// + public string Name { get; } + + /// + /// Gets nzMax (for sparse arrays). + /// + public uint NzMax { get; } + } +} \ No newline at end of file diff --git a/MatFileHandler/DataExtraction.cs b/MatFileHandler/DataExtraction.cs index d79ed1e..77c9e9f 100755 --- a/MatFileHandler/DataExtraction.cs +++ b/MatFileHandler/DataExtraction.cs @@ -363,6 +363,14 @@ namespace MatFileHandler $"Expected data element that would be convertible to uint64, found {element.GetType()}."); } + /// + /// Convert sparse MATLAB data into dictionary. + /// + /// Array element type. + /// Array of row indices. + /// Array of column indices. + /// Getter function. + /// Dictionary mapping (row, column) pairs to value. public static Dictionary<(int, int), T> ConvertMatlabSparseToDictionary( int[] rowIndex, int[] columnIndex, diff --git a/MatFileHandler/Hdf/Attribute.cs b/MatFileHandler/Hdf/Attribute.cs index a72bf76..7c65265 100644 --- a/MatFileHandler/Hdf/Attribute.cs +++ b/MatFileHandler/Hdf/Attribute.cs @@ -1,18 +1,32 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using System.Runtime.InteropServices; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// Wrapper for HDF attribute. + /// internal struct Attribute : IDisposable { - public long Id { get; private set; } - + /// + /// Initializes a new instance of the struct. + /// + /// Containing location id. + /// Attribute name. public Attribute(long locationId, string name) { Id = H5A.open_by_name(locationId, ".", name); } + /// + /// Gets attribute id. + /// + public long Id { get; private set; } + + /// public void Dispose() { if (Id != -1) @@ -22,6 +36,28 @@ namespace MatFileHandler.Hdf } } + /// + /// Get HDF type of the attribute. + /// + /// HDF type. + public Type GetHdfType() + { + return new Type(H5A.get_type(Id)); + } + + /// + /// Get HDF space of the attribute. + /// + /// HDF space. + public Space GetSpace() + { + return new Space(H5A.get_space(Id)); + } + + /// + /// Read attribute value as boolean. + /// + /// Attribute value. public bool ReadBool() { using (var h = new MemoryHandle(sizeof(int))) @@ -32,19 +68,14 @@ namespace MatFileHandler.Hdf } } + /// + /// Read attribute value to the provided memory handle. + /// + /// Target memory handle. + /// HDF type to read from the attribute. public void ReadToHandle(MemoryHandle handle, Type type) { H5A.read(Id, type.Id, handle.Handle); } - - public Type GetHdfType() - { - return new Type(H5A.get_type(Id)); - } - - public Space GetSpace() - { - return new Space(H5A.get_space(Id)); - } } } \ No newline at end of file diff --git a/MatFileHandler/Hdf/Class.cs b/MatFileHandler/Hdf/Class.cs index d735e9c..2b7ed08 100644 --- a/MatFileHandler/Hdf/Class.cs +++ b/MatFileHandler/Hdf/Class.cs @@ -1,23 +1,41 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// HDF class. + /// internal struct Class : IEquatable { - public Class(H5T.class_t c) + /// + /// Compound class. + /// + public static readonly Class Compound = new Class(H5T.class_t.COMPOUND); + + /// + /// Reference class. + /// + public static readonly Class Reference = new Class(H5T.class_t.REFERENCE); + + /// + /// String class. + /// + public static readonly Class String = new Class(H5T.class_t.STRING); + + private readonly H5T.class_t classT; + + /// + /// Initializes a new instance of the struct. + /// + /// HDF class_t. + public Class(H5T.class_t classT) { - C = c; + this.classT = classT; } - public static Class String => new Class(H5T.class_t.STRING); - - public static Class Reference => new Class(H5T.class_t.REFERENCE); - - public static Class Compound => new Class(H5T.class_t.COMPOUND); - - public H5T.class_t C { get; } - public static bool operator ==(Class one, Class other) { return one.Equals(other); @@ -28,19 +46,26 @@ namespace MatFileHandler.Hdf return !one.Equals(other); } + /// + /// Check if the class is equal to the other class. + /// + /// Other class. + /// True iff the classes are equal. public bool Equals(Class other) { - return C == other.C; + return classT == other.classT; } + /// public override bool Equals(object obj) { return obj is Class other && Equals(other); } + /// public override int GetHashCode() { - return (int)C; + return (int)classT; } } } \ No newline at end of file diff --git a/MatFileHandler/Hdf/Dataset.cs b/MatFileHandler/Hdf/Dataset.cs index fcc4cca..c0aaf82 100644 --- a/MatFileHandler/Hdf/Dataset.cs +++ b/MatFileHandler/Hdf/Dataset.cs @@ -1,22 +1,50 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// HDF dataset. + /// internal struct Dataset : IDisposable { - public long Id { get; private set; } - + /// + /// Initializes a new instance of the struct. + /// + /// Dataset id. public Dataset(long datasetId) { Id = datasetId; } + /// + /// Initializes a new instance of the struct. + /// + /// Containing group id. + /// Name of the dataset in the group. public Dataset(long groupId, string name) { Id = H5D.open(groupId, name); } + /// + /// Gets dataset id. + /// + public long Id { get; private set; } + + /// + /// Check if dataset attribute with the given name exists. + /// + /// Attribute name. + /// True iff dataset has an attribute with this name. + public bool AttributeExists(string name) + { + return H5A.exists_by_name(Id, ".", name) != 0; + } + + /// public void Dispose() { if (Id != -1) @@ -26,31 +54,48 @@ namespace MatFileHandler.Hdf } } + /// + /// Open attribute with given name. + /// + /// Attribute name. + /// Attribute. public Attribute GetAttribute(string name) { return new Attribute(Id, name); } - public bool AttributeExists(string name) - { - return H5A.exists_by_name(Id, ".", name) != 0; - } - - public Type GetHdfType() - { - return new Type(H5D.get_type(Id)); - } - - public int GetStorageSize() - { - return (int)H5D.get_storage_size(Id); - } - + /// + /// Get HDF space of the dataset. + /// + /// HDF space. public Space GetHdfSpace() { return new Space(H5D.get_space(Id)); } + /// + /// Get HDF type of the dataset. + /// + /// HDF type. + public Type GetHdfType() + { + return new Type(H5D.get_type(Id)); + } + + /// + /// Get storage size of the dataset. + /// + /// Storage size. + public int GetStorageSize() + { + return (int)H5D.get_storage_size(Id); + } + + /// + /// Read the contents of the dataset into the memory handle. + /// + /// HDF type of the data to read. + /// Memory handle. public void ReadToHandle(Type type, MemoryHandle handle) { H5D.read(Id, type.Id, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.Handle); diff --git a/MatFileHandler/Hdf/Group.cs b/MatFileHandler/Hdf/Group.cs index 3812a1e..20b4161 100644 --- a/MatFileHandler/Hdf/Group.cs +++ b/MatFileHandler/Hdf/Group.cs @@ -1,17 +1,41 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// Hdf group. + /// internal struct Group : IDisposable { - public long Id { get; private set; } - + /// + /// Initializes a new instance of the struct. + /// + /// Containing group id. + /// Name of the subgroup in the containing group. public Group(long groupId, string name) { Id = H5G.open(groupId, name); } + /// + /// Gets group id. + /// + public long Id { get; private set; } + + /// + /// Check if group attribute with the given name exists. + /// + /// Attribute name. + /// True iff group has an attribute with this name. + public bool AttributeExists(string name) + { + return H5A.exists_by_name(Id, ".", name) != 0; + } + + /// public void Dispose() { if (Id != -1) @@ -21,14 +45,14 @@ namespace MatFileHandler.Hdf } } + /// + /// Get group attribute. + /// + /// Attribute name. + /// Attribute. public Attribute GetAttribute(string name) { return new Attribute(Id, name); } - - public bool AttributeExists(string name) - { - return H5A.exists_by_name(Id, ".", name) != 0; - } } } \ No newline at end of file diff --git a/MatFileHandler/Hdf/MatlabClass.cs b/MatFileHandler/Hdf/MatlabClass.cs index b522fdd..4309b17 100644 --- a/MatFileHandler/Hdf/MatlabClass.cs +++ b/MatFileHandler/Hdf/MatlabClass.cs @@ -1,20 +1,80 @@ -namespace MatFileHandler.Hdf +// Copyright 2017-2018 Alexander Luzgarev + +namespace MatFileHandler.Hdf { + /// + /// Matlab classes as they appear in HDF files. + /// internal enum MatlabClass { + /// + /// Empty array. + /// MEmpty, + + /// + /// Char array. + /// MChar, + + /// + /// Int8 array. + /// MInt8, + + /// + /// UInt8 array. + /// MUInt8, + + /// + /// Int16 array. + /// MInt16, + + /// + /// UInt16 array. + /// MUInt16, + + /// + /// Int32 array. + /// MInt32, + + /// + /// UInt32 array. + /// MUInt32, + + /// + /// Int64 array. + /// MInt64, + + /// + /// UInt64 array. + /// MUInt64, + + /// + /// Single-precision floating point array. + /// MSingle, + + /// + /// Double-precision floating point array. + /// MDouble, + + /// + /// Cell array. + /// MCell, + + /// + /// Logical array. + /// MLogical, } } \ No newline at end of file diff --git a/MatFileHandler/Hdf/MemoryHandle.cs b/MatFileHandler/Hdf/MemoryHandle.cs index 0aac738..b5d4ae6 100644 --- a/MatFileHandler/Hdf/MemoryHandle.cs +++ b/MatFileHandler/Hdf/MemoryHandle.cs @@ -1,15 +1,27 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using System.Runtime.InteropServices; namespace MatFileHandler.Hdf { + /// + /// Wrapper around IntPtr to array in unmanaged memory. + /// internal sealed class MemoryHandle : IDisposable { + /// + /// Initializes a new instance of the class. + /// + /// Size of the memory to be allocated. internal MemoryHandle(int sizeInBytes) { Handle = Marshal.AllocHGlobal(sizeInBytes); } + /// + /// Gets wrapped IntPtr. + /// internal IntPtr Handle { get; private set; } /// diff --git a/MatFileHandler/Hdf/ReferenceArray.cs b/MatFileHandler/Hdf/ReferenceArray.cs index adfcbeb..c395de7 100644 --- a/MatFileHandler/Hdf/ReferenceArray.cs +++ b/MatFileHandler/Hdf/ReferenceArray.cs @@ -1,32 +1,35 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Text; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// Array of HDF references stored in an HDF dataset. + /// internal struct ReferenceArray : IDisposable, IEnumerable { - public Dataset Dataset { get; } - - public int Size { get; } - - public MemoryHandle Buf { get; } - - public Dataset[] References { get; } + private readonly Dataset[] references; + /// + /// Initializes a new instance of the struct. + /// + /// Containing dataset. + /// Array size. public ReferenceArray(Dataset dataset, int size) { Dataset = dataset; Size = size; Buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * size); Dataset.ReadToHandle(Type.Reference, Buf); - References = new Dataset[size]; + references = new Dataset[size]; for (var i = 0; i < size; i++) { - References[i] = + references[i] = new Dataset(H5R.dereference( dataset.Id, H5P.DEFAULT, @@ -35,26 +38,48 @@ namespace MatFileHandler.Hdf } } + /// + /// Gets containing dataset. + /// + public Dataset Dataset { get; } + + /// + /// Gets references. + /// + public IReadOnlyList References => references; + + /// + /// Gets array size. + /// + public int Size { get; } + + private MemoryHandle Buf { get; } + + /// public void Dispose() { Buf?.Dispose(); - if (!(References is null)) + if (References is null) { - foreach (var reference in References) - { - reference.Dispose(); - } + return; + } + + foreach (var reference in References) + { + reference.Dispose(); } } + /// public IEnumerator GetEnumerator() { return ((IEnumerable)References).GetEnumerator(); } + /// IEnumerator IEnumerable.GetEnumerator() { return References.GetEnumerator(); } } -} +} \ No newline at end of file diff --git a/MatFileHandler/Hdf/Space.cs b/MatFileHandler/Hdf/Space.cs index 87751e4..c2821a1 100644 --- a/MatFileHandler/Hdf/Space.cs +++ b/MatFileHandler/Hdf/Space.cs @@ -1,22 +1,42 @@ -using System.Linq; +// Copyright 2017-2018 Alexander Luzgarev + +using System.Linq; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// HDF space. + /// internal struct Space { + /// + /// Initializes a new instance of the struct. + /// + /// Space id. public Space(long id) { Id = id; } + /// + /// Gets space id. + /// public long Id { get; } + /// + /// Get space rank. + /// + /// Space rank. public int GetRank() { return H5S.get_simple_extent_ndims(Id); } + /// + /// Get dimensions of the space. + /// + /// Space dimensions. public int[] GetDimensions() { var dims = new ulong[GetRank()]; diff --git a/MatFileHandler/Hdf/Type.cs b/MatFileHandler/Hdf/Type.cs index 8a36d7c..4558d01 100644 --- a/MatFileHandler/Hdf/Type.cs +++ b/MatFileHandler/Hdf/Type.cs @@ -1,70 +1,147 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using HDF.PInvoke; namespace MatFileHandler.Hdf { + /// + /// HDF type. + /// internal struct Type { + /// + /// Initializes a new instance of the struct. + /// + /// Type id. public Type(long id) { Id = id; } + /// + /// Gets HDF string type. + /// + public static Type CS1 => new Type(H5T.C_S1); + + /// + /// Gets HDF double type. + /// + public static Type NativeDouble => new Type(H5T.NATIVE_DOUBLE); + + /// + /// Gets HDF float (single) type. + /// + public static Type NativeFloat => new Type(H5T.NATIVE_FLOAT); + + /// + /// Gets HDF int type. + /// + public static Type NativeInt => new Type(H5T.NATIVE_INT); + + /// + /// Gets HDF int16 type. + /// + public static Type NativeInt16 => new Type(H5T.NATIVE_INT16); + + /// + /// Gets HDF int32 type. + /// + public static Type NativeInt32 => new Type(H5T.NATIVE_INT32); + + /// + /// Gets HDF int64 type. + /// + public static Type NativeInt64 => new Type(H5T.NATIVE_INT64); + + /// + /// Gets HDF int8 type. + /// + public static Type NativeInt8 => new Type(H5T.NATIVE_INT8); + + /// + /// Gets HDF uint type. + /// + public static Type NativeUInt => new Type(H5T.NATIVE_UINT); + + /// + /// Gets HDF uint16 type + /// + public static Type NativeUInt16 => new Type(H5T.NATIVE_UINT16); + + /// + /// Gets HDF uint32 type. + /// + public static Type NativeUInt32 => new Type(H5T.NATIVE_UINT32); + + /// + /// Gets HDF uint64 type. + /// + public static Type NativeUInt64 => new Type(H5T.NATIVE_UINT64); + + /// + /// Gets HDF uint8 type. + /// + public static Type NativeUInt8 => new Type(H5T.NATIVE_UINT8); + + /// + /// Gets HDF reference type. + /// + public static Type Reference => new Type(H5T.STD_REF_OBJ); + + /// + /// Gets type id. + /// public long Id { get; } + /// + /// Create compound type of given size. + /// + /// Size of the type. + /// The created type. + public static Type CreateCompound(int size) + { + return new Type(H5T.create(H5T.class_t.COMPOUND, (IntPtr)size)); + } + + /// + /// Get class of the type. + /// + /// Class of the type. public Class GetClass() { return new Class(H5T.get_class(Id)); } + /// + /// Get size of the type. + /// + /// Size of the type. public int GetSize() { return (int)H5T.get_size(Id); } - public static Type NativeInt8 => new Type(H5T.NATIVE_INT8); - - public static Type NativeUInt8 => new Type(H5T.NATIVE_UINT8); - - public static Type NativeInt16 => new Type(H5T.NATIVE_INT16); - - public static Type NativeUInt16 => new Type(H5T.NATIVE_UINT16); - - public static Type NativeInt32 => new Type(H5T.NATIVE_INT32); - - public static Type NativeUInt32 => new Type(H5T.NATIVE_UINT32); - - public static Type NativeInt64 => new Type(H5T.NATIVE_INT64); - - public static Type NativeUInt64 => new Type(H5T.NATIVE_UINT64); - - public static Type NativeFloat => new Type(H5T.NATIVE_FLOAT); - - public static Type NativeDouble => new Type(H5T.NATIVE_DOUBLE); - - public static Type NativeInt => new Type(H5T.NATIVE_INT); - - public static Type NativeUInt => new Type(H5T.NATIVE_UINT); - - public static Type CS1 => new Type(H5T.C_S1); - - public static Type Reference => new Type(H5T.STD_REF_OBJ); + /// + /// Insert a field into the type. + /// + /// Field name. + /// Field type. + public void InsertField(string name, Type fieldType) + { + H5T.insert(Id, name, IntPtr.Zero, fieldType.Id); + } + /// + /// Create type copy with same class and given size. + /// + /// New size. + /// New type. public Type WithSize(int size) { var classId = H5T.copy(Id); H5T.set_size(classId, (IntPtr)size); return new Type(classId); } - - public static Type CreateCompound(int size) - { - return new Type(H5T.create(H5T.class_t.COMPOUND, (IntPtr)size)); - } - - public void InsertField(string name, Type fieldType) - { - H5T.insert(Id, name, IntPtr.Zero, fieldType.Id); - } } } \ No newline at end of file diff --git a/MatFileHandler/HdfFileReader.cs b/MatFileHandler/HdfFileReader.cs index 312bb41..ac4b754 100644 --- a/MatFileHandler/HdfFileReader.cs +++ b/MatFileHandler/HdfFileReader.cs @@ -1,4 +1,6 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -9,29 +11,40 @@ using MatFileHandler.Hdf; namespace MatFileHandler { + /// + /// Reader of HDF files containing MATLAB data. + /// internal class HdfFileReader { - private const string classAttributeName = "MATLAB_class"; + private const string ClassAttributeName = "MATLAB_class"; - private const string globalAttributeName = "MATLAB_global"; + private const string GlobalAttributeName = "MATLAB_global"; - private const string sparseAttributeName = "MATLAB_sparse"; - private long fileId; + private const string SparseAttributeName = "MATLAB_sparse"; + + private readonly long fileId; private List variables; + /// + /// Initializes a new instance of the class. + /// + /// File id to read data from. internal HdfFileReader(long fileId) { this.fileId = fileId; } + /// + /// Read MATLAB data from the HDF file. + /// + /// MATLAB data file contents. internal IMatFile Read() { variables = new List(); var group_info = default(H5G.info_t); H5G.get_info(fileId, ref group_info); var numberOfVariables = group_info.nlinks; - ulong idx = 0; while (idx < numberOfVariables) { @@ -117,12 +130,22 @@ namespace MatFileHandler Marshal.Copy(buf.Handle, matlabClassNameBytes, 0, typeIdSize); } - return Encoding.ASCII.GetString(matlabClassNameBytes); + var length = typeIdSize; + for (var i = 0; i < typeIdSize; i++) + { + if (matlabClassNameBytes[i] == 0) + { + length = i; + break; + } + } + + return Encoding.ASCII.GetString(matlabClassNameBytes, 0, length); } private static string GetMatlabClassOfDataset(Dataset dataset) { - using (var attribute = dataset.GetAttribute(classAttributeName)) + using (var attribute = dataset.GetAttribute(ClassAttributeName)) { return GetMatlabClassFromAttribute(attribute); } @@ -130,7 +153,7 @@ namespace MatFileHandler private static string GetMatlabClassOfGroup(Group group) { - using (var attribute = group.GetAttribute(classAttributeName)) + using (var attribute = group.GetAttribute(ClassAttributeName)) { return GetMatlabClassFromAttribute(attribute); } @@ -315,9 +338,8 @@ namespace MatFileHandler return ReadStruct(group.Id); } - if (group.AttributeExists(sparseAttributeName)) + if (group.AttributeExists(SparseAttributeName)) { - var dims = new int[0]; var arrayType = ArrayTypeFromMatlabClassName(matlabClass); switch (arrayType) @@ -378,7 +400,6 @@ namespace MatFileHandler { var numberOfElements = dims.NumberOfElements(); var dataSize = numberOfElements * SizeOfArrayElement(arrayType); - var storageSize = dataset.GetStorageSize(); var dataSetType = dataset.GetHdfType(); var dataSetTypeClass = dataSetType.GetClass(); var isCompound = dataSetTypeClass == Class.Compound; @@ -405,11 +426,6 @@ namespace MatFileHandler } } - if (dataSize != storageSize) - { - throw new Exception("Data size mismatch."); - } - var data = ReadDataset(dataset, H5tTypeFromHdfMatlabClass(arrayType), dataSize); var convertedData = ConvertDataToProperType(data, arrayType); return new MatNumericalArrayOf(dims, convertedData); @@ -418,7 +434,7 @@ namespace MatFileHandler private static IArray ReadSparseArray(long groupId, MatlabClass arrayType) where T : struct { - using (var sparseAttribute = new Hdf.Attribute(groupId, sparseAttributeName)) + using (var sparseAttribute = new Hdf.Attribute(groupId, SparseAttributeName)) { using (var numberOfRowsHandle = new MemoryHandle(sizeof(uint))) { @@ -464,7 +480,7 @@ namespace MatFileHandler var complexData = CombineComplexData( convertedRealData as double[], - convertedImaginaryData as double[]) + convertedImaginaryData as double[]) .ToArray(); var complexDataDictionary = DataExtraction.ConvertMatlabSparseToDictionary( @@ -475,7 +491,7 @@ namespace MatFileHandler } else { - var complexData = + var complexData = CombineComplexOfData( convertedRealData, convertedImaginaryData) @@ -489,11 +505,6 @@ namespace MatFileHandler } } - if (dataSize != storageSize) - { - throw new Exception("Data size mismatch."); - } - var d = ReadDataset(data, H5tTypeFromHdfMatlabClass(arrayType), dataSize); var elements = ConvertDataToProperType(d, arrayType); var dataDictionary = @@ -515,7 +526,7 @@ namespace MatFileHandler var firstFieldType = firstField.GetHdfType(); if (firstFieldType.GetClass() == Class.Reference) { - if (firstField.AttributeExists(classAttributeName)) + if (firstField.AttributeExists(ClassAttributeName)) { throw new NotImplementedException(); } @@ -592,12 +603,12 @@ namespace MatFileHandler private bool ReadGlobalFlag(Group group) { - if (!group.AttributeExists(globalAttributeName)) + if (!group.AttributeExists(GlobalAttributeName)) { return false; } - using (var globalAttribute = group.GetAttribute(globalAttributeName)) + using (var globalAttribute = group.GetAttribute(GlobalAttributeName)) { return globalAttribute.ReadBool(); } @@ -605,12 +616,12 @@ namespace MatFileHandler private bool ReadGlobalFlag(Dataset dataset) { - if (!dataset.AttributeExists(globalAttributeName)) + if (!dataset.AttributeExists(GlobalAttributeName)) { return false; } - using (var globalAttribute = dataset.GetAttribute(globalAttributeName)) + using (var globalAttribute = dataset.GetAttribute(GlobalAttributeName)) { return globalAttribute.ReadBool(); } diff --git a/MatFileHandler/Header.cs b/MatFileHandler/Header.cs index 0e7db2b..d63fb64 100755 --- a/MatFileHandler/Header.cs +++ b/MatFileHandler/Header.cs @@ -21,6 +21,9 @@ namespace MatFileHandler Version = version; } + /// + /// Gets raw byte contents of the header. + /// public byte[] RawBytes { get; } /// diff --git a/MatFileHandler/MatFileHdfReader.cs b/MatFileHandler/MatFileHdfReader.cs index 8b6642c..2cbe907 100644 --- a/MatFileHandler/MatFileHdfReader.cs +++ b/MatFileHandler/MatFileHdfReader.cs @@ -1,12 +1,23 @@ -using System; +// Copyright 2017-2018 Alexander Luzgarev + +using System; using System.IO; using System.Runtime.InteropServices; using HDF.PInvoke; namespace MatFileHandler { + /// + /// Reader for MATLAB HDF (-v7.3) files. + /// internal static class MatFileHdfReader { + /// + /// Continue reading MATLAB HDF file after reading the MATLAB header. + /// + /// MATLAB header that was read. + /// Stream to read the rest of the file from. + /// MATLAB data file contents. internal static IMatFile ContinueReadingHdfFile(Header header, Stream stream) { using (var memoryStream = new MemoryStream()) diff --git a/MatFileHandler/MatFileLevel5Reader.cs b/MatFileHandler/MatFileLevel5Reader.cs index 5a70629..e6c9f95 100644 --- a/MatFileHandler/MatFileLevel5Reader.cs +++ b/MatFileHandler/MatFileLevel5Reader.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +// Copyright 2017-2018 Alexander Luzgarev + +using System.Collections.Generic; using System.IO; namespace MatFileHandler @@ -61,6 +63,12 @@ namespace MatFileHandler return ReadRawVariables(reader, subsystemDataOffset, subsystemData); } + /// + /// Continue reading old-style (Level 5) MATLAB file. + /// + /// Header that was already read. + /// Reader for reading the rest of the file. + /// MATLAB data file contents. internal static IMatFile ContinueReadingLevel5File(Header header, BinaryReader reader) { var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset); diff --git a/MatFileHandler/MatFileReader.cs b/MatFileHandler/MatFileReader.cs index 1b79b3b..a12c09a 100755 --- a/MatFileHandler/MatFileReader.cs +++ b/MatFileHandler/MatFileReader.cs @@ -33,6 +33,11 @@ namespace MatFileHandler } } + private static Header ReadHeader(BinaryReader reader) + { + return Header.Read(reader); + } + private IMatFile Read(BinaryReader reader) { var header = ReadHeader(reader); @@ -46,10 +51,5 @@ namespace MatFileHandler throw new NotSupportedException($"Unknown file format."); } } - - private static Header ReadHeader(BinaryReader reader) - { - return Header.Read(reader); - } } } \ No newline at end of file diff --git a/MatFileHandler/MatSparseArrayOf.cs b/MatFileHandler/MatSparseArrayOf.cs index fd11039..a79b290 100755 --- a/MatFileHandler/MatSparseArrayOf.cs +++ b/MatFileHandler/MatSparseArrayOf.cs @@ -43,7 +43,7 @@ namespace MatFileHandler get { var rowAndColumn = GetRowAndColumn(list); - return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default(T); + return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default; } set => DataDictionary[GetRowAndColumn(list)] = value; } diff --git a/MatFileHandler/RawVariable.cs b/MatFileHandler/RawVariable.cs index b37008d..0576f11 100644 --- a/MatFileHandler/RawVariable.cs +++ b/MatFileHandler/RawVariable.cs @@ -17,6 +17,8 @@ namespace MatFileHandler /// /// Offset of the variable in the source file. /// Data element parsed from the file. + /// Array flags. + /// Variable name. internal RawVariable(long offset, DataElement dataElement, ArrayFlags flags, string name) { Offset = offset; @@ -30,8 +32,14 @@ namespace MatFileHandler /// public DataElement DataElement { get; } + /// + /// Gets array flags. + /// public ArrayFlags Flags { get; } + /// + /// Gets variable name. + /// public string Name { get; } ///