Add XML documentation

This commit is contained in:
Alexander Luzgarev 2019-03-21 21:30:30 +01:00
parent bdd04a80b7
commit e6d236139c
22 changed files with 651 additions and 254 deletions

View File

@ -1,10 +1,15 @@
using System.IO; // Copyright 2017-2018 Alexander Luzgarev
using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using NUnit.Framework; using NUnit.Framework;
namespace MatFileHandler.Tests namespace MatFileHandler.Tests
{ {
/// <summary>
/// Tests of file reading API (HDF cases).
/// </summary>
[TestFixture] [TestFixture]
public class MatFileReaderHdfTests public class MatFileReaderHdfTests
{ {

View File

@ -9,7 +9,7 @@ using NUnit.Framework;
namespace MatFileHandler.Tests namespace MatFileHandler.Tests
{ {
/// <summary> /// <summary>
/// Tests of file reading API. /// Tests of file reading API (Level 5 cases).
/// </summary> /// </summary>
[TestFixture] [TestFixture]
public class MatFileReaderLevel5Tests public class MatFileReaderLevel5Tests

View File

@ -25,60 +25,15 @@ namespace MatFileHandler
this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData)); this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
} }
private DataElement ReadElementWithoutFlags(Tag tag, BinaryReader reader)
{
switch (tag.Type)
{
case DataType.MiInt8:
return ReadNum<sbyte>(tag, reader);
case DataType.MiUInt8:
case DataType.MiUtf8:
return ReadNum<byte>(tag, reader);
case DataType.MiInt16:
return ReadNum<short>(tag, reader);
case DataType.MiUInt16:
case DataType.MiUtf16:
return ReadNum<ushort>(tag, reader);
case DataType.MiInt32:
return ReadNum<int>(tag, reader);
case DataType.MiUInt32:
return ReadNum<uint>(tag, reader);
case DataType.MiSingle:
return ReadNum<float>(tag, reader);
case DataType.MiDouble:
return ReadNum<double>(tag, reader);
case DataType.MiInt64:
return ReadNum<long>(tag, reader);
case DataType.MiUInt64:
return ReadNum<ulong>(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);
}
}
/// <summary> /// <summary>
/// Read a data element. /// Read a data element.
/// </summary> /// </summary>
/// <param name="reader">Input reader.</param> /// <param name="reader">Input reader.</param>
/// <returns>Data element.</returns> /// <returns>Data element.</returns>
public DataElementWithArrayFlags Read(BinaryReader reader) public DataElementWithMetadata Read(BinaryReader reader)
{ {
var (dataReader, tag) = ReadTag(reader); var (dataReader, tag) = ReadTag(reader);
DataElementWithArrayFlags result = ReadElementWithFlags(tag, dataReader); DataElementWithMetadata result = ReadElementWithFlags(tag, dataReader);
if (tag.Type != DataType.MiCompressed) if (tag.Type != DataType.MiCompressed)
{ {
var position = reader.BaseStream.Position; var position = reader.BaseStream.Position;
@ -211,9 +166,7 @@ namespace MatFileHandler
private DataElement ContinueReadingCellArray( private DataElement ContinueReadingCellArray(
BinaryReader reader, BinaryReader reader,
ArrayFlags flags, int[] dimensions)
int[] dimensions,
string name)
{ {
var numberOfElements = dimensions.NumberOfElements(); var numberOfElements = dimensions.NumberOfElements();
var elements = new List<IArray>(); var elements = new List<IArray>();
@ -226,7 +179,7 @@ namespace MatFileHandler
return new MatCellArray(dimensions, elements); return new MatCellArray(dimensions, elements);
} }
private DataElementWithArrayFlags ContinueReadingOpaque(BinaryReader reader) private DataElementWithMetadata ContinueReadingOpaque(BinaryReader reader)
{ {
var nameElement = Read(reader).Element as MiNum<sbyte> ?? var nameElement = Read(reader).Element as MiNum<sbyte> ??
throw new HandlerException("Unexpected type in object name."); throw new HandlerException("Unexpected type in object name.");
@ -242,7 +195,7 @@ namespace MatFileHandler
if (data is MatNumericalArrayOf<uint> linkElement) if (data is MatNumericalArrayOf<uint> linkElement)
{ {
var (dimensions, indexToObjectId, classIndex) = ParseOpaqueData(linkElement.Data); var (dimensions, indexToObjectId, classIndex) = ParseOpaqueData(linkElement.Data);
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
new OpaqueLink( new OpaqueLink(
typeDescription, typeDescription,
className, className,
@ -256,7 +209,7 @@ namespace MatFileHandler
} }
else else
{ {
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
new Opaque( new Opaque(
typeDescription, typeDescription,
className, className,
@ -267,7 +220,7 @@ namespace MatFileHandler
} }
} }
private DataElementWithArrayFlags ContinueReadingSparseArray( private DataElementWithMetadata ContinueReadingSparseArray(
BinaryReader reader, BinaryReader reader,
DataElement firstElement, DataElement firstElement,
int[] dimensions, int[] dimensions,
@ -281,7 +234,7 @@ namespace MatFileHandler
var data = Read(reader).Element; var data = Read(reader).Element;
if (arrayFlags.Variable.HasFlag(Variable.IsLogical)) if (arrayFlags.Variable.HasFlag(Variable.IsLogical))
{ {
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatSparseArrayOf<bool>( DataElementConverter.ConvertToMatSparseArrayOf<bool>(
arrayFlags, arrayFlags,
dimensions, dimensions,
@ -296,7 +249,7 @@ namespace MatFileHandler
if (arrayFlags.Variable.HasFlag(Variable.IsComplex)) if (arrayFlags.Variable.HasFlag(Variable.IsComplex))
{ {
var imaginaryData = Read(reader).Element; var imaginaryData = Read(reader).Element;
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatSparseArrayOfComplex( DataElementConverter.ConvertToMatSparseArrayOfComplex(
dimensions, dimensions,
rowIndex.Data, rowIndex.Data,
@ -311,7 +264,7 @@ namespace MatFileHandler
switch (data) switch (data)
{ {
case MiNum<double> _: case MiNum<double> _:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatSparseArrayOf<double>( DataElementConverter.ConvertToMatSparseArrayOf<double>(
arrayFlags, arrayFlags,
dimensions, dimensions,
@ -352,7 +305,7 @@ namespace MatFileHandler
return new MatStructureArray(dimensions, fields); return new MatStructureArray(dimensions, fields);
} }
private DataElementWithArrayFlags Read(Stream stream) private DataElementWithMetadata Read(Stream stream)
{ {
using (var reader = new BinaryReader(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); reader.ReadBytes(2);
var compressedData = new byte[tag.Length - 6]; var compressedData = new byte[tag.Length - 6];
@ -379,11 +332,56 @@ namespace MatFileHandler
return Read(resultStream); 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<sbyte>(tag, reader);
case DataType.MiUInt8:
case DataType.MiUtf8:
return ReadNum<byte>(tag, reader);
case DataType.MiInt16:
return ReadNum<short>(tag, reader);
case DataType.MiUInt16:
case DataType.MiUtf16:
return ReadNum<ushort>(tag, reader);
case DataType.MiInt32:
return ReadNum<int>(tag, reader);
case DataType.MiUInt32:
return ReadNum<uint>(tag, reader);
case DataType.MiSingle:
return ReadNum<float>(tag, reader);
case DataType.MiDouble:
return ReadNum<double>(tag, reader);
case DataType.MiInt64:
return ReadNum<long>(tag, reader);
case DataType.MiUInt64:
return ReadNum<ulong>(tag, reader);
default:
throw new NotSupportedException("Unknown element.");
}
}
private DataElementWithMetadata ReadMatrix(Tag tag, BinaryReader reader)
{ {
if (tag.Length == 0) if (tag.Length == 0)
{ {
return new DataElementWithArrayFlags(MatArray.Empty()); return new DataElementWithMetadata(MatArray.Empty());
} }
var element1 = Read(reader).Element; var element1 = Read(reader).Element;
@ -403,7 +401,7 @@ namespace MatFileHandler
var name = ReadName(element3); var name = ReadName(element3);
if (flags.Class == ArrayType.MxCell) if (flags.Class == ArrayType.MxCell)
{ {
return new DataElementWithArrayFlags(ContinueReadingCellArray(reader, flags, dimensions, name)); return new DataElementWithMetadata(ContinueReadingCellArray(reader, dimensions));
} }
if (flags.Class == ArrayType.MxSparse) if (flags.Class == ArrayType.MxSparse)
@ -425,7 +423,7 @@ namespace MatFileHandler
var fieldNameLengthElement = data as MiNum<int> ?? var fieldNameLengthElement = data as MiNum<int> ??
throw new HandlerException( throw new HandlerException(
"Unexpected type in structure field name length."); "Unexpected type in structure field name length.");
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
ContinueReadingStructure(reader, dimensions, fieldNameLengthElement.Data[0]), ContinueReadingStructure(reader, dimensions, fieldNameLengthElement.Data[0]),
flags, flags,
name); name);
@ -437,7 +435,7 @@ namespace MatFileHandler
switch (data) switch (data)
{ {
case MiNum<byte> _: case MiNum<byte> _:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<byte>( DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
flags, flags,
dimensions, dimensions,
@ -446,7 +444,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case MiNum<ushort> _: case MiNum<ushort> _:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>( DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
flags, flags,
dimensions, dimensions,
@ -459,7 +457,7 @@ namespace MatFileHandler
$"This type of char array ({data.GetType()}) is not supported."); $"This type of char array ({data.GetType()}) is not supported.");
} }
case ArrayType.MxInt8: case ArrayType.MxInt8:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>( DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
flags, flags,
dimensions, dimensions,
@ -470,7 +468,7 @@ namespace MatFileHandler
case ArrayType.MxUInt8: case ArrayType.MxUInt8:
if (flags.Variable.HasFlag(Variable.IsLogical)) if (flags.Variable.HasFlag(Variable.IsLogical))
{ {
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<bool>( DataElementConverter.ConvertToMatNumericalArrayOf<bool>(
flags, flags,
dimensions, dimensions,
@ -480,7 +478,7 @@ namespace MatFileHandler
name); name);
} }
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<byte>( DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
flags, flags,
dimensions, dimensions,
@ -489,7 +487,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxInt16: case ArrayType.MxInt16:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<short>( DataElementConverter.ConvertToMatNumericalArrayOf<short>(
flags, flags,
dimensions, dimensions,
@ -498,7 +496,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxUInt16: case ArrayType.MxUInt16:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>( DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
flags, flags,
dimensions, dimensions,
@ -507,7 +505,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxInt32: case ArrayType.MxInt32:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<int>( DataElementConverter.ConvertToMatNumericalArrayOf<int>(
flags, flags,
dimensions, dimensions,
@ -516,7 +514,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxUInt32: case ArrayType.MxUInt32:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<uint>( DataElementConverter.ConvertToMatNumericalArrayOf<uint>(
flags, flags,
dimensions, dimensions,
@ -525,7 +523,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxInt64: case ArrayType.MxInt64:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<long>( DataElementConverter.ConvertToMatNumericalArrayOf<long>(
flags, flags,
dimensions, dimensions,
@ -534,7 +532,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxUInt64: case ArrayType.MxUInt64:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<ulong>( DataElementConverter.ConvertToMatNumericalArrayOf<ulong>(
flags, flags,
dimensions, dimensions,
@ -543,7 +541,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxSingle: case ArrayType.MxSingle:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<float>( DataElementConverter.ConvertToMatNumericalArrayOf<float>(
flags, flags,
dimensions, dimensions,
@ -552,7 +550,7 @@ namespace MatFileHandler
flags, flags,
name); name);
case ArrayType.MxDouble: case ArrayType.MxDouble:
return new DataElementWithArrayFlags( return new DataElementWithMetadata(
DataElementConverter.ConvertToMatNumericalArrayOf<double>( DataElementConverter.ConvertToMatNumericalArrayOf<double>(
flags, flags,
dimensions, dimensions,

View File

@ -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; }
}
}

View File

@ -0,0 +1,54 @@
// Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler
{
/// <summary>
/// Data element together with array flags, variable name, and sparse array's nzMax value.
/// </summary>
internal class DataElementWithMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="DataElementWithMetadata"/> class.
/// </summary>
/// <param name="element">Data element.</param>
/// <param name="flags">Array flags.</param>
/// <param name="name">Variable name.</param>
/// <param name="nzMax">nzMax (for sparse arrays).</param>
public DataElementWithMetadata(DataElement element, ArrayFlags flags, string name, uint nzMax = 0)
{
Element = element;
Flags = flags;
Name = name;
NzMax = nzMax;
}
/// <summary>
/// Initializes a new instance of the <see cref="DataElementWithMetadata"/> class.
/// </summary>
/// <param name="element">Data element.</param>
public DataElementWithMetadata(DataElement element)
{
Element = element;
}
/// <summary>
/// Gets data element.
/// </summary>
public DataElement Element { get; }
/// <summary>
/// Gets array flags.
/// </summary>
public ArrayFlags Flags { get; }
/// <summary>
/// Gets variable name.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets nzMax (for sparse arrays).
/// </summary>
public uint NzMax { get; }
}
}

View File

@ -363,6 +363,14 @@ namespace MatFileHandler
$"Expected data element that would be convertible to uint64, found {element.GetType()}."); $"Expected data element that would be convertible to uint64, found {element.GetType()}.");
} }
/// <summary>
/// Convert sparse MATLAB data into dictionary.
/// </summary>
/// <typeparam name="T">Array element type.</typeparam>
/// <param name="rowIndex">Array of row indices.</param>
/// <param name="columnIndex">Array of column indices.</param>
/// <param name="get">Getter function.</param>
/// <returns>Dictionary mapping (row, column) pairs to value.</returns>
public static Dictionary<(int, int), T> ConvertMatlabSparseToDictionary<T>( public static Dictionary<(int, int), T> ConvertMatlabSparseToDictionary<T>(
int[] rowIndex, int[] rowIndex,
int[] columnIndex, int[] columnIndex,

View File

@ -1,18 +1,32 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// Wrapper for HDF attribute.
/// </summary>
internal struct Attribute : IDisposable internal struct Attribute : IDisposable
{ {
public long Id { get; private set; } /// <summary>
/// Initializes a new instance of the <see cref="Attribute"/> struct.
/// </summary>
/// <param name="locationId">Containing location id.</param>
/// <param name="name">Attribute name.</param>
public Attribute(long locationId, string name) public Attribute(long locationId, string name)
{ {
Id = H5A.open_by_name(locationId, ".", name); Id = H5A.open_by_name(locationId, ".", name);
} }
/// <summary>
/// Gets attribute id.
/// </summary>
public long Id { get; private set; }
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
if (Id != -1) if (Id != -1)
@ -22,6 +36,28 @@ namespace MatFileHandler.Hdf
} }
} }
/// <summary>
/// Get HDF type of the attribute.
/// </summary>
/// <returns>HDF type.</returns>
public Type GetHdfType()
{
return new Type(H5A.get_type(Id));
}
/// <summary>
/// Get HDF space of the attribute.
/// </summary>
/// <returns>HDF space.</returns>
public Space GetSpace()
{
return new Space(H5A.get_space(Id));
}
/// <summary>
/// Read attribute value as boolean.
/// </summary>
/// <returns>Attribute value.</returns>
public bool ReadBool() public bool ReadBool()
{ {
using (var h = new MemoryHandle(sizeof(int))) using (var h = new MemoryHandle(sizeof(int)))
@ -32,19 +68,14 @@ namespace MatFileHandler.Hdf
} }
} }
/// <summary>
/// Read attribute value to the provided memory handle.
/// </summary>
/// <param name="handle">Target memory handle.</param>
/// <param name="type">HDF type to read from the attribute.</param>
public void ReadToHandle(MemoryHandle handle, Type type) public void ReadToHandle(MemoryHandle handle, Type type)
{ {
H5A.read(Id, type.Id, handle.Handle); 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));
}
} }
} }

View File

@ -1,23 +1,41 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// HDF class.
/// </summary>
internal struct Class : IEquatable<Class> internal struct Class : IEquatable<Class>
{ {
public Class(H5T.class_t c) /// <summary>
/// Compound class.
/// </summary>
public static readonly Class Compound = new Class(H5T.class_t.COMPOUND);
/// <summary>
/// Reference class.
/// </summary>
public static readonly Class Reference = new Class(H5T.class_t.REFERENCE);
/// <summary>
/// String class.
/// </summary>
public static readonly Class String = new Class(H5T.class_t.STRING);
private readonly H5T.class_t classT;
/// <summary>
/// Initializes a new instance of the <see cref="Class"/> struct.
/// </summary>
/// <param name="classT">HDF class_t.</param>
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) public static bool operator ==(Class one, Class other)
{ {
return one.Equals(other); return one.Equals(other);
@ -28,19 +46,26 @@ namespace MatFileHandler.Hdf
return !one.Equals(other); return !one.Equals(other);
} }
/// <summary>
/// Check if the class is equal to the other class.
/// </summary>
/// <param name="other">Other class.</param>
/// <returns>True iff the classes are equal.</returns>
public bool Equals(Class other) public bool Equals(Class other)
{ {
return C == other.C; return classT == other.classT;
} }
/// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is Class other && Equals(other); return obj is Class other && Equals(other);
} }
/// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
return (int)C; return (int)classT;
} }
} }
} }

View File

@ -1,22 +1,50 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// HDF dataset.
/// </summary>
internal struct Dataset : IDisposable internal struct Dataset : IDisposable
{ {
public long Id { get; private set; } /// <summary>
/// Initializes a new instance of the <see cref="Dataset"/> struct.
/// </summary>
/// <param name="datasetId">Dataset id.</param>
public Dataset(long datasetId) public Dataset(long datasetId)
{ {
Id = datasetId; Id = datasetId;
} }
/// <summary>
/// Initializes a new instance of the <see cref="Dataset"/> struct.
/// </summary>
/// <param name="groupId">Containing group id.</param>
/// <param name="name">Name of the dataset in the group.</param>
public Dataset(long groupId, string name) public Dataset(long groupId, string name)
{ {
Id = H5D.open(groupId, name); Id = H5D.open(groupId, name);
} }
/// <summary>
/// Gets dataset id.
/// </summary>
public long Id { get; private set; }
/// <summary>
/// Check if dataset attribute with the given name exists.
/// </summary>
/// <param name="name">Attribute name.</param>
/// <returns>True iff dataset has an attribute with this name.</returns>
public bool AttributeExists(string name)
{
return H5A.exists_by_name(Id, ".", name) != 0;
}
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
if (Id != -1) if (Id != -1)
@ -26,31 +54,48 @@ namespace MatFileHandler.Hdf
} }
} }
/// <summary>
/// Open attribute with given name.
/// </summary>
/// <param name="name">Attribute name.</param>
/// <returns>Attribute.</returns>
public Attribute GetAttribute(string name) public Attribute GetAttribute(string name)
{ {
return new Attribute(Id, name); return new Attribute(Id, name);
} }
public bool AttributeExists(string name) /// <summary>
{ /// Get HDF space of the dataset.
return H5A.exists_by_name(Id, ".", name) != 0; /// </summary>
} /// <returns>HDF space.</returns>
public Type GetHdfType()
{
return new Type(H5D.get_type(Id));
}
public int GetStorageSize()
{
return (int)H5D.get_storage_size(Id);
}
public Space GetHdfSpace() public Space GetHdfSpace()
{ {
return new Space(H5D.get_space(Id)); return new Space(H5D.get_space(Id));
} }
/// <summary>
/// Get HDF type of the dataset.
/// </summary>
/// <returns>HDF type.</returns>
public Type GetHdfType()
{
return new Type(H5D.get_type(Id));
}
/// <summary>
/// Get storage size of the dataset.
/// </summary>
/// <returns>Storage size.</returns>
public int GetStorageSize()
{
return (int)H5D.get_storage_size(Id);
}
/// <summary>
/// Read the contents of the dataset into the memory handle.
/// </summary>
/// <param name="type">HDF type of the data to read.</param>
/// <param name="handle">Memory handle.</param>
public void ReadToHandle(Type type, MemoryHandle handle) public void ReadToHandle(Type type, MemoryHandle handle)
{ {
H5D.read(Id, type.Id, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.Handle); H5D.read(Id, type.Id, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.Handle);

View File

@ -1,17 +1,41 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// Hdf group.
/// </summary>
internal struct Group : IDisposable internal struct Group : IDisposable
{ {
public long Id { get; private set; } /// <summary>
/// Initializes a new instance of the <see cref="Group"/> struct.
/// </summary>
/// <param name="groupId">Containing group id.</param>
/// <param name="name">Name of the subgroup in the containing group.</param>
public Group(long groupId, string name) public Group(long groupId, string name)
{ {
Id = H5G.open(groupId, name); Id = H5G.open(groupId, name);
} }
/// <summary>
/// Gets group id.
/// </summary>
public long Id { get; private set; }
/// <summary>
/// Check if group attribute with the given name exists.
/// </summary>
/// <param name="name">Attribute name.</param>
/// <returns>True iff group has an attribute with this name.</returns>
public bool AttributeExists(string name)
{
return H5A.exists_by_name(Id, ".", name) != 0;
}
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
if (Id != -1) if (Id != -1)
@ -21,14 +45,14 @@ namespace MatFileHandler.Hdf
} }
} }
/// <summary>
/// Get group attribute.
/// </summary>
/// <param name="name">Attribute name.</param>
/// <returns>Attribute.</returns>
public Attribute GetAttribute(string name) public Attribute GetAttribute(string name)
{ {
return new Attribute(Id, name); return new Attribute(Id, name);
} }
public bool AttributeExists(string name)
{
return H5A.exists_by_name(Id, ".", name) != 0;
}
} }
} }

View File

@ -1,20 +1,80 @@
namespace MatFileHandler.Hdf // Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler.Hdf
{ {
/// <summary>
/// Matlab classes as they appear in HDF files.
/// </summary>
internal enum MatlabClass internal enum MatlabClass
{ {
/// <summary>
/// Empty array.
/// </summary>
MEmpty, MEmpty,
/// <summary>
/// Char array.
/// </summary>
MChar, MChar,
/// <summary>
/// Int8 array.
/// </summary>
MInt8, MInt8,
/// <summary>
/// UInt8 array.
/// </summary>
MUInt8, MUInt8,
/// <summary>
/// Int16 array.
/// </summary>
MInt16, MInt16,
/// <summary>
/// UInt16 array.
/// </summary>
MUInt16, MUInt16,
/// <summary>
/// Int32 array.
/// </summary>
MInt32, MInt32,
/// <summary>
/// UInt32 array.
/// </summary>
MUInt32, MUInt32,
/// <summary>
/// Int64 array.
/// </summary>
MInt64, MInt64,
/// <summary>
/// UInt64 array.
/// </summary>
MUInt64, MUInt64,
/// <summary>
/// Single-precision floating point array.
/// </summary>
MSingle, MSingle,
/// <summary>
/// Double-precision floating point array.
/// </summary>
MDouble, MDouble,
/// <summary>
/// Cell array.
/// </summary>
MCell, MCell,
/// <summary>
/// Logical array.
/// </summary>
MLogical, MLogical,
} }
} }

View File

@ -1,15 +1,27 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// Wrapper around IntPtr to array in unmanaged memory.
/// </summary>
internal sealed class MemoryHandle : IDisposable internal sealed class MemoryHandle : IDisposable
{ {
/// <summary>
/// Initializes a new instance of the <see cref="MemoryHandle"/> class.
/// </summary>
/// <param name="sizeInBytes">Size of the memory to be allocated.</param>
internal MemoryHandle(int sizeInBytes) internal MemoryHandle(int sizeInBytes)
{ {
Handle = Marshal.AllocHGlobal(sizeInBytes); Handle = Marshal.AllocHGlobal(sizeInBytes);
} }
/// <summary>
/// Gets wrapped IntPtr.
/// </summary>
internal IntPtr Handle { get; private set; } internal IntPtr Handle { get; private set; }
/// <inheritdoc/> /// <inheritdoc/>

View File

@ -1,32 +1,35 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// Array of HDF references stored in an HDF dataset.
/// </summary>
internal struct ReferenceArray : IDisposable, IEnumerable<Dataset> internal struct ReferenceArray : IDisposable, IEnumerable<Dataset>
{ {
public Dataset Dataset { get; } private readonly Dataset[] references;
public int Size { get; }
public MemoryHandle Buf { get; }
public Dataset[] References { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ReferenceArray"/> struct.
/// </summary>
/// <param name="dataset">Containing dataset.</param>
/// <param name="size">Array size.</param>
public ReferenceArray(Dataset dataset, int size) public ReferenceArray(Dataset dataset, int size)
{ {
Dataset = dataset; Dataset = dataset;
Size = size; Size = size;
Buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * size); Buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * size);
Dataset.ReadToHandle(Type.Reference, Buf); Dataset.ReadToHandle(Type.Reference, Buf);
References = new Dataset[size]; references = new Dataset[size];
for (var i = 0; i < size; i++) for (var i = 0; i < size; i++)
{ {
References[i] = references[i] =
new Dataset(H5R.dereference( new Dataset(H5R.dereference(
dataset.Id, dataset.Id,
H5P.DEFAULT, H5P.DEFAULT,
@ -35,26 +38,48 @@ namespace MatFileHandler.Hdf
} }
} }
/// <summary>
/// Gets containing dataset.
/// </summary>
public Dataset Dataset { get; }
/// <summary>
/// Gets references.
/// </summary>
public IReadOnlyList<Dataset> References => references;
/// <summary>
/// Gets array size.
/// </summary>
public int Size { get; }
private MemoryHandle Buf { get; }
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
Buf?.Dispose(); Buf?.Dispose();
if (!(References is null)) if (References is null)
{ {
foreach (var reference in References) return;
{ }
reference.Dispose();
} foreach (var reference in References)
{
reference.Dispose();
} }
} }
/// <inheritdoc />
public IEnumerator<Dataset> GetEnumerator() public IEnumerator<Dataset> GetEnumerator()
{ {
return ((IEnumerable<Dataset>)References).GetEnumerator(); return ((IEnumerable<Dataset>)References).GetEnumerator();
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()
{ {
return References.GetEnumerator(); return References.GetEnumerator();
} }
} }
} }

View File

@ -1,22 +1,42 @@
using System.Linq; // Copyright 2017-2018 Alexander Luzgarev
using System.Linq;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// HDF space.
/// </summary>
internal struct Space internal struct Space
{ {
/// <summary>
/// Initializes a new instance of the <see cref="Space"/> struct.
/// </summary>
/// <param name="id">Space id.</param>
public Space(long id) public Space(long id)
{ {
Id = id; Id = id;
} }
/// <summary>
/// Gets space id.
/// </summary>
public long Id { get; } public long Id { get; }
/// <summary>
/// Get space rank.
/// </summary>
/// <returns>Space rank.</returns>
public int GetRank() public int GetRank()
{ {
return H5S.get_simple_extent_ndims(Id); return H5S.get_simple_extent_ndims(Id);
} }
/// <summary>
/// Get dimensions of the space.
/// </summary>
/// <returns>Space dimensions.</returns>
public int[] GetDimensions() public int[] GetDimensions()
{ {
var dims = new ulong[GetRank()]; var dims = new ulong[GetRank()];

View File

@ -1,70 +1,147 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler.Hdf namespace MatFileHandler.Hdf
{ {
/// <summary>
/// HDF type.
/// </summary>
internal struct Type internal struct Type
{ {
/// <summary>
/// Initializes a new instance of the <see cref="Type"/> struct.
/// </summary>
/// <param name="id">Type id.</param>
public Type(long id) public Type(long id)
{ {
Id = id; Id = id;
} }
/// <summary>
/// Gets HDF string type.
/// </summary>
public static Type CS1 => new Type(H5T.C_S1);
/// <summary>
/// Gets HDF double type.
/// </summary>
public static Type NativeDouble => new Type(H5T.NATIVE_DOUBLE);
/// <summary>
/// Gets HDF float (single) type.
/// </summary>
public static Type NativeFloat => new Type(H5T.NATIVE_FLOAT);
/// <summary>
/// Gets HDF int type.
/// </summary>
public static Type NativeInt => new Type(H5T.NATIVE_INT);
/// <summary>
/// Gets HDF int16 type.
/// </summary>
public static Type NativeInt16 => new Type(H5T.NATIVE_INT16);
/// <summary>
/// Gets HDF int32 type.
/// </summary>
public static Type NativeInt32 => new Type(H5T.NATIVE_INT32);
/// <summary>
/// Gets HDF int64 type.
/// </summary>
public static Type NativeInt64 => new Type(H5T.NATIVE_INT64);
/// <summary>
/// Gets HDF int8 type.
/// </summary>
public static Type NativeInt8 => new Type(H5T.NATIVE_INT8);
/// <summary>
/// Gets HDF uint type.
/// </summary>
public static Type NativeUInt => new Type(H5T.NATIVE_UINT);
/// <summary>
/// Gets HDF uint16 type
/// </summary>
public static Type NativeUInt16 => new Type(H5T.NATIVE_UINT16);
/// <summary>
/// Gets HDF uint32 type.
/// </summary>
public static Type NativeUInt32 => new Type(H5T.NATIVE_UINT32);
/// <summary>
/// Gets HDF uint64 type.
/// </summary>
public static Type NativeUInt64 => new Type(H5T.NATIVE_UINT64);
/// <summary>
/// Gets HDF uint8 type.
/// </summary>
public static Type NativeUInt8 => new Type(H5T.NATIVE_UINT8);
/// <summary>
/// Gets HDF reference type.
/// </summary>
public static Type Reference => new Type(H5T.STD_REF_OBJ);
/// <summary>
/// Gets type id.
/// </summary>
public long Id { get; } public long Id { get; }
/// <summary>
/// Create compound type of given size.
/// </summary>
/// <param name="size">Size of the type.</param>
/// <returns>The created type.</returns>
public static Type CreateCompound(int size)
{
return new Type(H5T.create(H5T.class_t.COMPOUND, (IntPtr)size));
}
/// <summary>
/// Get class of the type.
/// </summary>
/// <returns>Class of the type.</returns>
public Class GetClass() public Class GetClass()
{ {
return new Class(H5T.get_class(Id)); return new Class(H5T.get_class(Id));
} }
/// <summary>
/// Get size of the type.
/// </summary>
/// <returns>Size of the type.</returns>
public int GetSize() public int GetSize()
{ {
return (int)H5T.get_size(Id); return (int)H5T.get_size(Id);
} }
public static Type NativeInt8 => new Type(H5T.NATIVE_INT8); /// <summary>
/// Insert a field into the type.
public static Type NativeUInt8 => new Type(H5T.NATIVE_UINT8); /// </summary>
/// <param name="name">Field name.</param>
public static Type NativeInt16 => new Type(H5T.NATIVE_INT16); /// <param name="fieldType">Field type.</param>
public void InsertField(string name, Type fieldType)
public static Type NativeUInt16 => new Type(H5T.NATIVE_UINT16); {
H5T.insert(Id, name, IntPtr.Zero, fieldType.Id);
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);
/// <summary>
/// Create type copy with same class and given size.
/// </summary>
/// <param name="size">New size.</param>
/// <returns>New type.</returns>
public Type WithSize(int size) public Type WithSize(int size)
{ {
var classId = H5T.copy(Id); var classId = H5T.copy(Id);
H5T.set_size(classId, (IntPtr)size); H5T.set_size(classId, (IntPtr)size);
return new Type(classId); 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);
}
} }
} }

View File

@ -1,4 +1,6 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
@ -9,29 +11,40 @@ using MatFileHandler.Hdf;
namespace MatFileHandler namespace MatFileHandler
{ {
/// <summary>
/// Reader of HDF files containing MATLAB data.
/// </summary>
internal class HdfFileReader 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 const string SparseAttributeName = "MATLAB_sparse";
private long fileId;
private readonly long fileId;
private List<IVariable> variables; private List<IVariable> variables;
/// <summary>
/// Initializes a new instance of the <see cref="HdfFileReader"/> class.
/// </summary>
/// <param name="fileId">File id to read data from.</param>
internal HdfFileReader(long fileId) internal HdfFileReader(long fileId)
{ {
this.fileId = fileId; this.fileId = fileId;
} }
/// <summary>
/// Read MATLAB data from the HDF file.
/// </summary>
/// <returns>MATLAB data file contents.</returns>
internal IMatFile Read() internal IMatFile Read()
{ {
variables = new List<IVariable>(); variables = new List<IVariable>();
var group_info = default(H5G.info_t); var group_info = default(H5G.info_t);
H5G.get_info(fileId, ref group_info); H5G.get_info(fileId, ref group_info);
var numberOfVariables = group_info.nlinks; var numberOfVariables = group_info.nlinks;
ulong idx = 0; ulong idx = 0;
while (idx < numberOfVariables) while (idx < numberOfVariables)
{ {
@ -117,12 +130,22 @@ namespace MatFileHandler
Marshal.Copy(buf.Handle, matlabClassNameBytes, 0, typeIdSize); 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) private static string GetMatlabClassOfDataset(Dataset dataset)
{ {
using (var attribute = dataset.GetAttribute(classAttributeName)) using (var attribute = dataset.GetAttribute(ClassAttributeName))
{ {
return GetMatlabClassFromAttribute(attribute); return GetMatlabClassFromAttribute(attribute);
} }
@ -130,7 +153,7 @@ namespace MatFileHandler
private static string GetMatlabClassOfGroup(Group group) private static string GetMatlabClassOfGroup(Group group)
{ {
using (var attribute = group.GetAttribute(classAttributeName)) using (var attribute = group.GetAttribute(ClassAttributeName))
{ {
return GetMatlabClassFromAttribute(attribute); return GetMatlabClassFromAttribute(attribute);
} }
@ -315,9 +338,8 @@ namespace MatFileHandler
return ReadStruct(group.Id); return ReadStruct(group.Id);
} }
if (group.AttributeExists(sparseAttributeName)) if (group.AttributeExists(SparseAttributeName))
{ {
var dims = new int[0];
var arrayType = ArrayTypeFromMatlabClassName(matlabClass); var arrayType = ArrayTypeFromMatlabClassName(matlabClass);
switch (arrayType) switch (arrayType)
@ -378,7 +400,6 @@ namespace MatFileHandler
{ {
var numberOfElements = dims.NumberOfElements(); var numberOfElements = dims.NumberOfElements();
var dataSize = numberOfElements * SizeOfArrayElement(arrayType); var dataSize = numberOfElements * SizeOfArrayElement(arrayType);
var storageSize = dataset.GetStorageSize();
var dataSetType = dataset.GetHdfType(); var dataSetType = dataset.GetHdfType();
var dataSetTypeClass = dataSetType.GetClass(); var dataSetTypeClass = dataSetType.GetClass();
var isCompound = dataSetTypeClass == Class.Compound; 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 data = ReadDataset(dataset, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
var convertedData = ConvertDataToProperType<T>(data, arrayType); var convertedData = ConvertDataToProperType<T>(data, arrayType);
return new MatNumericalArrayOf<T>(dims, convertedData); return new MatNumericalArrayOf<T>(dims, convertedData);
@ -418,7 +434,7 @@ namespace MatFileHandler
private static IArray ReadSparseArray<T>(long groupId, MatlabClass arrayType) private static IArray ReadSparseArray<T>(long groupId, MatlabClass arrayType)
where T : struct 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))) using (var numberOfRowsHandle = new MemoryHandle(sizeof(uint)))
{ {
@ -464,7 +480,7 @@ namespace MatFileHandler
var complexData = var complexData =
CombineComplexData( CombineComplexData(
convertedRealData as double[], convertedRealData as double[],
convertedImaginaryData as double[]) convertedImaginaryData as double[])
.ToArray(); .ToArray();
var complexDataDictionary = var complexDataDictionary =
DataExtraction.ConvertMatlabSparseToDictionary( DataExtraction.ConvertMatlabSparseToDictionary(
@ -475,7 +491,7 @@ namespace MatFileHandler
} }
else else
{ {
var complexData = var complexData =
CombineComplexOfData<T>( CombineComplexOfData<T>(
convertedRealData, convertedRealData,
convertedImaginaryData) convertedImaginaryData)
@ -489,11 +505,6 @@ namespace MatFileHandler
} }
} }
if (dataSize != storageSize)
{
throw new Exception("Data size mismatch.");
}
var d = ReadDataset(data, H5tTypeFromHdfMatlabClass(arrayType), dataSize); var d = ReadDataset(data, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
var elements = ConvertDataToProperType<T>(d, arrayType); var elements = ConvertDataToProperType<T>(d, arrayType);
var dataDictionary = var dataDictionary =
@ -515,7 +526,7 @@ namespace MatFileHandler
var firstFieldType = firstField.GetHdfType(); var firstFieldType = firstField.GetHdfType();
if (firstFieldType.GetClass() == Class.Reference) if (firstFieldType.GetClass() == Class.Reference)
{ {
if (firstField.AttributeExists(classAttributeName)) if (firstField.AttributeExists(ClassAttributeName))
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -592,12 +603,12 @@ namespace MatFileHandler
private bool ReadGlobalFlag(Group group) private bool ReadGlobalFlag(Group group)
{ {
if (!group.AttributeExists(globalAttributeName)) if (!group.AttributeExists(GlobalAttributeName))
{ {
return false; return false;
} }
using (var globalAttribute = group.GetAttribute(globalAttributeName)) using (var globalAttribute = group.GetAttribute(GlobalAttributeName))
{ {
return globalAttribute.ReadBool(); return globalAttribute.ReadBool();
} }
@ -605,12 +616,12 @@ namespace MatFileHandler
private bool ReadGlobalFlag(Dataset dataset) private bool ReadGlobalFlag(Dataset dataset)
{ {
if (!dataset.AttributeExists(globalAttributeName)) if (!dataset.AttributeExists(GlobalAttributeName))
{ {
return false; return false;
} }
using (var globalAttribute = dataset.GetAttribute(globalAttributeName)) using (var globalAttribute = dataset.GetAttribute(GlobalAttributeName))
{ {
return globalAttribute.ReadBool(); return globalAttribute.ReadBool();
} }

View File

@ -21,6 +21,9 @@ namespace MatFileHandler
Version = version; Version = version;
} }
/// <summary>
/// Gets raw byte contents of the header.
/// </summary>
public byte[] RawBytes { get; } public byte[] RawBytes { get; }
/// <summary> /// <summary>

View File

@ -1,12 +1,23 @@
using System; // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using HDF.PInvoke; using HDF.PInvoke;
namespace MatFileHandler namespace MatFileHandler
{ {
/// <summary>
/// Reader for MATLAB HDF (-v7.3) files.
/// </summary>
internal static class MatFileHdfReader internal static class MatFileHdfReader
{ {
/// <summary>
/// Continue reading MATLAB HDF file after reading the MATLAB header.
/// </summary>
/// <param name="header">MATLAB header that was read.</param>
/// <param name="stream">Stream to read the rest of the file from.</param>
/// <returns>MATLAB data file contents.</returns>
internal static IMatFile ContinueReadingHdfFile(Header header, Stream stream) internal static IMatFile ContinueReadingHdfFile(Header header, Stream stream)
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())

View File

@ -1,4 +1,6 @@
using System.Collections.Generic; // Copyright 2017-2018 Alexander Luzgarev
using System.Collections.Generic;
using System.IO; using System.IO;
namespace MatFileHandler namespace MatFileHandler
@ -61,6 +63,12 @@ namespace MatFileHandler
return ReadRawVariables(reader, subsystemDataOffset, subsystemData); return ReadRawVariables(reader, subsystemDataOffset, subsystemData);
} }
/// <summary>
/// Continue reading old-style (Level 5) MATLAB file.
/// </summary>
/// <param name="header">Header that was already read.</param>
/// <param name="reader">Reader for reading the rest of the file.</param>
/// <returns>MATLAB data file contents.</returns>
internal static IMatFile ContinueReadingLevel5File(Header header, BinaryReader reader) internal static IMatFile ContinueReadingLevel5File(Header header, BinaryReader reader)
{ {
var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset); var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset);

View File

@ -33,6 +33,11 @@ namespace MatFileHandler
} }
} }
private static Header ReadHeader(BinaryReader reader)
{
return Header.Read(reader);
}
private IMatFile Read(BinaryReader reader) private IMatFile Read(BinaryReader reader)
{ {
var header = ReadHeader(reader); var header = ReadHeader(reader);
@ -46,10 +51,5 @@ namespace MatFileHandler
throw new NotSupportedException($"Unknown file format."); throw new NotSupportedException($"Unknown file format.");
} }
} }
private static Header ReadHeader(BinaryReader reader)
{
return Header.Read(reader);
}
} }
} }

View File

@ -43,7 +43,7 @@ namespace MatFileHandler
get get
{ {
var rowAndColumn = GetRowAndColumn(list); var rowAndColumn = GetRowAndColumn(list);
return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default(T); return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default;
} }
set => DataDictionary[GetRowAndColumn(list)] = value; set => DataDictionary[GetRowAndColumn(list)] = value;
} }

View File

@ -17,6 +17,8 @@ namespace MatFileHandler
/// </summary> /// </summary>
/// <param name="offset">Offset of the variable in the source file.</param> /// <param name="offset">Offset of the variable in the source file.</param>
/// <param name="dataElement">Data element parsed from the file.</param> /// <param name="dataElement">Data element parsed from the file.</param>
/// <param name="flags">Array flags.</param>
/// <param name="name">Variable name.</param>
internal RawVariable(long offset, DataElement dataElement, ArrayFlags flags, string name) internal RawVariable(long offset, DataElement dataElement, ArrayFlags flags, string name)
{ {
Offset = offset; Offset = offset;
@ -30,8 +32,14 @@ namespace MatFileHandler
/// </summary> /// </summary>
public DataElement DataElement { get; } public DataElement DataElement { get; }
/// <summary>
/// Gets array flags.
/// </summary>
public ArrayFlags Flags { get; } public ArrayFlags Flags { get; }
/// <summary>
/// Gets variable name.
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>