Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
80e4356442 | |||
aaefd0eb86 | |||
6a286ed53d | |||
e6d236139c | |||
bdd04a80b7 | |||
433dca8c69 | |||
ef73a380bb | |||
199ab46f0c | |||
cfe51d57ae | |||
f727c6d430 | |||
82f43a7e5d | |||
99558d96c4 | |||
67905605d6 | |||
b0ae15abc9 | |||
beae9e4429 | |||
b66e380414 | |||
93be86d526 | |||
0e14434bae | |||
957234d30d |
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright 2017 Alexander Luzgarev
|
Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||||
|
<RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
||||||
|
744
MatFileHandler.Tests/MatFileReaderTests.cs
Executable file → Normal file
744
MatFileHandler.Tests/MatFileReaderTests.cs
Executable file → Normal file
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -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 MatFileReaderTests
|
public class MatFileReaderTests
|
||||||
@ -17,59 +17,30 @@ namespace MatFileHandler.Tests
|
|||||||
private const string TestDirectory = "test-data";
|
private const string TestDirectory = "test-data";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading all files in a given test set.
|
/// Test reading an ASCII-encoded string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="testSet">Name of the set.</param>
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
[TestCase("good")]
|
[TestCase("level5/ascii")]
|
||||||
public void TestReader(string testSet)
|
[TestCase("hdf/ascii")]
|
||||||
|
public void TestAscii(string testCaseName)
|
||||||
{
|
{
|
||||||
foreach (var matFile in GetTests(testSet).GetAllTestData())
|
var matFile = GetTestCase(testCaseName);
|
||||||
{
|
var arrayAscii = matFile["s"].Value as ICharArray;
|
||||||
Assert.That(matFile.Variables, Is.Not.Empty);
|
Assert.That(arrayAscii, Is.Not.Null);
|
||||||
}
|
Assert.That(arrayAscii.Dimensions, Is.EqualTo(new[] { 1, 3 }));
|
||||||
}
|
Assert.That(arrayAscii.String, Is.EqualTo("abc"));
|
||||||
|
Assert.That(arrayAscii[2], Is.EqualTo('c'));
|
||||||
/// <summary>
|
|
||||||
/// Test reading lower and upper limits of integer data types.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestLimits()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["limits"];
|
|
||||||
IArray array;
|
|
||||||
array = matFile["int8_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<sbyte>, CommonData.Int8Limits);
|
|
||||||
Assert.That(array.ConvertToDoubleArray(), Is.EqualTo(new[] { -128.0, 127.0 }));
|
|
||||||
|
|
||||||
array = matFile["uint8_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<byte>, CommonData.UInt8Limits);
|
|
||||||
|
|
||||||
array = matFile["int16_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<short>, CommonData.Int16Limits);
|
|
||||||
|
|
||||||
array = matFile["uint16_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<ushort>, CommonData.UInt16Limits);
|
|
||||||
|
|
||||||
array = matFile["int32_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<int>, CommonData.Int32Limits);
|
|
||||||
|
|
||||||
array = matFile["uint32_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<uint>, CommonData.UInt32Limits);
|
|
||||||
|
|
||||||
array = matFile["int64_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<long>, CommonData.Int64Limits);
|
|
||||||
|
|
||||||
array = matFile["uint64_"].Value;
|
|
||||||
CheckLimits(array as IArrayOf<ulong>, CommonData.UInt64Limits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing lower and upper limits of integer-based complex data types.
|
/// Test writing lower and upper limits of integer-based complex data types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestComplexLimits()
|
[TestCase("level5/limits_complex")]
|
||||||
|
[TestCase("hdf/limits_complex")]
|
||||||
|
public void TestComplexLimits(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["limits_complex"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
IArray array;
|
IArray array;
|
||||||
array = matFile["int8_complex"].Value;
|
array = matFile["int8_complex"].Value;
|
||||||
CheckComplexLimits(array as IArrayOf<ComplexOf<sbyte>>, CommonData.Int8Limits);
|
CheckComplexLimits(array as IArrayOf<ComplexOf<sbyte>>, CommonData.Int8Limits);
|
||||||
@ -100,78 +71,345 @@ namespace MatFileHandler.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading an ASCII-encoded string.
|
/// Test reading a two-dimensional complex array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestAscii()
|
[TestCase("level5/matrix_complex")]
|
||||||
|
[TestCase("hdf/matrix_complex")]
|
||||||
|
public void TestComplexMatrix(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["ascii"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var arrayAscii = matFile["s"].Value as ICharArray;
|
var matrix = matFile["matrix"].Value as IArrayOf<Complex>;
|
||||||
Assert.That(arrayAscii, Is.Not.Null);
|
Assert.That(matrix.Dimensions, Is.EqualTo(new[] { 3, 2 }));
|
||||||
Assert.That(arrayAscii.Dimensions, Is.EqualTo(new[] { 1, 3 }));
|
Assert.That(matrix.ConvertToComplexArray(), Is.EqualTo(new[]
|
||||||
Assert.That(arrayAscii.String, Is.EqualTo("abc"));
|
|
||||||
Assert.That(arrayAscii[2], Is.EqualTo('c'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a Unicode string.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestUnicode()
|
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["unicode"];
|
new Complex(1.0, 4.0),
|
||||||
var arrayUnicode = matFile["s"].Value as ICharArray;
|
new Complex(3.0, 1.0),
|
||||||
Assert.That(arrayUnicode, Is.Not.Null);
|
new Complex(5.0, 0.25),
|
||||||
Assert.That(arrayUnicode.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
new Complex(2.0, 2.0),
|
||||||
Assert.That(arrayUnicode.String, Is.EqualTo("必フ"));
|
new Complex(4.0, 0.5),
|
||||||
Assert.That(arrayUnicode[0], Is.EqualTo('必'));
|
new Complex(6.0, 0.125),
|
||||||
Assert.That(arrayUnicode[1], Is.EqualTo('フ'));
|
}));
|
||||||
}
|
Assert.That(matrix[0, 0], Is.EqualTo(new Complex(1.0, 4.0)));
|
||||||
|
Assert.That(matrix[0, 1], Is.EqualTo(new Complex(2.0, 2.0)));
|
||||||
/// <summary>
|
Assert.That(matrix[1, 0], Is.EqualTo(new Complex(3.0, 1.0)));
|
||||||
/// Test reading a wide Unicode string.
|
Assert.That(matrix[1, 1], Is.EqualTo(new Complex(4.0, 0.5)));
|
||||||
/// </summary>
|
Assert.That(matrix[2, 0], Is.EqualTo(new Complex(5.0, 0.25)));
|
||||||
[Test]
|
Assert.That(matrix[2, 1], Is.EqualTo(new Complex(6.0, 0.125)));
|
||||||
public void TestUnicodeWide()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["unicode-wide"];
|
|
||||||
var arrayUnicodeWide = matFile["s"].Value as ICharArray;
|
|
||||||
Assert.That(arrayUnicodeWide, Is.Not.Null);
|
|
||||||
Assert.That(arrayUnicodeWide.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
|
||||||
Assert.That(arrayUnicodeWide.String, Is.EqualTo("🍆"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test converting a structure array to a Double array.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Should return null.</returns>
|
|
||||||
[Test(ExpectedResult = null)]
|
|
||||||
public double[] TestConvertToDoubleArray()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["struct"];
|
|
||||||
var array = matFile.Variables[0].Value;
|
|
||||||
return array.ConvertToDoubleArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test converting a structure array to a Complex array.
|
/// Test converting a structure array to a Complex array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Should return null.</returns>
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
[Test(ExpectedResult = null)]
|
[TestCase("level5/struct")]
|
||||||
public Complex[] TestConvertToComplexArray()
|
[TestCase("hdf/struct")]
|
||||||
|
public void TestConvertToComplexArray(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["struct"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var array = matFile.Variables[0].Value;
|
var array = matFile.Variables[0].Value;
|
||||||
return array.ConvertToComplexArray();
|
Assert.IsNull(array.ConvertToComplexArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test converting a structure array to a Double array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/struct")]
|
||||||
|
[TestCase("hdf/struct")]
|
||||||
|
public void TestConvertToDoubleArray(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var array = matFile.Variables[0].Value;
|
||||||
|
Assert.IsNull(array.ConvertToDoubleArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test datetime objects.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDatetime()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("datetime");
|
||||||
|
var d = matFile["d"].Value as IMatObject;
|
||||||
|
var datetime = new DatetimeAdapter(d);
|
||||||
|
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 2 }));
|
||||||
|
Assert.That(datetime[0], Is.EqualTo(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero)));
|
||||||
|
Assert.That(datetime[1], Is.EqualTo(new DateTimeOffset(1987, 1, 2, 3, 4, 5, TimeSpan.Zero)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test unrepresentable datetime.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDatetime_Unrepresentable()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("datetime-unrepresentable");
|
||||||
|
var obj = matFile["d"].Value as IMatObject;
|
||||||
|
var datetime = new DatetimeAdapter(obj);
|
||||||
|
var d0 = datetime[0];
|
||||||
|
Assert.That(d0, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Another test for datetime objects.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDatetime2()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("datetime2");
|
||||||
|
var d = matFile["d"].Value as IMatObject;
|
||||||
|
var datetime = new DatetimeAdapter(d);
|
||||||
|
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 1 }));
|
||||||
|
var diff = new DateTimeOffset(2, 1, 1, 1, 1, 1, 235, TimeSpan.Zero);
|
||||||
|
Assert.That(datetime[0] - diff < TimeSpan.FromMilliseconds(1));
|
||||||
|
Assert.That(diff - datetime[0] < TimeSpan.FromMilliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test duration objects.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestDuration()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("duration");
|
||||||
|
var d = matFile["d"].Value as IMatObject;
|
||||||
|
var duration = new DurationAdapter(d);
|
||||||
|
Assert.That(duration.Dimensions, Is.EquivalentTo(new[] { 1, 3 }));
|
||||||
|
Assert.That(duration[0], Is.EqualTo(TimeSpan.FromTicks(12345678L)));
|
||||||
|
Assert.That(duration[1], Is.EqualTo(new TimeSpan(0, 2, 4)));
|
||||||
|
Assert.That(duration[2], Is.EqualTo(new TimeSpan(1, 3, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a global variable.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/global")]
|
||||||
|
[TestCase("hdf/global")]
|
||||||
|
public void TestGlobal(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var variable = matFile.Variables.First();
|
||||||
|
Assert.That(variable.IsGlobal, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading lower and upper limits of integer data types.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/limits")]
|
||||||
|
[TestCase("hdf/limits")]
|
||||||
|
public void TestLimits(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
IArray array;
|
||||||
|
array = matFile["int8_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<sbyte>, CommonData.Int8Limits);
|
||||||
|
Assert.That(array.ConvertToDoubleArray(), Is.EqualTo(new[] { -128.0, 127.0 }));
|
||||||
|
|
||||||
|
array = matFile["uint8_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<byte>, CommonData.UInt8Limits);
|
||||||
|
|
||||||
|
array = matFile["int16_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<short>, CommonData.Int16Limits);
|
||||||
|
|
||||||
|
array = matFile["uint16_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<ushort>, CommonData.UInt16Limits);
|
||||||
|
|
||||||
|
array = matFile["int32_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<int>, CommonData.Int32Limits);
|
||||||
|
|
||||||
|
array = matFile["uint32_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<uint>, CommonData.UInt32Limits);
|
||||||
|
|
||||||
|
array = matFile["int64_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<long>, CommonData.Int64Limits);
|
||||||
|
|
||||||
|
array = matFile["uint64_"].Value;
|
||||||
|
CheckLimits(array as IArrayOf<ulong>, CommonData.UInt64Limits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a logical array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/logical")]
|
||||||
|
[TestCase("hdf/logical")]
|
||||||
|
public void TestLogical(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var array = matFile["logical_"].Value;
|
||||||
|
var logicalArray = array as IArrayOf<bool>;
|
||||||
|
Assert.That(logicalArray, Is.Not.Null);
|
||||||
|
Assert.That(logicalArray[0, 0], Is.True);
|
||||||
|
Assert.That(logicalArray[0, 1], Is.True);
|
||||||
|
Assert.That(logicalArray[0, 2], Is.False);
|
||||||
|
Assert.That(logicalArray[1, 0], Is.False);
|
||||||
|
Assert.That(logicalArray[1, 1], Is.True);
|
||||||
|
Assert.That(logicalArray[1, 2], Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a two-dimensional double array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/matrix")]
|
||||||
|
[TestCase("hdf/matrix")]
|
||||||
|
public void TestMatrix(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var matrix = matFile["matrix"].Value as IArrayOf<double>;
|
||||||
|
Assert.That(matrix.Dimensions, Is.EqualTo(new[] { 3, 2 }));
|
||||||
|
Assert.That(matrix.ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0, 3.0, 5.0, 2.0, 4.0, 6.0 }));
|
||||||
|
Assert.That(matrix[0, 0], Is.EqualTo(1.0));
|
||||||
|
Assert.That(matrix[0, 1], Is.EqualTo(2.0));
|
||||||
|
Assert.That(matrix[1, 0], Is.EqualTo(3.0));
|
||||||
|
Assert.That(matrix[1, 1], Is.EqualTo(4.0));
|
||||||
|
Assert.That(matrix[2, 0], Is.EqualTo(5.0));
|
||||||
|
Assert.That(matrix[2, 1], Is.EqualTo(6.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test nested objects.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestNestedObjects()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("subsubPoint");
|
||||||
|
var p = matFile["p"].Value as IMatObject;
|
||||||
|
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
||||||
|
Assert.That(p["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 1.0 }));
|
||||||
|
var pp = p["y"] as IMatObject;
|
||||||
|
Assert.That(pp.ClassName == "Point");
|
||||||
|
Assert.That(pp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 10.0 }));
|
||||||
|
var ppp = pp["y"] as IMatObject;
|
||||||
|
Assert.That(ppp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 100.0 }));
|
||||||
|
Assert.That(ppp["y"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 200.0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading an object.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestObject()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("object");
|
||||||
|
var obj = matFile["object_"].Value as IMatObject;
|
||||||
|
Assert.IsNotNull(obj);
|
||||||
|
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
||||||
|
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
|
Assert.That(obj["x", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
||||||
|
Assert.That(obj["y", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
||||||
|
Assert.That(obj["x", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
|
Assert.That(obj["y", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading another object.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestObject2()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("object2");
|
||||||
|
var obj = matFile["object2"].Value as IMatObject;
|
||||||
|
Assert.IsNotNull(obj);
|
||||||
|
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
||||||
|
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
|
Assert.That(obj["x", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
||||||
|
Assert.That(obj["y", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
||||||
|
Assert.That(obj["x", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
||||||
|
Assert.That(obj["y", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
||||||
|
Assert.That(obj["x", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
|
Assert.That(obj["y", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
||||||
|
Assert.That(obj["x", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
||||||
|
Assert.That(obj["y", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
||||||
|
Assert.That(obj[0, 1]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
|
Assert.That(obj[2]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading all files in a given test set.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testSet">Name of the set.</param>
|
||||||
|
[TestCase("level5")]
|
||||||
|
[TestCase("hdf")]
|
||||||
|
public void TestReader(string testSet)
|
||||||
|
{
|
||||||
|
foreach (var matFile in GetTests(testSet).GetAllTestData())
|
||||||
|
{
|
||||||
|
Assert.That(matFile.Variables, Is.Not.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a sparse array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/sparse")]
|
||||||
|
[TestCase("hdf/sparse")]
|
||||||
|
public void TestSparse(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var sparseArray = matFile["sparse_"].Value as ISparseArrayOf<double>;
|
||||||
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
|
Assert.That(sparseArray.Dimensions, Is.EqualTo(new[] { 4, 5 }));
|
||||||
|
Assert.That(sparseArray.Data[(1, 1)], Is.EqualTo(1.0));
|
||||||
|
Assert.That(sparseArray[1, 1], Is.EqualTo(1.0));
|
||||||
|
Assert.That(sparseArray[1, 2], Is.EqualTo(2.0));
|
||||||
|
Assert.That(sparseArray[2, 1], Is.EqualTo(3.0));
|
||||||
|
Assert.That(sparseArray[2, 3], Is.EqualTo(4.0));
|
||||||
|
Assert.That(sparseArray[0, 4], Is.EqualTo(0.0));
|
||||||
|
Assert.That(sparseArray[3, 0], Is.EqualTo(0.0));
|
||||||
|
Assert.That(sparseArray[3, 4], Is.EqualTo(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test reading a sparse logical array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
|
[TestCase("level5/sparse_logical")]
|
||||||
|
[TestCase("hdf/sparse_logical")]
|
||||||
|
public void TestSparseLogical(string testCaseName)
|
||||||
|
{
|
||||||
|
var matFile = GetTestCase(testCaseName);
|
||||||
|
var array = matFile["sparse_logical"].Value;
|
||||||
|
var sparseArray = array as ISparseArrayOf<bool>;
|
||||||
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
|
Assert.That(sparseArray.Data[(0, 0)], Is.True);
|
||||||
|
Assert.That(sparseArray[0, 0], Is.True);
|
||||||
|
Assert.That(sparseArray[0, 1], Is.True);
|
||||||
|
Assert.That(sparseArray[0, 2], Is.False);
|
||||||
|
Assert.That(sparseArray[1, 0], Is.False);
|
||||||
|
Assert.That(sparseArray[1, 1], Is.True);
|
||||||
|
Assert.That(sparseArray[1, 2], Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test string objects.
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TestString()
|
||||||
|
{
|
||||||
|
var matFile = ReadLevel5TestFile("string");
|
||||||
|
var s = matFile["s"].Value as IMatObject;
|
||||||
|
var str = new StringAdapter(s);
|
||||||
|
Assert.That(str.Dimensions, Is.EquivalentTo(new[] { 4, 1 }));
|
||||||
|
Assert.That(str[0], Is.EqualTo("abc"));
|
||||||
|
Assert.That(str[1], Is.EqualTo("defgh"));
|
||||||
|
Assert.That(str[2], Is.EqualTo("абвгд"));
|
||||||
|
Assert.That(str[3], Is.EqualTo("æøå"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a structure array.
|
/// Test reading a structure array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestStruct()
|
[TestCase("level5/struct")]
|
||||||
|
[TestCase("hdf/struct")]
|
||||||
|
public void TestStruct(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["struct"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var structure = matFile["struct_"].Value as IStructureArray;
|
var structure = matFile["struct_"].Value as IStructureArray;
|
||||||
Assert.That(structure, Is.Not.Null);
|
Assert.That(structure, Is.Not.Null);
|
||||||
Assert.That(structure.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
Assert.That(structure.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
@ -203,158 +441,13 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.That(structure["y", 1, 2].IsEmpty, Is.True);
|
Assert.That(structure["y", 1, 2].IsEmpty, Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a sparse array.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestSparse()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["sparse"];
|
|
||||||
var sparseArray = matFile["sparse_"].Value as ISparseArrayOf<double>;
|
|
||||||
Assert.That(sparseArray, Is.Not.Null);
|
|
||||||
Assert.That(sparseArray.Dimensions, Is.EqualTo(new[] { 4, 5 }));
|
|
||||||
Assert.That(sparseArray.Data[(1, 1)], Is.EqualTo(1.0));
|
|
||||||
Assert.That(sparseArray[1, 1], Is.EqualTo(1.0));
|
|
||||||
Assert.That(sparseArray[1, 2], Is.EqualTo(2.0));
|
|
||||||
Assert.That(sparseArray[2, 1], Is.EqualTo(3.0));
|
|
||||||
Assert.That(sparseArray[2, 3], Is.EqualTo(4.0));
|
|
||||||
Assert.That(sparseArray[0, 4], Is.EqualTo(0.0));
|
|
||||||
Assert.That(sparseArray[3, 0], Is.EqualTo(0.0));
|
|
||||||
Assert.That(sparseArray[3, 4], Is.EqualTo(0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a logical array.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestLogical()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["logical"];
|
|
||||||
var array = matFile["logical_"].Value;
|
|
||||||
var logicalArray = array as IArrayOf<bool>;
|
|
||||||
Assert.That(logicalArray, Is.Not.Null);
|
|
||||||
Assert.That(logicalArray[0, 0], Is.True);
|
|
||||||
Assert.That(logicalArray[0, 1], Is.True);
|
|
||||||
Assert.That(logicalArray[0, 2], Is.False);
|
|
||||||
Assert.That(logicalArray[1, 0], Is.False);
|
|
||||||
Assert.That(logicalArray[1, 1], Is.True);
|
|
||||||
Assert.That(logicalArray[1, 2], Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a sparse logical array.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestSparseLogical()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["sparse_logical"];
|
|
||||||
var array = matFile["sparse_logical"].Value;
|
|
||||||
var sparseArray = array as ISparseArrayOf<bool>;
|
|
||||||
Assert.That(sparseArray, Is.Not.Null);
|
|
||||||
Assert.That(sparseArray.Data[(0, 0)], Is.True);
|
|
||||||
Assert.That(sparseArray[0, 0], Is.True);
|
|
||||||
Assert.That(sparseArray[0, 1], Is.True);
|
|
||||||
Assert.That(sparseArray[0, 2], Is.False);
|
|
||||||
Assert.That(sparseArray[1, 0], Is.False);
|
|
||||||
Assert.That(sparseArray[1, 1], Is.True);
|
|
||||||
Assert.That(sparseArray[1, 2], Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a global variable.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestGlobal()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["global"];
|
|
||||||
var variable = matFile.Variables.First();
|
|
||||||
Assert.That(variable.IsGlobal, Is.True);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a sparse complex array.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TextSparseComplex()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["sparse_complex"];
|
|
||||||
var array = matFile["sparse_complex"].Value;
|
|
||||||
var sparseArray = array as ISparseArrayOf<Complex>;
|
|
||||||
Assert.That(sparseArray, Is.Not.Null);
|
|
||||||
Assert.That(sparseArray[0, 0], Is.EqualTo(-1.5 + (2.5 * Complex.ImaginaryOne)));
|
|
||||||
Assert.That(sparseArray[1, 0], Is.EqualTo(2 - (3 * Complex.ImaginaryOne)));
|
|
||||||
Assert.That(sparseArray[0, 1], Is.EqualTo(Complex.Zero));
|
|
||||||
Assert.That(sparseArray[1, 1], Is.EqualTo(0.5 + (1.0 * Complex.ImaginaryOne)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading an object.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestObject()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["object"];
|
|
||||||
var obj = matFile["object_"].Value as IMatObject;
|
|
||||||
Assert.IsNotNull(obj);
|
|
||||||
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
|
||||||
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
|
||||||
Assert.That(obj["x", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
|
||||||
Assert.That(obj["y", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
|
||||||
Assert.That(obj["x", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
|
||||||
Assert.That(obj["y", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading another object.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestObject2()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["object2"];
|
|
||||||
var obj = matFile["object2"].Value as IMatObject;
|
|
||||||
Assert.IsNotNull(obj);
|
|
||||||
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
|
||||||
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
|
||||||
Assert.That(obj["x", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
|
||||||
Assert.That(obj["y", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
|
||||||
Assert.That(obj["x", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
|
||||||
Assert.That(obj["y", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
|
||||||
Assert.That(obj["x", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
|
||||||
Assert.That(obj["y", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
|
||||||
Assert.That(obj["x", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
|
||||||
Assert.That(obj["y", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
|
||||||
Assert.That(obj[0, 1]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
|
||||||
Assert.That(obj[2]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a table.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestTable()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["table"];
|
|
||||||
var obj = matFile["table_"].Value as IMatObject;
|
|
||||||
var table = new TableAdapter(obj);
|
|
||||||
Assert.That(table.NumberOfRows, Is.EqualTo(3));
|
|
||||||
Assert.That(table.NumberOfVariables, Is.EqualTo(2));
|
|
||||||
Assert.That(table.Description, Is.EqualTo("Some table"));
|
|
||||||
Assert.That(table.VariableNames, Is.EqualTo(new[] { "variable1", "variable2" }));
|
|
||||||
var variable1 = table["variable1"] as ICellArray;
|
|
||||||
Assert.That((variable1[0] as ICharArray).String, Is.EqualTo("First row"));
|
|
||||||
Assert.That((variable1[1] as ICharArray).String, Is.EqualTo("Second row"));
|
|
||||||
Assert.That((variable1[2] as ICharArray).String, Is.EqualTo("Third row"));
|
|
||||||
var variable2 = table["variable2"];
|
|
||||||
Assert.That(variable2.ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0, 3.0, 5.0, 2.0, 4.0, 6.0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test subobjects within objects.
|
/// Test subobjects within objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSubobjects()
|
public void TestSubobjects()
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["pointWithSubpoints"];
|
var matFile = ReadLevel5TestFile("pointWithSubpoints");
|
||||||
var p = matFile["p"].Value as IMatObject;
|
var p = matFile["p"].Value as IMatObject;
|
||||||
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
||||||
var x = p["x"] as IMatObject;
|
var x = p["x"] as IMatObject;
|
||||||
@ -372,105 +465,74 @@ namespace MatFileHandler.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test nested objects.
|
/// Test reading a table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNestedObjects()
|
public void TestTable()
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["subsubPoint"];
|
var matFile = ReadLevel5TestFile("table");
|
||||||
var p = matFile["p"].Value as IMatObject;
|
var obj = matFile["table_"].Value as IMatObject;
|
||||||
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
var table = new TableAdapter(obj);
|
||||||
Assert.That(p["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 1.0 }));
|
Assert.That(table.NumberOfRows, Is.EqualTo(3));
|
||||||
var pp = p["y"] as IMatObject;
|
Assert.That(table.NumberOfVariables, Is.EqualTo(2));
|
||||||
Assert.That(pp.ClassName == "Point");
|
Assert.That(table.Description, Is.EqualTo("Some table"));
|
||||||
Assert.That(pp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 10.0 }));
|
Assert.That(table.VariableNames, Is.EqualTo(new[] { "variable1", "variable2" }));
|
||||||
var ppp = pp["y"] as IMatObject;
|
var variable1 = table["variable1"] as ICellArray;
|
||||||
Assert.That(ppp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 100.0 }));
|
Assert.That((variable1[0] as ICharArray).String, Is.EqualTo("First row"));
|
||||||
Assert.That(ppp["y"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 200.0 }));
|
Assert.That((variable1[1] as ICharArray).String, Is.EqualTo("Second row"));
|
||||||
|
Assert.That((variable1[2] as ICharArray).String, Is.EqualTo("Third row"));
|
||||||
|
var variable2 = table["variable2"];
|
||||||
|
Assert.That(variable2.ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0, 3.0, 5.0, 2.0, 4.0, 6.0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test datetime objects.
|
/// Test reading a Unicode string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestDatetime()
|
[TestCase("level5/unicode")]
|
||||||
|
[TestCase("hdf/unicode")]
|
||||||
|
public void TestUnicode(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["datetime"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var d = matFile["d"].Value as IMatObject;
|
var arrayUnicode = matFile["s"].Value as ICharArray;
|
||||||
var datetime = new DatetimeAdapter(d);
|
Assert.That(arrayUnicode, Is.Not.Null);
|
||||||
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 2 }));
|
Assert.That(arrayUnicode.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
Assert.That(datetime[0], Is.EqualTo(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero)));
|
Assert.That(arrayUnicode.String, Is.EqualTo("必フ"));
|
||||||
Assert.That(datetime[1], Is.EqualTo(new DateTimeOffset(1987, 1, 2, 3, 4, 5, TimeSpan.Zero)));
|
Assert.That(arrayUnicode[0], Is.EqualTo('必'));
|
||||||
|
Assert.That(arrayUnicode[1], Is.EqualTo('フ'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Another test for datetime objects.
|
/// Test reading a wide Unicode string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestDatetime2()
|
[TestCase("level5/unicode-wide")]
|
||||||
|
[TestCase("hdf/unicode-wide")]
|
||||||
|
public void TestUnicodeWide(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["datetime2"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var d = matFile["d"].Value as IMatObject;
|
var arrayUnicodeWide = matFile["s"].Value as ICharArray;
|
||||||
var datetime = new DatetimeAdapter(d);
|
Assert.That(arrayUnicodeWide, Is.Not.Null);
|
||||||
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 1 }));
|
Assert.That(arrayUnicodeWide.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
var diff = new DateTimeOffset(2, 1, 1, 1, 1, 1, 235, TimeSpan.Zero);
|
Assert.That(arrayUnicodeWide.String, Is.EqualTo("🍆"));
|
||||||
Assert.That(datetime[0] - diff < TimeSpan.FromMilliseconds(1));
|
|
||||||
Assert.That(diff - datetime[0] < TimeSpan.FromMilliseconds(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test string objects.
|
/// Test reading a sparse complex array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
/// <param name="testCaseName">Test case name.</param>
|
||||||
public void TestString()
|
[TestCase("level5/sparse_complex")]
|
||||||
|
[TestCase("hdf/sparse_complex")]
|
||||||
|
public void TextSparseComplex(string testCaseName)
|
||||||
{
|
{
|
||||||
var matFile = GetTests("good")["string"];
|
var matFile = GetTestCase(testCaseName);
|
||||||
var s = matFile["s"].Value as IMatObject;
|
var array = matFile["sparse_complex"].Value;
|
||||||
var str = new StringAdapter(s);
|
var sparseArray = array as ISparseArrayOf<Complex>;
|
||||||
Assert.That(str.Dimensions, Is.EquivalentTo(new[] { 4, 1 }));
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
Assert.That(str[0], Is.EqualTo("abc"));
|
Assert.That(sparseArray[0, 0], Is.EqualTo(-1.5 + (2.5 * Complex.ImaginaryOne)));
|
||||||
Assert.That(str[1], Is.EqualTo("defgh"));
|
Assert.That(sparseArray[1, 0], Is.EqualTo(2 - (3 * Complex.ImaginaryOne)));
|
||||||
Assert.That(str[2], Is.EqualTo("абвгд"));
|
Assert.That(sparseArray[0, 1], Is.EqualTo(Complex.Zero));
|
||||||
Assert.That(str[3], Is.EqualTo("æøå"));
|
Assert.That(sparseArray[1, 1], Is.EqualTo(0.5 + (1.0 * Complex.ImaginaryOne)));
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test duration objects.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestDuration()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["duration"];
|
|
||||||
var d = matFile["d"].Value as IMatObject;
|
|
||||||
var duration = new DurationAdapter(d);
|
|
||||||
Assert.That(duration.Dimensions, Is.EquivalentTo(new[] { 1, 3 }));
|
|
||||||
Assert.That(duration[0], Is.EqualTo(TimeSpan.FromTicks(12345678L)));
|
|
||||||
Assert.That(duration[1], Is.EqualTo(new TimeSpan(0, 2, 4)));
|
|
||||||
Assert.That(duration[2], Is.EqualTo(new TimeSpan(1, 3, 5)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test unrepresentable datetime.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public void TestDatetime_Unrepresentable()
|
|
||||||
{
|
|
||||||
var matFile = GetTests("good")["datetime-unrepresentable"];
|
|
||||||
var obj = matFile["d"].Value as IMatObject;
|
|
||||||
var datetime = new DatetimeAdapter(obj);
|
|
||||||
var d0 = datetime[0];
|
|
||||||
Assert.That(d0, Is.Null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AbstractTestDataFactory<IMatFile> GetTests(string factoryName) =>
|
|
||||||
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
|
|
||||||
|
|
||||||
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
Assert.That(array, Is.Not.Null);
|
|
||||||
Assert.That(array.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
|
||||||
Assert.That(array.Data, Is.EqualTo(limits));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckComplexLimits<T>(IArrayOf<ComplexOf<T>> array, T[] limits)
|
private static void CheckComplexLimits<T>(IArrayOf<ComplexOf<T>> array, T[] limits)
|
||||||
@ -481,5 +543,27 @@ namespace MatFileHandler.Tests
|
|||||||
Assert.That(array[0], Is.EqualTo(new ComplexOf<T>(limits[0], limits[1])));
|
Assert.That(array[0], Is.EqualTo(new ComplexOf<T>(limits[0], limits[1])));
|
||||||
Assert.That(array[1], Is.EqualTo(new ComplexOf<T>(limits[1], limits[0])));
|
Assert.That(array[1], Is.EqualTo(new ComplexOf<T>(limits[1], limits[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
Assert.That(array, Is.Not.Null);
|
||||||
|
Assert.That(array.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
|
Assert.That(array.Data, Is.EqualTo(limits));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IMatFile GetTestCase(string testCaseName)
|
||||||
|
{
|
||||||
|
var parts = testCaseName.Split('/');
|
||||||
|
return GetTests(parts[0])[parts[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AbstractTestDataFactory<IMatFile> GetTests(string factoryName) =>
|
||||||
|
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
|
||||||
|
|
||||||
|
private IMatFile ReadLevel5TestFile(string testName)
|
||||||
|
{
|
||||||
|
return GetTests("level5")[testName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -27,7 +27,7 @@ namespace MatFileHandler.Tests
|
|||||||
array[1] = 17.0;
|
array[1] = 17.0;
|
||||||
var variable = builder.NewVariable("test", array);
|
var variable = builder.NewVariable("test", array);
|
||||||
var actual = builder.NewFile(new[] { variable });
|
var actual = builder.NewFile(new[] { variable });
|
||||||
MatCompareWithTestData("good", "double-array", actual);
|
MatCompareWithLevel5TestData("double-array", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -65,7 +65,7 @@ namespace MatFileHandler.Tests
|
|||||||
var int64 = builder.NewVariable("int64_", builder.NewArray(CommonData.Int64Limits, 1, 2));
|
var int64 = builder.NewVariable("int64_", builder.NewArray(CommonData.Int64Limits, 1, 2));
|
||||||
var uint64 = builder.NewVariable("uint64_", builder.NewArray(CommonData.UInt64Limits, 1, 2));
|
var uint64 = builder.NewVariable("uint64_", builder.NewArray(CommonData.UInt64Limits, 1, 2));
|
||||||
var actual = builder.NewFile(new[] { int16, int32, int64, int8, uint16, uint32, uint64, uint8 });
|
var actual = builder.NewFile(new[] { int16, int32, int64, int8, uint16, uint32, uint64, uint8 });
|
||||||
MatCompareWithTestData("good", "limits", actual);
|
MatCompareWithLevel5TestData("limits", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -104,7 +104,7 @@ namespace MatFileHandler.Tests
|
|||||||
int16Complex, int32Complex, int64Complex, int8Complex,
|
int16Complex, int32Complex, int64Complex, int8Complex,
|
||||||
uint16Complex, uint32Complex, uint64Complex, uint8Complex,
|
uint16Complex, uint32Complex, uint64Complex, uint8Complex,
|
||||||
});
|
});
|
||||||
MatCompareWithTestData("good", "limits_complex", actual);
|
MatCompareWithLevel5TestData("limits_complex", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -116,7 +116,7 @@ namespace MatFileHandler.Tests
|
|||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var s = builder.NewVariable("s", builder.NewCharArray("🍆"));
|
var s = builder.NewVariable("s", builder.NewCharArray("🍆"));
|
||||||
var actual = builder.NewFile(new[] { s });
|
var actual = builder.NewFile(new[] { s });
|
||||||
MatCompareWithTestData("good", "unicode-wide", actual);
|
MatCompareWithLevel5TestData("unicode-wide", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -133,7 +133,7 @@ namespace MatFileHandler.Tests
|
|||||||
sparseArray[2, 3] = 4;
|
sparseArray[2, 3] = 4;
|
||||||
var sparse = builder.NewVariable("sparse_", sparseArray);
|
var sparse = builder.NewVariable("sparse_", sparseArray);
|
||||||
var actual = builder.NewFile(new[] { sparse });
|
var actual = builder.NewFile(new[] { sparse });
|
||||||
MatCompareWithTestData("good", "sparse", actual);
|
MatCompareWithLevel5TestData("sparse", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -161,7 +161,7 @@ namespace MatFileHandler.Tests
|
|||||||
structure["y", 1, 2] = builder.NewEmpty();
|
structure["y", 1, 2] = builder.NewEmpty();
|
||||||
var struct_ = builder.NewVariable("struct_", structure);
|
var struct_ = builder.NewVariable("struct_", structure);
|
||||||
var actual = builder.NewFile(new[] { struct_ });
|
var actual = builder.NewFile(new[] { struct_ });
|
||||||
MatCompareWithTestData("good", "struct", actual);
|
MatCompareWithLevel5TestData("struct", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -174,7 +174,7 @@ namespace MatFileHandler.Tests
|
|||||||
var logical = builder.NewArray(new[] { true, false, true, true, false, true }, 2, 3);
|
var logical = builder.NewArray(new[] { true, false, true, true, false, true }, 2, 3);
|
||||||
var logicalVariable = builder.NewVariable("logical_", logical);
|
var logicalVariable = builder.NewVariable("logical_", logical);
|
||||||
var actual = builder.NewFile(new[] { logicalVariable });
|
var actual = builder.NewFile(new[] { logicalVariable });
|
||||||
MatCompareWithTestData("good", "logical", actual);
|
MatCompareWithLevel5TestData("logical", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -191,7 +191,7 @@ namespace MatFileHandler.Tests
|
|||||||
array[1, 2] = true;
|
array[1, 2] = true;
|
||||||
var sparseLogical = builder.NewVariable("sparse_logical", array);
|
var sparseLogical = builder.NewVariable("sparse_logical", array);
|
||||||
var actual = builder.NewFile(new[] { sparseLogical });
|
var actual = builder.NewFile(new[] { sparseLogical });
|
||||||
MatCompareWithTestData("good", "sparse_logical", actual);
|
MatCompareWithLevel5TestData("sparse_logical", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -207,7 +207,7 @@ namespace MatFileHandler.Tests
|
|||||||
array[1, 1] = 0.5 + Complex.ImaginaryOne;
|
array[1, 1] = 0.5 + Complex.ImaginaryOne;
|
||||||
var sparseComplex = builder.NewVariable("sparse_complex", array);
|
var sparseComplex = builder.NewVariable("sparse_complex", array);
|
||||||
var actual = builder.NewFile(new[] { sparseComplex });
|
var actual = builder.NewFile(new[] { sparseComplex });
|
||||||
MatCompareWithTestData("good", "sparse_complex", actual);
|
MatCompareWithLevel5TestData("sparse_complex", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -220,7 +220,7 @@ namespace MatFileHandler.Tests
|
|||||||
var array = builder.NewArray(new double[] { 1, 3, 5 }, 1, 3);
|
var array = builder.NewArray(new double[] { 1, 3, 5 }, 1, 3);
|
||||||
var global = builder.NewVariable("global_", array, true);
|
var global = builder.NewVariable("global_", array, true);
|
||||||
var actual = builder.NewFile(new[] { global });
|
var actual = builder.NewFile(new[] { global });
|
||||||
MatCompareWithTestData("good", "global", actual);
|
MatCompareWithLevel5TestData("global", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractTestDataFactory<IMatFile> GetMatTestData(string factoryName) =>
|
private static AbstractTestDataFactory<IMatFile> GetMatTestData(string factoryName) =>
|
||||||
@ -398,6 +398,11 @@ namespace MatFileHandler.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MatCompareWithLevel5TestData(string testName, IMatFile actual)
|
||||||
|
{
|
||||||
|
MatCompareWithTestData("level5", testName, actual);
|
||||||
|
}
|
||||||
|
|
||||||
private void MatCompareWithTestData(string factoryName, string testName, IMatFile actual)
|
private void MatCompareWithTestData(string factoryName, string testName, IMatFile actual)
|
||||||
{
|
{
|
||||||
var expected = GetMatTestData(factoryName)[testName];
|
var expected = GetMatTestData(factoryName)[testName];
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
BIN
MatFileHandler.Tests/test-data/hdf/ascii.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/ascii.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/global.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/global.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/limits.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/limits.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/limits_complex.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/limits_complex.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/logical.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/logical.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/matrix.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/matrix.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/matrix_complex.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/matrix_complex.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/sparse.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/sparse.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/sparse_complex.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/sparse_complex.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/sparse_logical.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/sparse_logical.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/struct.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/struct.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/unicode-wide.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/unicode-wide.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/hdf/unicode.mat
Normal file
BIN
MatFileHandler.Tests/test-data/hdf/unicode.mat
Normal file
Binary file not shown.
0
MatFileHandler.Tests/test-data/good/ascii.mat → MatFileHandler.Tests/test-data/level5/ascii.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/ascii.mat → MatFileHandler.Tests/test-data/level5/ascii.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/global.mat → MatFileHandler.Tests/test-data/level5/global.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/global.mat → MatFileHandler.Tests/test-data/level5/global.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/limits.mat → MatFileHandler.Tests/test-data/level5/limits.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/limits.mat → MatFileHandler.Tests/test-data/level5/limits.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/limits_complex.mat → MatFileHandler.Tests/test-data/level5/limits_complex.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/limits_complex.mat → MatFileHandler.Tests/test-data/level5/limits_complex.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/logical.mat → MatFileHandler.Tests/test-data/level5/logical.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/logical.mat → MatFileHandler.Tests/test-data/level5/logical.mat
Executable file → Normal file
BIN
MatFileHandler.Tests/test-data/level5/matrix.mat
Normal file
BIN
MatFileHandler.Tests/test-data/level5/matrix.mat
Normal file
Binary file not shown.
BIN
MatFileHandler.Tests/test-data/level5/matrix_complex.mat
Normal file
BIN
MatFileHandler.Tests/test-data/level5/matrix_complex.mat
Normal file
Binary file not shown.
0
MatFileHandler.Tests/test-data/good/sparse.mat → MatFileHandler.Tests/test-data/level5/sparse.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/sparse.mat → MatFileHandler.Tests/test-data/level5/sparse.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/sparse_complex.mat → MatFileHandler.Tests/test-data/level5/sparse_complex.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/sparse_complex.mat → MatFileHandler.Tests/test-data/level5/sparse_complex.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/sparse_logical.mat → MatFileHandler.Tests/test-data/level5/sparse_logical.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/sparse_logical.mat → MatFileHandler.Tests/test-data/level5/sparse_logical.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/struct.mat → MatFileHandler.Tests/test-data/level5/struct.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/struct.mat → MatFileHandler.Tests/test-data/level5/struct.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/unicode-wide.mat → MatFileHandler.Tests/test-data/level5/unicode-wide.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/unicode-wide.mat → MatFileHandler.Tests/test-data/level5/unicode-wide.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/unicode.mat → MatFileHandler.Tests/test-data/level5/unicode.mat
Executable file → Normal file
0
MatFileHandler.Tests/test-data/good/unicode.mat → MatFileHandler.Tests/test-data/level5/unicode.mat
Executable file → Normal file
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -138,20 +138,4 @@ namespace MatFileHandler
|
|||||||
Variable = variable;
|
Variable = variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sparse array properties.
|
|
||||||
/// </summary>
|
|
||||||
internal struct SparseArrayFlags
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Usual array properties.
|
|
||||||
/// </summary>
|
|
||||||
public ArrayFlags ArrayFlags;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maximal number of non-zero elements.
|
|
||||||
/// </summary>
|
|
||||||
public uint NzMax;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -28,9 +28,7 @@ namespace MatFileHandler
|
|||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
return new MatNumericalArrayOf<T>(
|
return new MatNumericalArrayOf<T>(
|
||||||
GetStandardFlags<T>(),
|
|
||||||
dimensions,
|
dimensions,
|
||||||
string.Empty,
|
|
||||||
new T[dimensions.NumberOfElements()]);
|
new T[dimensions.NumberOfElements()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Data size does not match the specified dimensions", "data");
|
throw new ArgumentException("Data size does not match the specified dimensions", "data");
|
||||||
}
|
}
|
||||||
return new MatNumericalArrayOf<T>(GetStandardFlags<T>(), dimensions, string.Empty, data);
|
return new MatNumericalArrayOf<T>(dimensions, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,7 +64,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
var flags = ConstructArrayFlags(ArrayType.MxCell);
|
var flags = ConstructArrayFlags(ArrayType.MxCell);
|
||||||
var elements = Enumerable.Repeat(MatArray.Empty() as IArray, dimensions.NumberOfElements()).ToList();
|
var elements = Enumerable.Repeat(MatArray.Empty() as IArray, dimensions.NumberOfElements()).ToList();
|
||||||
return new MatCellArray(flags, dimensions, string.Empty, elements);
|
return new MatCellArray(dimensions, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,7 +82,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
dictionary[field] = elements.ToList();
|
dictionary[field] = elements.ToList();
|
||||||
}
|
}
|
||||||
return new MatStructureArray(flags, dimensions, string.Empty, dictionary);
|
return new MatStructureArray(dimensions, dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -107,7 +105,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
var flags = ConstructArrayFlags(ArrayType.MxChar);
|
var flags = ConstructArrayFlags(ArrayType.MxChar);
|
||||||
var ushortArray = contents.ToCharArray().Select(c => (ushort)c).ToArray();
|
var ushortArray = contents.ToCharArray().Select(c => (ushort)c).ToArray();
|
||||||
return new MatCharArrayOf<ushort>(flags, dimensions, string.Empty, ushortArray, contents);
|
return new MatCharArrayOf<ushort>(dimensions, ushortArray, contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -129,9 +127,7 @@ namespace MatFileHandler
|
|||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
return new MatSparseArrayOf<T>(
|
return new MatSparseArrayOf<T>(
|
||||||
GetStandardSparseArrayFlags<T>(),
|
|
||||||
dimensions,
|
dimensions,
|
||||||
string.Empty,
|
|
||||||
new Dictionary<(int, int), T>());
|
new Dictionary<(int, int), T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,15 +251,5 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
return ConstructArrayFlags(ArrayType.MxObject);
|
return ConstructArrayFlags(ArrayType.MxObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SparseArrayFlags GetStandardSparseArrayFlags<T>()
|
|
||||||
{
|
|
||||||
var arrayFlags = GetStandardFlags<T>();
|
|
||||||
return new SparseArrayFlags
|
|
||||||
{
|
|
||||||
ArrayFlags = arrayFlags,
|
|
||||||
NzMax = 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -16,18 +16,14 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a complex sparse array.
|
/// Construct a complex sparse array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array flags.</param>
|
|
||||||
/// <param name="dimensions">Array dimensions.</param>
|
/// <param name="dimensions">Array dimensions.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="rowIndex">Row indices.</param>
|
/// <param name="rowIndex">Row indices.</param>
|
||||||
/// <param name="columnIndex">Denotes index ranges for each column.</param>
|
/// <param name="columnIndex">Denotes index ranges for each column.</param>
|
||||||
/// <param name="data">Real parts of the values.</param>
|
/// <param name="data">Real parts of the values.</param>
|
||||||
/// <param name="imaginaryData">Imaginary parts of the values.</param>
|
/// <param name="imaginaryData">Imaginary parts of the values.</param>
|
||||||
/// <returns>A constructed array.</returns>
|
/// <returns>A constructed array.</returns>
|
||||||
public static MatArray ConvertToMatSparseArrayOfComplex(
|
public static MatArray ConvertToMatSparseArrayOfComplex(
|
||||||
SparseArrayFlags flags,
|
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
int[] rowIndex,
|
int[] rowIndex,
|
||||||
int[] columnIndex,
|
int[] columnIndex,
|
||||||
DataElement data,
|
DataElement data,
|
||||||
@ -40,11 +36,11 @@ namespace MatFileHandler
|
|||||||
throw new HandlerException("Couldn't read sparse array.");
|
throw new HandlerException("Couldn't read sparse array.");
|
||||||
}
|
}
|
||||||
var dataDictionary =
|
var dataDictionary =
|
||||||
ConvertMatlabSparseToDictionary(
|
DataExtraction.ConvertMatlabSparseToDictionary(
|
||||||
rowIndex,
|
rowIndex,
|
||||||
columnIndex,
|
columnIndex,
|
||||||
j => new Complex(realParts[j], imaginaryParts[j]));
|
j => new Complex(realParts[j], imaginaryParts[j]));
|
||||||
return new MatSparseArrayOf<Complex>(flags, dimensions, name, dataDictionary);
|
return new MatSparseArrayOf<Complex>(dimensions, dataDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,15 +49,13 @@ namespace MatFileHandler
|
|||||||
/// <typeparam name="T">Element type (Double or Boolean).</typeparam>
|
/// <typeparam name="T">Element type (Double or Boolean).</typeparam>
|
||||||
/// <param name="flags">Array flags.</param>
|
/// <param name="flags">Array flags.</param>
|
||||||
/// <param name="dimensions">Array dimensions.</param>
|
/// <param name="dimensions">Array dimensions.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="rowIndex">Row indices.</param>
|
/// <param name="rowIndex">Row indices.</param>
|
||||||
/// <param name="columnIndex">Denotes index ranges for each column.</param>
|
/// <param name="columnIndex">Denotes index ranges for each column.</param>
|
||||||
/// <param name="data">The values.</param>
|
/// <param name="data">The values.</param>
|
||||||
/// <returns>A constructed array.</returns>
|
/// <returns>A constructed array.</returns>
|
||||||
public static MatArray ConvertToMatSparseArrayOf<T>(
|
public static MatArray ConvertToMatSparseArrayOf<T>(
|
||||||
SparseArrayFlags flags,
|
ArrayFlags flags,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
int[] rowIndex,
|
int[] rowIndex,
|
||||||
int[] columnIndex,
|
int[] columnIndex,
|
||||||
DataElement data)
|
DataElement data)
|
||||||
@ -76,14 +70,14 @@ namespace MatFileHandler
|
|||||||
throw new ArgumentException("Null data found.", "data");
|
throw new ArgumentException("Null data found.", "data");
|
||||||
}
|
}
|
||||||
var elements =
|
var elements =
|
||||||
ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical));
|
ConvertDataToSparseProperType<T>(data, flags.Variable.HasFlag(Variable.IsLogical));
|
||||||
if (elements == null)
|
if (elements == null)
|
||||||
{
|
{
|
||||||
throw new HandlerException("Couldn't read sparse array.");
|
throw new HandlerException("Couldn't read sparse array.");
|
||||||
}
|
}
|
||||||
var dataDictionary =
|
var dataDictionary =
|
||||||
ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
|
DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
|
||||||
return new MatSparseArrayOf<T>(flags, dimensions, name, dataDictionary);
|
return new MatSparseArrayOf<T>(dimensions, dataDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -92,7 +86,6 @@ namespace MatFileHandler
|
|||||||
/// <typeparam name="T">Element type.</typeparam>
|
/// <typeparam name="T">Element type.</typeparam>
|
||||||
/// <param name="flags">Array flags.</param>
|
/// <param name="flags">Array flags.</param>
|
||||||
/// <param name="dimensions">Array dimensions.</param>
|
/// <param name="dimensions">Array dimensions.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="realData">Real parts of the values.</param>
|
/// <param name="realData">Real parts of the values.</param>
|
||||||
/// <param name="imaginaryData">Imaginary parts of the values.</param>
|
/// <param name="imaginaryData">Imaginary parts of the values.</param>
|
||||||
/// <returns>A constructed array.</returns>
|
/// <returns>A constructed array.</returns>
|
||||||
@ -104,7 +97,6 @@ namespace MatFileHandler
|
|||||||
public static MatArray ConvertToMatNumericalArrayOf<T>(
|
public static MatArray ConvertToMatNumericalArrayOf<T>(
|
||||||
ArrayFlags flags,
|
ArrayFlags flags,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
DataElement realData,
|
DataElement realData,
|
||||||
DataElement imaginaryData)
|
DataElement imaginaryData)
|
||||||
where T : struct
|
where T : struct
|
||||||
@ -112,7 +104,7 @@ namespace MatFileHandler
|
|||||||
if (flags.Variable.HasFlag(Variable.IsLogical))
|
if (flags.Variable.HasFlag(Variable.IsLogical))
|
||||||
{
|
{
|
||||||
var data = DataExtraction.GetDataAsUInt8(realData).ToArrayLazily().Select(x => x != 0).ToArray();
|
var data = DataExtraction.GetDataAsUInt8(realData).ToArrayLazily().Select(x => x != 0).ToArray();
|
||||||
return new MatNumericalArrayOf<bool>(flags, dimensions, name, data);
|
return new MatNumericalArrayOf<bool>(dimensions, data);
|
||||||
}
|
}
|
||||||
switch (flags.Class)
|
switch (flags.Class)
|
||||||
{
|
{
|
||||||
@ -120,9 +112,9 @@ namespace MatFileHandler
|
|||||||
switch (realData)
|
switch (realData)
|
||||||
{
|
{
|
||||||
case MiNum<byte> dataByte:
|
case MiNum<byte> dataByte:
|
||||||
return ConvertToMatCharArray(flags, dimensions, name, dataByte);
|
return ConvertToMatCharArray(dimensions, dataByte);
|
||||||
case MiNum<ushort> dataUshort:
|
case MiNum<ushort> dataUshort:
|
||||||
return ConvertToMatCharArray(flags, dimensions, name, dataUshort);
|
return ConvertToMatCharArray(dimensions, dataUshort);
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported.");
|
throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported.");
|
||||||
}
|
}
|
||||||
@ -146,25 +138,23 @@ namespace MatFileHandler
|
|||||||
(dataArray as double[])
|
(dataArray as double[])
|
||||||
.Zip(dataArray2 as double[], (x, y) => new Complex(x, y))
|
.Zip(dataArray2 as double[], (x, y) => new Complex(x, y))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
return new MatNumericalArrayOf<Complex>(flags, dimensions, name, complexArray);
|
return new MatNumericalArrayOf<Complex>(dimensions, complexArray);
|
||||||
}
|
}
|
||||||
var complexDataArray = dataArray.Zip(dataArray2, (x, y) => new ComplexOf<T>(x, y)).ToArray();
|
var complexDataArray = dataArray.Zip(dataArray2, (x, y) => new ComplexOf<T>(x, y)).ToArray();
|
||||||
return new MatNumericalArrayOf<ComplexOf<T>>(flags, dimensions, name, complexDataArray);
|
return new MatNumericalArrayOf<ComplexOf<T>>(dimensions, complexDataArray);
|
||||||
}
|
}
|
||||||
return new MatNumericalArrayOf<T>(flags, dimensions, name, dataArray);
|
return new MatNumericalArrayOf<T>(dimensions, dataArray);
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MatCharArrayOf<byte> ConvertToMatCharArray(
|
private static MatCharArrayOf<byte> ConvertToMatCharArray(
|
||||||
ArrayFlags flags,
|
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
MiNum<byte> dataElement)
|
MiNum<byte> dataElement)
|
||||||
{
|
{
|
||||||
var data = dataElement?.Data;
|
var data = dataElement?.Data;
|
||||||
return new MatCharArrayOf<byte>(flags, dimensions, name, data, Encoding.UTF8.GetString(data));
|
return new MatCharArrayOf<byte>(dimensions, data, Encoding.UTF8.GetString(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T[] ConvertDataToProperType<T>(DataElement data, ArrayType arrayType)
|
private static T[] ConvertDataToProperType<T>(DataElement data, ArrayType arrayType)
|
||||||
@ -212,35 +202,14 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static MatCharArrayOf<ushort> ConvertToMatCharArray(
|
private static MatCharArrayOf<ushort> ConvertToMatCharArray(
|
||||||
ArrayFlags flags,
|
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
MiNum<ushort> dataElement)
|
MiNum<ushort> dataElement)
|
||||||
{
|
{
|
||||||
var data = dataElement?.Data;
|
var data = dataElement?.Data;
|
||||||
return new MatCharArrayOf<ushort>(
|
return new MatCharArrayOf<ushort>(
|
||||||
flags,
|
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
new string(data.Select(x => (char)x).ToArray()));
|
new string(data.Select(x => (char)x).ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<(int, int), T> ConvertMatlabSparseToDictionary<T>(
|
|
||||||
int[] rowIndex,
|
|
||||||
int[] columnIndex,
|
|
||||||
Func<int, T> get)
|
|
||||||
{
|
|
||||||
var result = new Dictionary<(int, int), T>();
|
|
||||||
for (var column = 0; column < columnIndex.Length - 1; column++)
|
|
||||||
{
|
|
||||||
for (var j = columnIndex[column]; j < columnIndex[column + 1]; j++)
|
|
||||||
{
|
|
||||||
var row = rowIndex[j];
|
|
||||||
result[(row, column)] = get(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -30,54 +30,10 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reader">Input reader.</param>
|
/// <param name="reader">Input reader.</param>
|
||||||
/// <returns>Data element.</returns>
|
/// <returns>Data element.</returns>
|
||||||
public DataElement Read(BinaryReader reader)
|
public DataElementWithMetadata Read(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var (dataReader, tag) = ReadTag(reader);
|
var (dataReader, tag) = ReadTag(reader);
|
||||||
DataElement result;
|
DataElementWithMetadata result = ReadElementWithFlags(tag, dataReader);
|
||||||
switch (tag.Type)
|
|
||||||
{
|
|
||||||
case DataType.MiInt8:
|
|
||||||
result = ReadNum<sbyte>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiUInt8:
|
|
||||||
case DataType.MiUtf8:
|
|
||||||
result = ReadNum<byte>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiInt16:
|
|
||||||
result = ReadNum<short>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiUInt16:
|
|
||||||
case DataType.MiUtf16:
|
|
||||||
result = ReadNum<ushort>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiInt32:
|
|
||||||
result = ReadNum<int>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiUInt32:
|
|
||||||
result = ReadNum<uint>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiSingle:
|
|
||||||
result = ReadNum<float>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiDouble:
|
|
||||||
result = ReadNum<double>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiInt64:
|
|
||||||
result = ReadNum<long>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiUInt64:
|
|
||||||
result = ReadNum<ulong>(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiMatrix:
|
|
||||||
result = ReadMatrix(tag, dataReader);
|
|
||||||
break;
|
|
||||||
case DataType.MiCompressed:
|
|
||||||
result = ReadCompressed(tag, dataReader);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException("Unknown element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag.Type != DataType.MiCompressed)
|
if (tag.Type != DataType.MiCompressed)
|
||||||
{
|
{
|
||||||
var position = reader.BaseStream.Position;
|
var position = reader.BaseStream.Position;
|
||||||
@ -181,17 +137,13 @@ namespace MatFileHandler
|
|||||||
return new MiNum<T>(result);
|
return new MiNum<T>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SparseArrayFlags ReadSparseArrayFlags(DataElement element)
|
private static (ArrayFlags flags, uint nzMax) ReadSparseArrayFlags(DataElement element)
|
||||||
{
|
{
|
||||||
var arrayFlags = ReadArrayFlags(element);
|
var arrayFlags = ReadArrayFlags(element);
|
||||||
var flagData = (element as MiNum<uint>)?.Data ??
|
var flagData = (element as MiNum<uint>)?.Data ??
|
||||||
throw new HandlerException("Unexpected type in sparse array flags.");
|
throw new HandlerException("Unexpected type in sparse array flags.");
|
||||||
var nzMax = flagData[1];
|
var nzMax = flagData[1];
|
||||||
return new SparseArrayFlags
|
return (arrayFlags, nzMax);
|
||||||
{
|
|
||||||
ArrayFlags = arrayFlags,
|
|
||||||
NzMax = nzMax,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (BinaryReader, Tag) ReadTag(BinaryReader reader)
|
private static (BinaryReader, Tag) ReadTag(BinaryReader reader)
|
||||||
@ -214,99 +166,114 @@ 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>();
|
||||||
for (var i = 0; i < numberOfElements; i++)
|
for (var i = 0; i < numberOfElements; i++)
|
||||||
{
|
{
|
||||||
var element = Read(reader) as IArray;
|
var element = Read(reader).Element as IArray;
|
||||||
elements.Add(element);
|
elements.Add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatCellArray(flags, dimensions, name, elements);
|
return new MatCellArray(dimensions, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement ContinueReadingOpaque(BinaryReader reader)
|
private DataElementWithMetadata ContinueReadingOpaque(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var nameElement = Read(reader) 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.");
|
||||||
var name = ReadName(nameElement);
|
var name = ReadName(nameElement);
|
||||||
var anotherElement = Read(reader) as MiNum<sbyte> ??
|
var anotherElement = Read(reader).Element as MiNum<sbyte> ??
|
||||||
throw new HandlerException("Unexpected type in object type description.");
|
throw new HandlerException("Unexpected type in object type description.");
|
||||||
var typeDescription = ReadName(anotherElement);
|
var typeDescription = ReadName(anotherElement);
|
||||||
var classNameElement = Read(reader) as MiNum<sbyte> ??
|
var classNameElement = Read(reader).Element as MiNum<sbyte> ??
|
||||||
throw new HandlerException("Unexpected type in class name.");
|
throw new HandlerException("Unexpected type in class name.");
|
||||||
var className = ReadName(classNameElement);
|
var className = ReadName(classNameElement);
|
||||||
var dataElement = Read(reader);
|
var dataElement = Read(reader).Element;
|
||||||
var data = ReadData(dataElement);
|
var data = ReadData(dataElement);
|
||||||
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 OpaqueLink(
|
return new DataElementWithMetadata(
|
||||||
name,
|
new OpaqueLink(
|
||||||
typeDescription,
|
typeDescription,
|
||||||
className,
|
className,
|
||||||
dimensions,
|
dimensions,
|
||||||
data,
|
data,
|
||||||
indexToObjectId,
|
indexToObjectId,
|
||||||
classIndex,
|
classIndex,
|
||||||
subsystemData);
|
subsystemData),
|
||||||
|
default,
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Opaque(name, typeDescription, className, new int[] { }, data);
|
return new DataElementWithMetadata(
|
||||||
|
new Opaque(
|
||||||
|
typeDescription,
|
||||||
|
className,
|
||||||
|
new int[] { },
|
||||||
|
data),
|
||||||
|
default,
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement ContinueReadingSparseArray(
|
private DataElementWithMetadata ContinueReadingSparseArray(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
DataElement firstElement,
|
DataElement firstElement,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name)
|
string name)
|
||||||
{
|
{
|
||||||
var sparseArrayFlags = ReadSparseArrayFlags(firstElement);
|
var (arrayFlags, nzMax) = ReadSparseArrayFlags(firstElement);
|
||||||
var rowIndex = Read(reader) as MiNum<int> ??
|
var rowIndex = Read(reader).Element as MiNum<int> ??
|
||||||
throw new HandlerException("Unexpected type in row indices of a sparse array.");
|
throw new HandlerException("Unexpected type in row indices of a sparse array.");
|
||||||
var columnIndex = Read(reader) as MiNum<int> ??
|
var columnIndex = Read(reader).Element as MiNum<int> ??
|
||||||
throw new HandlerException("Unexpected type in column indices of a sparse array.");
|
throw new HandlerException("Unexpected type in column indices of a sparse array.");
|
||||||
var data = Read(reader);
|
var data = Read(reader).Element;
|
||||||
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsLogical))
|
if (arrayFlags.Variable.HasFlag(Variable.IsLogical))
|
||||||
{
|
{
|
||||||
return DataElementConverter.ConvertToMatSparseArrayOf<bool>(
|
return new DataElementWithMetadata(
|
||||||
sparseArrayFlags,
|
DataElementConverter.ConvertToMatSparseArrayOf<bool>(
|
||||||
|
arrayFlags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
rowIndex.Data,
|
rowIndex.Data,
|
||||||
columnIndex.Data,
|
columnIndex.Data,
|
||||||
data);
|
data),
|
||||||
|
arrayFlags,
|
||||||
|
name,
|
||||||
|
nzMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsComplex))
|
if (arrayFlags.Variable.HasFlag(Variable.IsComplex))
|
||||||
{
|
{
|
||||||
var imaginaryData = Read(reader);
|
var imaginaryData = Read(reader).Element;
|
||||||
return DataElementConverter.ConvertToMatSparseArrayOfComplex(
|
return new DataElementWithMetadata(
|
||||||
sparseArrayFlags,
|
DataElementConverter.ConvertToMatSparseArrayOfComplex(
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
rowIndex.Data,
|
rowIndex.Data,
|
||||||
columnIndex.Data,
|
columnIndex.Data,
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
arrayFlags,
|
||||||
|
name,
|
||||||
|
nzMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data)
|
switch (data)
|
||||||
{
|
{
|
||||||
case MiNum<double> _:
|
case MiNum<double> _:
|
||||||
return DataElementConverter.ConvertToMatSparseArrayOf<double>(
|
return new DataElementWithMetadata(
|
||||||
sparseArrayFlags,
|
DataElementConverter.ConvertToMatSparseArrayOf<double>(
|
||||||
|
arrayFlags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
rowIndex.Data,
|
rowIndex.Data,
|
||||||
columnIndex.Data,
|
columnIndex.Data,
|
||||||
data);
|
data),
|
||||||
|
arrayFlags,
|
||||||
|
name,
|
||||||
|
nzMax);
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException("Only double and logical sparse arrays are supported.");
|
throw new NotSupportedException("Only double and logical sparse arrays are supported.");
|
||||||
}
|
}
|
||||||
@ -314,12 +281,10 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
private DataElement ContinueReadingStructure(
|
private DataElement ContinueReadingStructure(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
ArrayFlags flags,
|
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
string name,
|
|
||||||
int fieldNameLength)
|
int fieldNameLength)
|
||||||
{
|
{
|
||||||
var element = Read(reader);
|
var element = Read(reader).Element;
|
||||||
var fieldNames = ReadFieldNames(element as MiNum<sbyte>, fieldNameLength);
|
var fieldNames = ReadFieldNames(element as MiNum<sbyte>, fieldNameLength);
|
||||||
var fields = new Dictionary<string, List<IArray>>();
|
var fields = new Dictionary<string, List<IArray>>();
|
||||||
foreach (var fieldName in fieldNames)
|
foreach (var fieldName in fieldNames)
|
||||||
@ -332,15 +297,15 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
foreach (var fieldName in fieldNames)
|
foreach (var fieldName in fieldNames)
|
||||||
{
|
{
|
||||||
var field = Read(reader) as IArray;
|
var field = Read(reader).Element as IArray;
|
||||||
fields[fieldName].Add(field);
|
fields[fieldName].Add(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatStructureArray(flags, dimensions, name, fields);
|
return new MatStructureArray(dimensions, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement Read(Stream stream)
|
private DataElementWithMetadata Read(Stream stream)
|
||||||
{
|
{
|
||||||
using (var reader = new BinaryReader(stream))
|
using (var reader = new BinaryReader(stream))
|
||||||
{
|
{
|
||||||
@ -348,7 +313,7 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement 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];
|
||||||
@ -367,28 +332,76 @@ namespace MatFileHandler
|
|||||||
return Read(resultStream);
|
return Read(resultStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement 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 MatArray.Empty();
|
return new DataElementWithMetadata(MatArray.Empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
var element1 = Read(reader);
|
var element1 = Read(reader).Element;
|
||||||
var flags = ReadArrayFlags(element1);
|
var flags = ReadArrayFlags(element1);
|
||||||
if (flags.Class == ArrayType.MxOpaque)
|
if (flags.Class == ArrayType.MxOpaque)
|
||||||
{
|
{
|
||||||
return ContinueReadingOpaque(reader);
|
return ContinueReadingOpaque(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
var element2 = Read(reader) as MiNum<int> ??
|
var element2 =
|
||||||
throw new HandlerException("Unexpected type in array dimensions data.");
|
Read(reader).Element as MiNum<int>
|
||||||
|
?? throw new HandlerException("Unexpected type in array dimensions data.");
|
||||||
var dimensions = ReadDimensionsArray(element2);
|
var dimensions = ReadDimensionsArray(element2);
|
||||||
var element3 = Read(reader) as MiNum<sbyte> ?? throw new HandlerException("Unexpected type in array name.");
|
var element3 =
|
||||||
|
Read(reader).Element as MiNum<sbyte>
|
||||||
|
?? throw new HandlerException("Unexpected type in array name.");
|
||||||
var name = ReadName(element3);
|
var name = ReadName(element3);
|
||||||
if (flags.Class == ArrayType.MxCell)
|
if (flags.Class == ArrayType.MxCell)
|
||||||
{
|
{
|
||||||
return ContinueReadingCellArray(reader, flags, dimensions, name);
|
return new DataElementWithMetadata(ContinueReadingCellArray(reader, dimensions));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.Class == ArrayType.MxSparse)
|
if (flags.Class == ArrayType.MxSparse)
|
||||||
@ -396,12 +409,12 @@ namespace MatFileHandler
|
|||||||
return ContinueReadingSparseArray(reader, element1, dimensions, name);
|
return ContinueReadingSparseArray(reader, element1, dimensions, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var element4 = Read(reader);
|
var element4 = Read(reader).Element;
|
||||||
var data = ReadData(element4);
|
var data = ReadData(element4);
|
||||||
DataElement imaginaryData = null;
|
DataElement imaginaryData = null;
|
||||||
if (flags.Variable.HasFlag(Variable.IsComplex))
|
if (flags.Variable.HasFlag(Variable.IsComplex))
|
||||||
{
|
{
|
||||||
var element5 = Read(reader);
|
var element5 = Read(reader).Element;
|
||||||
imaginaryData = ReadData(element5);
|
imaginaryData = ReadData(element5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +423,10 @@ 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 ContinueReadingStructure(reader, flags, dimensions, name, fieldNameLengthElement.Data[0]);
|
return new DataElementWithMetadata(
|
||||||
|
ContinueReadingStructure(reader, dimensions, fieldNameLengthElement.Data[0]),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (flags.Class)
|
switch (flags.Class)
|
||||||
@ -419,103 +435,129 @@ namespace MatFileHandler
|
|||||||
switch (data)
|
switch (data)
|
||||||
{
|
{
|
||||||
case MiNum<byte> _:
|
case MiNum<byte> _:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case MiNum<ushort> _:
|
case MiNum<ushort> _:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException(
|
throw new NotSupportedException(
|
||||||
$"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 DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxUInt8:
|
case ArrayType.MxUInt8:
|
||||||
if (flags.Variable.HasFlag(Variable.IsLogical))
|
if (flags.Variable.HasFlag(Variable.IsLogical))
|
||||||
{
|
{
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<bool>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<bool>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxInt16:
|
case ArrayType.MxInt16:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<short>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<short>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxUInt16:
|
case ArrayType.MxUInt16:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxInt32:
|
case ArrayType.MxInt32:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<int>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<int>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxUInt32:
|
case ArrayType.MxUInt32:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<uint>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<uint>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxInt64:
|
case ArrayType.MxInt64:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<long>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<long>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxUInt64:
|
case ArrayType.MxUInt64:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<ulong>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<ulong>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxSingle:
|
case ArrayType.MxSingle:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<float>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<float>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
case ArrayType.MxDouble:
|
case ArrayType.MxDouble:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<double>(
|
return new DataElementWithMetadata(
|
||||||
|
DataElementConverter.ConvertToMatNumericalArrayOf<double>(
|
||||||
flags,
|
flags,
|
||||||
dimensions,
|
dimensions,
|
||||||
name,
|
|
||||||
data,
|
data,
|
||||||
imaginaryData);
|
imaginaryData),
|
||||||
|
flags,
|
||||||
|
name);
|
||||||
default:
|
default:
|
||||||
throw new HandlerException("Unknown data type.");
|
throw new HandlerException("Unknown data type.");
|
||||||
}
|
}
|
||||||
|
54
MatFileHandler/DataElementWithMetadata.cs
Normal file
54
MatFileHandler/DataElementWithMetadata.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2017-2019 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; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -362,5 +362,30 @@ namespace MatFileHandler
|
|||||||
throw new HandlerException(
|
throw new HandlerException(
|
||||||
$"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>(
|
||||||
|
int[] rowIndex,
|
||||||
|
int[] columnIndex,
|
||||||
|
Func<int, T> get)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<(int, int), T>();
|
||||||
|
for (var column = 0; column < columnIndex.Length - 1; column++)
|
||||||
|
{
|
||||||
|
for (var j = columnIndex[column]; j < columnIndex[column + 1]; j++)
|
||||||
|
{
|
||||||
|
var row = rowIndex[j];
|
||||||
|
result[(row, column)] = get(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
81
MatFileHandler/Hdf/Attribute.cs
Normal file
81
MatFileHandler/Hdf/Attribute.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper for HDF attribute.
|
||||||
|
/// </summary>
|
||||||
|
internal struct Attribute : IDisposable
|
||||||
|
{
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
Id = H5A.open_by_name(locationId, ".", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets attribute id.
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Id != -1)
|
||||||
|
{
|
||||||
|
H5A.close(Id);
|
||||||
|
Id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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()
|
||||||
|
{
|
||||||
|
using (var h = new MemoryHandle(sizeof(int)))
|
||||||
|
{
|
||||||
|
H5A.read(Id, H5T.NATIVE_INT, h.Handle);
|
||||||
|
var result = Marshal.ReadInt32(h.Handle);
|
||||||
|
return result != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
H5A.read(Id, type.Id, handle.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
MatFileHandler/Hdf/Class.cs
Normal file
71
MatFileHandler/Hdf/Class.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HDF class.
|
||||||
|
/// </summary>
|
||||||
|
internal struct Class : IEquatable<Class>
|
||||||
|
{
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
this.classT = classT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Class one, Class other)
|
||||||
|
{
|
||||||
|
return one.Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Class one, Class 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)
|
||||||
|
{
|
||||||
|
return classT == other.classT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Class other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (int)classT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
MatFileHandler/Hdf/Dataset.cs
Normal file
104
MatFileHandler/Hdf/Dataset.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HDF dataset.
|
||||||
|
/// </summary>
|
||||||
|
internal struct Dataset : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Dataset"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="datasetId">Dataset id.</param>
|
||||||
|
public Dataset(long 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)
|
||||||
|
{
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
if (Id != -1)
|
||||||
|
{
|
||||||
|
H5D.close(Id);
|
||||||
|
Id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open attribute with given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Attribute name.</param>
|
||||||
|
/// <returns>Attribute.</returns>
|
||||||
|
public Attribute GetAttribute(string name)
|
||||||
|
{
|
||||||
|
return new Attribute(Id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get HDF space of the dataset.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>HDF space.</returns>
|
||||||
|
public Space GetHdfSpace()
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
H5D.read(Id, type.Id, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
MatFileHandler/Hdf/Group.cs
Normal file
58
MatFileHandler/Hdf/Group.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hdf group.
|
||||||
|
/// </summary>
|
||||||
|
internal struct Group : IDisposable
|
||||||
|
{
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
if (Id != -1)
|
||||||
|
{
|
||||||
|
H5G.close(Id);
|
||||||
|
Id = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get group attribute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Attribute name.</param>
|
||||||
|
/// <returns>Attribute.</returns>
|
||||||
|
public Attribute GetAttribute(string name)
|
||||||
|
{
|
||||||
|
return new Attribute(Id, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
MatFileHandler/Hdf/MatlabClass.cs
Normal file
80
MatFileHandler/Hdf/MatlabClass.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Matlab classes as they appear in HDF files.
|
||||||
|
/// </summary>
|
||||||
|
internal enum MatlabClass
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Empty array.
|
||||||
|
/// </summary>
|
||||||
|
MEmpty,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Char array.
|
||||||
|
/// </summary>
|
||||||
|
MChar,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int8 array.
|
||||||
|
/// </summary>
|
||||||
|
MInt8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UInt8 array.
|
||||||
|
/// </summary>
|
||||||
|
MUInt8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int16 array.
|
||||||
|
/// </summary>
|
||||||
|
MInt16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UInt16 array.
|
||||||
|
/// </summary>
|
||||||
|
MUInt16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int32 array.
|
||||||
|
/// </summary>
|
||||||
|
MInt32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UInt32 array.
|
||||||
|
/// </summary>
|
||||||
|
MUInt32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Int64 array.
|
||||||
|
/// </summary>
|
||||||
|
MInt64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UInt64 array.
|
||||||
|
/// </summary>
|
||||||
|
MUInt64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Single-precision floating point array.
|
||||||
|
/// </summary>
|
||||||
|
MSingle,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Double-precision floating point array.
|
||||||
|
/// </summary>
|
||||||
|
MDouble,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cell array.
|
||||||
|
/// </summary>
|
||||||
|
MCell,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logical array.
|
||||||
|
/// </summary>
|
||||||
|
MLogical,
|
||||||
|
}
|
||||||
|
}
|
37
MatFileHandler/Hdf/MemoryHandle.cs
Normal file
37
MatFileHandler/Hdf/MemoryHandle.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper around IntPtr to array in unmanaged memory.
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Handle = Marshal.AllocHGlobal(sizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets wrapped IntPtr.
|
||||||
|
/// </summary>
|
||||||
|
internal IntPtr Handle { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Handle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(Handle);
|
||||||
|
Handle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
MatFileHandler/Hdf/ReferenceArray.cs
Normal file
85
MatFileHandler/Hdf/ReferenceArray.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Array of HDF references stored in an HDF dataset.
|
||||||
|
/// </summary>
|
||||||
|
internal struct ReferenceArray : IDisposable, IEnumerable<Dataset>
|
||||||
|
{
|
||||||
|
private readonly Dataset[] references;
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
Dataset = dataset;
|
||||||
|
Size = size;
|
||||||
|
Buf = new MemoryHandle(Marshal.SizeOf(default(IntPtr)) * size);
|
||||||
|
Dataset.ReadToHandle(Type.Reference, Buf);
|
||||||
|
references = new Dataset[size];
|
||||||
|
for (var i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
references[i] =
|
||||||
|
new Dataset(H5R.dereference(
|
||||||
|
dataset.Id,
|
||||||
|
H5P.DEFAULT,
|
||||||
|
H5R.type_t.OBJECT,
|
||||||
|
Buf.Handle + (i * Marshal.SizeOf(default(IntPtr)))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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()
|
||||||
|
{
|
||||||
|
Buf?.Dispose();
|
||||||
|
if (References is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var reference in References)
|
||||||
|
{
|
||||||
|
reference.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerator<Dataset> GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<Dataset>)References).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return References.GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
MatFileHandler/Hdf/Space.cs
Normal file
48
MatFileHandler/Hdf/Space.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HDF space.
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets space id.
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get space rank.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Space rank.</returns>
|
||||||
|
public int GetRank()
|
||||||
|
{
|
||||||
|
return H5S.get_simple_extent_ndims(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get dimensions of the space.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Space dimensions.</returns>
|
||||||
|
public int[] GetDimensions()
|
||||||
|
{
|
||||||
|
var dims = new ulong[GetRank()];
|
||||||
|
H5S.get_simple_extent_dims(Id, dims, null);
|
||||||
|
System.Array.Reverse(dims);
|
||||||
|
return dims.Select(x => (int)x).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
MatFileHandler/Hdf/Type.cs
Normal file
147
MatFileHandler/Hdf/Type.cs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Hdf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HDF type.
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
|
||||||
|
/// <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()
|
||||||
|
{
|
||||||
|
return new Class(H5T.get_class(Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get size of the type.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Size of the type.</returns>
|
||||||
|
public int GetSize()
|
||||||
|
{
|
||||||
|
return (int)H5T.get_size(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert a field into the type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Field name.</param>
|
||||||
|
/// <param name="fieldType">Field type.</param>
|
||||||
|
public void InsertField(string name, Type fieldType)
|
||||||
|
{
|
||||||
|
H5T.insert(Id, name, IntPtr.Zero, fieldType.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
var classId = H5T.copy(Id);
|
||||||
|
H5T.set_size(classId, (IntPtr)size);
|
||||||
|
return new Type(classId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
667
MatFileHandler/HdfFileReader.cs
Normal file
667
MatFileHandler/HdfFileReader.cs
Normal file
@ -0,0 +1,667 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
using MatFileHandler.Hdf;
|
||||||
|
|
||||||
|
namespace MatFileHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reader of HDF files containing MATLAB data.
|
||||||
|
/// </summary>
|
||||||
|
internal class HdfFileReader
|
||||||
|
{
|
||||||
|
private const string ClassAttributeName = "MATLAB_class";
|
||||||
|
|
||||||
|
private const string GlobalAttributeName = "MATLAB_global";
|
||||||
|
|
||||||
|
private const string SparseAttributeName = "MATLAB_sparse";
|
||||||
|
|
||||||
|
private readonly long fileId;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
this.fileId = fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read MATLAB data from the HDF file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>MATLAB data file contents.</returns>
|
||||||
|
internal IMatFile Read()
|
||||||
|
{
|
||||||
|
variables = new List<IVariable>();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
H5L.iterate(
|
||||||
|
fileId,
|
||||||
|
H5.index_t.NAME,
|
||||||
|
H5.iter_order_t.NATIVE,
|
||||||
|
ref idx,
|
||||||
|
VariableIterator,
|
||||||
|
IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MatFile(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MatlabClass ArrayTypeFromMatlabClassName(string matlabClassName)
|
||||||
|
{
|
||||||
|
switch (matlabClassName)
|
||||||
|
{
|
||||||
|
case "canonical empty":
|
||||||
|
return MatlabClass.MEmpty;
|
||||||
|
case "logical":
|
||||||
|
return MatlabClass.MLogical;
|
||||||
|
case "char":
|
||||||
|
return MatlabClass.MChar;
|
||||||
|
case "int8":
|
||||||
|
return MatlabClass.MInt8;
|
||||||
|
case "uint8":
|
||||||
|
return MatlabClass.MUInt8;
|
||||||
|
case "int16":
|
||||||
|
return MatlabClass.MInt16;
|
||||||
|
case "uint16":
|
||||||
|
return MatlabClass.MUInt16;
|
||||||
|
case "int32":
|
||||||
|
return MatlabClass.MInt32;
|
||||||
|
case "uint32":
|
||||||
|
return MatlabClass.MUInt32;
|
||||||
|
case "int64":
|
||||||
|
return MatlabClass.MInt64;
|
||||||
|
case "uint64":
|
||||||
|
return MatlabClass.MUInt64;
|
||||||
|
case "single":
|
||||||
|
return MatlabClass.MSingle;
|
||||||
|
case "double":
|
||||||
|
return MatlabClass.MDouble;
|
||||||
|
case "cell":
|
||||||
|
return MatlabClass.MCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T[] ConvertDataToProperType<T>(byte[] bytes, MatlabClass arrayType)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
var length = bytes.Length;
|
||||||
|
var arrayElementSize = SizeOfArrayElement(arrayType);
|
||||||
|
var data = new T[length / arrayElementSize];
|
||||||
|
Buffer.BlockCopy(bytes, 0, data, 0, length);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] GetDimensionsOfDataset(Dataset dataset)
|
||||||
|
{
|
||||||
|
return dataset.GetHdfSpace().GetDimensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMatlabClassFromAttribute(Hdf.Attribute attribute)
|
||||||
|
{
|
||||||
|
var type = attribute.GetHdfType();
|
||||||
|
var cl = type.GetClass();
|
||||||
|
if (cl != Class.String)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeIdSize = type.GetSize();
|
||||||
|
var copiedType = Hdf.Type.CS1.WithSize(type.GetSize());
|
||||||
|
var matlabClassNameBytes = new byte[typeIdSize];
|
||||||
|
using (var buf = new MemoryHandle(typeIdSize))
|
||||||
|
{
|
||||||
|
attribute.ReadToHandle(buf, copiedType);
|
||||||
|
Marshal.Copy(buf.Handle, matlabClassNameBytes, 0, typeIdSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
return GetMatlabClassFromAttribute(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMatlabClassOfGroup(Group group)
|
||||||
|
{
|
||||||
|
using (var attribute = group.GetAttribute(ClassAttributeName))
|
||||||
|
{
|
||||||
|
return GetMatlabClassFromAttribute(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Hdf.Type H5tTypeFromHdfMatlabClass(MatlabClass arrayType)
|
||||||
|
{
|
||||||
|
switch (arrayType)
|
||||||
|
{
|
||||||
|
case MatlabClass.MInt8:
|
||||||
|
return Hdf.Type.NativeInt8;
|
||||||
|
case MatlabClass.MUInt8:
|
||||||
|
case MatlabClass.MLogical:
|
||||||
|
return Hdf.Type.NativeUInt8;
|
||||||
|
case MatlabClass.MInt16:
|
||||||
|
return Hdf.Type.NativeInt16;
|
||||||
|
case MatlabClass.MUInt16:
|
||||||
|
return Hdf.Type.NativeUInt16;
|
||||||
|
case MatlabClass.MInt32:
|
||||||
|
return Hdf.Type.NativeInt32;
|
||||||
|
case MatlabClass.MUInt32:
|
||||||
|
return Hdf.Type.NativeUInt32;
|
||||||
|
case MatlabClass.MInt64:
|
||||||
|
return Hdf.Type.NativeInt64;
|
||||||
|
case MatlabClass.MUInt64:
|
||||||
|
return Hdf.Type.NativeUInt64;
|
||||||
|
case MatlabClass.MSingle:
|
||||||
|
return Hdf.Type.NativeFloat;
|
||||||
|
case MatlabClass.MDouble:
|
||||||
|
return Hdf.Type.NativeDouble;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadCellArray(Dataset dataset, int[] dims)
|
||||||
|
{
|
||||||
|
var numberOfElements = dims.NumberOfElements();
|
||||||
|
var elements = new IArray[numberOfElements];
|
||||||
|
using (var array = new ReferenceArray(dataset, numberOfElements))
|
||||||
|
{
|
||||||
|
var i = 0;
|
||||||
|
foreach (var reference in array)
|
||||||
|
{
|
||||||
|
elements[i++] = ReadDataset(reference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MatCellArray(dims, elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadCharArray(Dataset dataset, int[] dims)
|
||||||
|
{
|
||||||
|
var storageSize = dataset.GetStorageSize();
|
||||||
|
var data = ReadDataset(dataset, Hdf.Type.NativeUInt16, storageSize);
|
||||||
|
var uInt16Data = new ushort[data.Length / sizeof(ushort)];
|
||||||
|
Buffer.BlockCopy(data, 0, uInt16Data, 0, data.Length);
|
||||||
|
var str = Encoding.Unicode.GetString(data);
|
||||||
|
return new MatCharArrayOf<ushort>(dims, uInt16Data, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (T[] real, T[] imaginary) ReadComplexData<T>(
|
||||||
|
Dataset dataset,
|
||||||
|
int dataSize,
|
||||||
|
MatlabClass arrayType)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
var h5Type = H5tTypeFromHdfMatlabClass(arrayType);
|
||||||
|
var h5Size = h5Type.GetSize();
|
||||||
|
var h5tComplexReal = Hdf.Type.CreateCompound(h5Size);
|
||||||
|
h5tComplexReal.InsertField("real", h5Type);
|
||||||
|
var realData = ReadDataset(dataset, h5tComplexReal, dataSize);
|
||||||
|
var h5tComplexImaginary = Hdf.Type.CreateCompound(h5Size);
|
||||||
|
h5tComplexImaginary.InsertField("imag", h5Type);
|
||||||
|
var imaginaryData = ReadDataset(dataset, h5tComplexImaginary, dataSize);
|
||||||
|
var convertedRealData = ConvertDataToProperType<T>(realData, arrayType);
|
||||||
|
var convertedImaginaryData = ConvertDataToProperType<T>(imaginaryData, arrayType);
|
||||||
|
return (convertedRealData, convertedImaginaryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadDataset(Dataset dataset)
|
||||||
|
{
|
||||||
|
var dims = GetDimensionsOfDataset(dataset);
|
||||||
|
|
||||||
|
var matlabClass = GetMatlabClassOfDataset(dataset);
|
||||||
|
var arrayType = ArrayTypeFromMatlabClassName(matlabClass);
|
||||||
|
|
||||||
|
switch (arrayType)
|
||||||
|
{
|
||||||
|
case MatlabClass.MEmpty:
|
||||||
|
return MatArray.Empty();
|
||||||
|
case MatlabClass.MLogical:
|
||||||
|
return ReadNumericalArray<bool>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MChar:
|
||||||
|
return ReadCharArray(dataset, dims);
|
||||||
|
case MatlabClass.MInt8:
|
||||||
|
return ReadNumericalArray<sbyte>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MUInt8:
|
||||||
|
return ReadNumericalArray<byte>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MInt16:
|
||||||
|
return ReadNumericalArray<short>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MUInt16:
|
||||||
|
return ReadNumericalArray<ushort>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MInt32:
|
||||||
|
return ReadNumericalArray<int>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MUInt32:
|
||||||
|
return ReadNumericalArray<uint>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MInt64:
|
||||||
|
return ReadNumericalArray<long>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MUInt64:
|
||||||
|
return ReadNumericalArray<ulong>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MSingle:
|
||||||
|
return ReadNumericalArray<float>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MDouble:
|
||||||
|
return ReadNumericalArray<double>(dataset, dims, arrayType);
|
||||||
|
case MatlabClass.MCell:
|
||||||
|
return ReadCellArray(dataset, dims);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException($"Unknown array type: {arrayType}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] ReadDataset(Dataset dataset, Hdf.Type elementType, int dataSize)
|
||||||
|
{
|
||||||
|
var data = new byte[dataSize];
|
||||||
|
using (var dataBuffer = new MemoryHandle(dataSize))
|
||||||
|
{
|
||||||
|
dataset.ReadToHandle(elementType, dataBuffer);
|
||||||
|
Marshal.Copy(dataBuffer.Handle, data, 0, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] ReadFieldNames(long groupId)
|
||||||
|
{
|
||||||
|
// Try to read fields from MATLAB_fields.
|
||||||
|
using (var attr = new Hdf.Attribute(groupId, "MATLAB_fields"))
|
||||||
|
{
|
||||||
|
if (attr.Id == 0)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var dimensions = attr.GetSpace().GetDimensions();
|
||||||
|
var numberOfFields = dimensions.NumberOfElements();
|
||||||
|
|
||||||
|
var fieldType = attr.GetHdfType();
|
||||||
|
|
||||||
|
var fieldNamePointersSizeInBytes = numberOfFields * Marshal.SizeOf(default(H5T.hvl_t));
|
||||||
|
var fieldNamePointers = new IntPtr[numberOfFields * 2];
|
||||||
|
using (var fieldNamesBuf = new MemoryHandle(fieldNamePointersSizeInBytes))
|
||||||
|
{
|
||||||
|
attr.ReadToHandle(fieldNamesBuf, fieldType);
|
||||||
|
Marshal.Copy(fieldNamesBuf.Handle, fieldNamePointers, 0, numberOfFields * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 IArray ReadGroup(Group group)
|
||||||
|
{
|
||||||
|
var matlabClass = GetMatlabClassOfGroup(group);
|
||||||
|
if (matlabClass == "struct")
|
||||||
|
{
|
||||||
|
return ReadStruct(group.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group.AttributeExists(SparseAttributeName))
|
||||||
|
{
|
||||||
|
var arrayType = ArrayTypeFromMatlabClassName(matlabClass);
|
||||||
|
|
||||||
|
switch (arrayType)
|
||||||
|
{
|
||||||
|
case MatlabClass.MEmpty:
|
||||||
|
return MatArray.Empty();
|
||||||
|
case MatlabClass.MLogical:
|
||||||
|
return ReadSparseArray<bool>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MInt8:
|
||||||
|
return ReadSparseArray<sbyte>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MUInt8:
|
||||||
|
return ReadSparseArray<byte>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MInt16:
|
||||||
|
return ReadSparseArray<short>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MUInt16:
|
||||||
|
return ReadSparseArray<ushort>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MInt32:
|
||||||
|
return ReadSparseArray<int>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MUInt32:
|
||||||
|
return ReadSparseArray<uint>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MInt64:
|
||||||
|
return ReadSparseArray<long>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MUInt64:
|
||||||
|
return ReadSparseArray<ulong>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MSingle:
|
||||||
|
return ReadSparseArray<float>(group.Id, arrayType);
|
||||||
|
case MatlabClass.MDouble:
|
||||||
|
return ReadSparseArray<double>(group.Id, arrayType);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<ComplexOf<T>> CombineComplexOfData<T>(
|
||||||
|
IEnumerable<T> realData,
|
||||||
|
IEnumerable<T> imaginaryData)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return realData.Zip(
|
||||||
|
imaginaryData,
|
||||||
|
(x, y) => new ComplexOf<T>(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Complex> CombineComplexData(
|
||||||
|
IEnumerable<double> realData,
|
||||||
|
IEnumerable<double> imaginaryData)
|
||||||
|
{
|
||||||
|
return realData.Zip(
|
||||||
|
imaginaryData,
|
||||||
|
(x, y) => new Complex(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadNumericalArray<T>(Dataset dataset, int[] dims, MatlabClass arrayType)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
var numberOfElements = dims.NumberOfElements();
|
||||||
|
var dataSize = numberOfElements * SizeOfArrayElement(arrayType);
|
||||||
|
var dataSetType = dataset.GetHdfType();
|
||||||
|
var dataSetTypeClass = dataSetType.GetClass();
|
||||||
|
var isCompound = dataSetTypeClass == Class.Compound;
|
||||||
|
if (isCompound)
|
||||||
|
{
|
||||||
|
var (convertedRealData, convertedImaginaryData) = ReadComplexData<T>(dataset, dataSize, arrayType);
|
||||||
|
if (arrayType == MatlabClass.MDouble)
|
||||||
|
{
|
||||||
|
var complexData =
|
||||||
|
CombineComplexData(
|
||||||
|
convertedRealData as double[],
|
||||||
|
convertedImaginaryData as double[])
|
||||||
|
.ToArray();
|
||||||
|
return new MatNumericalArrayOf<Complex>(dims, complexData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var complexData =
|
||||||
|
CombineComplexOfData(
|
||||||
|
convertedRealData,
|
||||||
|
convertedImaginaryData)
|
||||||
|
.ToArray();
|
||||||
|
return new MatNumericalArrayOf<ComplexOf<T>>(dims, complexData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = ReadDataset(dataset, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
|
||||||
|
var convertedData = ConvertDataToProperType<T>(data, arrayType);
|
||||||
|
return new MatNumericalArrayOf<T>(dims, convertedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadSparseArray<T>(long groupId, MatlabClass arrayType)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
using (var sparseAttribute = new Hdf.Attribute(groupId, SparseAttributeName))
|
||||||
|
{
|
||||||
|
using (var numberOfRowsHandle = new MemoryHandle(sizeof(uint)))
|
||||||
|
{
|
||||||
|
sparseAttribute.ReadToHandle(numberOfRowsHandle, Hdf.Type.NativeUInt);
|
||||||
|
var numberOfRows = Marshal.ReadInt32(numberOfRowsHandle.Handle);
|
||||||
|
int[] rowIndex;
|
||||||
|
int[] columnIndex;
|
||||||
|
using (var irData = new Dataset(groupId, "ir"))
|
||||||
|
{
|
||||||
|
var ds = GetDimensionsOfDataset(irData);
|
||||||
|
var numberOfIr = ds.NumberOfElements();
|
||||||
|
var irBytes = ReadDataset(irData, Hdf.Type.NativeInt, numberOfIr * sizeof(int));
|
||||||
|
rowIndex = new int[numberOfIr];
|
||||||
|
Buffer.BlockCopy(irBytes, 0, rowIndex, 0, irBytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var jcData = new Dataset(groupId, "jc"))
|
||||||
|
{
|
||||||
|
var ds = GetDimensionsOfDataset(jcData);
|
||||||
|
var numberOfJc = ds.NumberOfElements();
|
||||||
|
var jcBytes = ReadDataset(jcData, Hdf.Type.NativeInt, numberOfJc * sizeof(int));
|
||||||
|
columnIndex = new int[numberOfJc];
|
||||||
|
Buffer.BlockCopy(jcBytes, 0, columnIndex, 0, jcBytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var data = new Dataset(groupId, "data"))
|
||||||
|
{
|
||||||
|
var ds = GetDimensionsOfDataset(data);
|
||||||
|
var dims = new int[2];
|
||||||
|
dims[0] = numberOfRows;
|
||||||
|
dims[1] = columnIndex.Length - 1;
|
||||||
|
var dataSize = ds.NumberOfElements() * SizeOfArrayElement(arrayType);
|
||||||
|
var storageSize = data.GetStorageSize();
|
||||||
|
var dataSetType = data.GetHdfType();
|
||||||
|
var dataSetTypeClass = dataSetType.GetClass();
|
||||||
|
var isCompound = dataSetTypeClass == Class.Compound;
|
||||||
|
if (isCompound)
|
||||||
|
{
|
||||||
|
var (convertedRealData, convertedImaginaryData) =
|
||||||
|
ReadComplexData<T>(data, dataSize, arrayType);
|
||||||
|
if (arrayType == MatlabClass.MDouble)
|
||||||
|
{
|
||||||
|
var complexData =
|
||||||
|
CombineComplexData(
|
||||||
|
convertedRealData as double[],
|
||||||
|
convertedImaginaryData as double[])
|
||||||
|
.ToArray();
|
||||||
|
var complexDataDictionary =
|
||||||
|
DataExtraction.ConvertMatlabSparseToDictionary(
|
||||||
|
rowIndex,
|
||||||
|
columnIndex,
|
||||||
|
j => complexData[j]);
|
||||||
|
return new MatSparseArrayOf<Complex>(dims, complexDataDictionary);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var complexData =
|
||||||
|
CombineComplexOfData<T>(
|
||||||
|
convertedRealData,
|
||||||
|
convertedImaginaryData)
|
||||||
|
.ToArray();
|
||||||
|
var complexDataDictionary =
|
||||||
|
DataExtraction.ConvertMatlabSparseToDictionary(
|
||||||
|
rowIndex,
|
||||||
|
columnIndex,
|
||||||
|
j => complexData[j]);
|
||||||
|
return new MatSparseArrayOf<ComplexOf<T>>(dims, complexDataDictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = ReadDataset(data, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
|
||||||
|
var elements = ConvertDataToProperType<T>(d, arrayType);
|
||||||
|
var dataDictionary =
|
||||||
|
DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
|
||||||
|
return new MatSparseArrayOf<T>(dims, dataDictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IArray ReadStruct(long groupId)
|
||||||
|
{
|
||||||
|
var fieldNames = ReadFieldNames(groupId);
|
||||||
|
var firstObjectType = GetObjectType(groupId, fieldNames[0]);
|
||||||
|
if (firstObjectType == H5O.type_t.DATASET)
|
||||||
|
{
|
||||||
|
using (var firstField = new Dataset(groupId, fieldNames[0]))
|
||||||
|
{
|
||||||
|
var firstFieldType = firstField.GetHdfType();
|
||||||
|
if (firstFieldType.GetClass() == Class.Reference)
|
||||||
|
{
|
||||||
|
if (firstField.AttributeExists(ClassAttributeName))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var dimensions = GetDimensionsOfDataset(firstField);
|
||||||
|
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:
|
||||||
|
using (var field = new Dataset(groupId, fieldName))
|
||||||
|
{
|
||||||
|
using (var array = new ReferenceArray(field, numberOfElements))
|
||||||
|
{
|
||||||
|
foreach (var reference in array)
|
||||||
|
{
|
||||||
|
var value = ReadDataset(reference);
|
||||||
|
dictionary[fieldName].Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MatStructureArray(dimensions, dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int SizeOfArrayElement(MatlabClass arrayType)
|
||||||
|
{
|
||||||
|
switch (arrayType)
|
||||||
|
{
|
||||||
|
case MatlabClass.MInt8:
|
||||||
|
case MatlabClass.MUInt8:
|
||||||
|
case MatlabClass.MLogical:
|
||||||
|
return 1;
|
||||||
|
case MatlabClass.MInt16:
|
||||||
|
case MatlabClass.MUInt16:
|
||||||
|
return 2;
|
||||||
|
case MatlabClass.MInt32:
|
||||||
|
case MatlabClass.MUInt32:
|
||||||
|
case MatlabClass.MSingle:
|
||||||
|
return 4;
|
||||||
|
case MatlabClass.MInt64:
|
||||||
|
case MatlabClass.MUInt64:
|
||||||
|
case MatlabClass.MDouble:
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadGlobalFlag(Group group)
|
||||||
|
{
|
||||||
|
if (!group.AttributeExists(GlobalAttributeName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var globalAttribute = group.GetAttribute(GlobalAttributeName))
|
||||||
|
{
|
||||||
|
return globalAttribute.ReadBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadGlobalFlag(Dataset dataset)
|
||||||
|
{
|
||||||
|
if (!dataset.AttributeExists(GlobalAttributeName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var globalAttribute = dataset.GetAttribute(GlobalAttributeName))
|
||||||
|
{
|
||||||
|
return globalAttribute.ReadBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int VariableIterator(long group, IntPtr name, ref H5L.info_t info, IntPtr op_data)
|
||||||
|
{
|
||||||
|
var variableName = Marshal.PtrToStringAnsi(name);
|
||||||
|
var object_info = default(H5O.info_t);
|
||||||
|
H5O.get_info_by_name(group, variableName, ref object_info);
|
||||||
|
switch (object_info.type)
|
||||||
|
{
|
||||||
|
case H5O.type_t.DATASET:
|
||||||
|
using (var dataset = new Dataset(group, variableName))
|
||||||
|
{
|
||||||
|
var isGlobal = ReadGlobalFlag(dataset);
|
||||||
|
var value = ReadDataset(dataset);
|
||||||
|
variables.Add(new MatVariable(value, variableName, isGlobal));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case H5O.type_t.GROUP:
|
||||||
|
if (variableName == "#refs#")
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var subGroup = new Group(group, variableName))
|
||||||
|
{
|
||||||
|
var isGlobal = ReadGlobalFlag(subGroup);
|
||||||
|
var groupValue = ReadGroup(subGroup);
|
||||||
|
variables.Add(new MatVariable(groupValue, variableName, isGlobal));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@ -13,13 +13,19 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Header
|
internal class Header
|
||||||
{
|
{
|
||||||
private Header(string text, long subsystemDataOffset, int version)
|
private Header(byte[] rawBytes, string text, long subsystemDataOffset, int version)
|
||||||
{
|
{
|
||||||
|
RawBytes = rawBytes;
|
||||||
Text = text;
|
Text = text;
|
||||||
SubsystemDataOffset = subsystemDataOffset;
|
SubsystemDataOffset = subsystemDataOffset;
|
||||||
Version = version;
|
Version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets raw byte contents of the header.
|
||||||
|
/// </summary>
|
||||||
|
public byte[] RawBytes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the header text.
|
/// Gets the header text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -55,7 +61,7 @@ namespace MatFileHandler
|
|||||||
platform = platform.Remove(length);
|
platform = platform.Remove(length);
|
||||||
}
|
}
|
||||||
var text = $"MATLAB 5.0 MAT-file, Platform: {platform}, Created on: {dateTime}{padding}";
|
var text = $"MATLAB 5.0 MAT-file, Platform: {platform}, Created on: {dateTime}{padding}";
|
||||||
return new Header(text, 0, 256);
|
return new Header(null, text, 0, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -65,18 +71,26 @@ namespace MatFileHandler
|
|||||||
/// <returns>The header read.</returns>
|
/// <returns>The header read.</returns>
|
||||||
public static Header Read(BinaryReader reader)
|
public static Header Read(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var textBytes = reader.ReadBytes(116);
|
var rawBytes = reader.ReadBytes(128);
|
||||||
|
using (var stream = new MemoryStream(rawBytes))
|
||||||
|
{
|
||||||
|
using (var newReader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
var textBytes = newReader.ReadBytes(116);
|
||||||
var text = System.Text.Encoding.UTF8.GetString(textBytes);
|
var text = System.Text.Encoding.UTF8.GetString(textBytes);
|
||||||
var subsystemDataOffsetBytes = reader.ReadBytes(8);
|
var subsystemDataOffsetBytes = newReader.ReadBytes(8);
|
||||||
var subsystemDataOffset = BitConverter.ToInt64(subsystemDataOffsetBytes, 0);
|
var subsystemDataOffset = BitConverter.ToInt64(subsystemDataOffsetBytes, 0);
|
||||||
var version = reader.ReadInt16();
|
var version = newReader.ReadInt16();
|
||||||
var endian = reader.ReadInt16();
|
var endian = newReader.ReadInt16();
|
||||||
var isLittleEndian = endian == 19785;
|
var isLittleEndian = endian == 19785;
|
||||||
if (!isLittleEndian)
|
if (!isLittleEndian)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Big-endian files are not supported.");
|
throw new NotSupportedException("Big-endian files are not supported.");
|
||||||
}
|
}
|
||||||
return new Header(text, subsystemDataOffset, version);
|
|
||||||
|
return new Header(rawBytes, text, subsystemDataOffset, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetOperatingSystem()
|
private static string GetOperatingSystem()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
@ -12,45 +12,28 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatArray"/> class.
|
/// Initializes a new instance of the <see cref="MatArray"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array properties.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
protected MatArray(int[] dimensions)
|
||||||
protected MatArray(
|
|
||||||
ArrayFlags flags,
|
|
||||||
int[] dimensions,
|
|
||||||
string name)
|
|
||||||
{
|
{
|
||||||
Flags = flags;
|
|
||||||
Dimensions = dimensions;
|
Dimensions = dimensions;
|
||||||
Name = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int[] Dimensions { get; }
|
public int[] Dimensions { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the array name.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Count => Dimensions.NumberOfElements();
|
public int Count => Dimensions.NumberOfElements();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsEmpty => Dimensions.Length == 0;
|
public bool IsEmpty => Dimensions.Length == 0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets properties of the array.
|
|
||||||
/// </summary>
|
|
||||||
internal ArrayFlags Flags { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a new empty array.
|
/// Returns a new empty array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Empty array.</returns>
|
/// <returns>Empty array.</returns>
|
||||||
public static MatArray Empty()
|
public static MatArray Empty()
|
||||||
{
|
{
|
||||||
return new MatArray(new ArrayFlags { Class = ArrayType.MxCell, Variable = 0 }, new int[] { }, string.Empty);
|
return new MatArray(new int[] { });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -13,12 +13,10 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatCellArray"/> class.
|
/// Initializes a new instance of the <see cref="MatCellArray"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array properties.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="elements">Array elements.</param>
|
/// <param name="elements">Array elements.</param>
|
||||||
public MatCellArray(ArrayFlags flags, int[] dimensions, string name, IEnumerable<IArray> elements)
|
public MatCellArray(int[] dimensions, IEnumerable<IArray> elements)
|
||||||
: base(flags, dimensions, name)
|
: base(dimensions)
|
||||||
{
|
{
|
||||||
Data = elements.ToArray();
|
Data = elements.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
@ -15,13 +15,11 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatCharArrayOf{T}"/> class.
|
/// Initializes a new instance of the <see cref="MatCharArrayOf{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array parameters.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="rawData">Raw data (UTF-8 or UTF-16).</param>
|
/// <param name="rawData">Raw data (UTF-8 or UTF-16).</param>
|
||||||
/// <param name="stringData">Contents as a string.</param>
|
/// <param name="stringData">Contents as a string.</param>
|
||||||
internal MatCharArrayOf(ArrayFlags flags, int[] dimensions, string name, T[] rawData, string stringData)
|
internal MatCharArrayOf(int[] dimensions, T[] rawData, string stringData)
|
||||||
: base(flags, dimensions, name, rawData)
|
: base(dimensions, rawData)
|
||||||
{
|
{
|
||||||
StringData = stringData;
|
StringData = stringData;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
||||||
@ -26,12 +27,13 @@
|
|||||||
<AdditionalFiles Include="..\stylecop.json" />
|
<AdditionalFiles Include="..\stylecop.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="HDF.PInvoke.NETStandard" Version="1.10.200" />
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
|
||||||
<PrivateAssets>All</PrivateAssets>
|
<PrivateAssets>All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.4.0" Condition="'$(TargetFramework)' == 'net461'" />
|
<PackageReference Include="System.ValueTuple" Version="4.4.0" Condition="'$(TargetFramework)' == 'net461'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE.md" Pack="true" PackagePath=""/>
|
<None Include="..\LICENSE.md" Pack="true" PackagePath="" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
50
MatFileHandler/MatFileHdfReader.cs
Normal file
50
MatFileHandler/MatFileHdfReader.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using HDF.PInvoke;
|
||||||
|
|
||||||
|
namespace MatFileHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reader for MATLAB HDF (-v7.3) files.
|
||||||
|
/// </summary>
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var headerStream = new MemoryStream(header.RawBytes))
|
||||||
|
{
|
||||||
|
headerStream.CopyTo(memoryStream);
|
||||||
|
}
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
var bytes = memoryStream.ToArray();
|
||||||
|
return ReadFromByteArray(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IMatFile ReadFromByteArray(byte[] bytes)
|
||||||
|
{
|
||||||
|
var fileAccessPropertyList = H5P.create(H5P.FILE_ACCESS);
|
||||||
|
H5P.set_fapl_core(fileAccessPropertyList, IntPtr.Add(IntPtr.Zero, 1024), 0);
|
||||||
|
var ptr = Marshal.AllocCoTaskMem(bytes.Length);
|
||||||
|
Marshal.Copy(bytes, 0, ptr, bytes.Length);
|
||||||
|
H5P.set_file_image(fileAccessPropertyList, ptr, IntPtr.Add(IntPtr.Zero, bytes.Length));
|
||||||
|
var fileId = H5F.open(Guid.NewGuid().ToString(), H5F.ACC_RDONLY, fileAccessPropertyList);
|
||||||
|
var hdfFileReader = new HdfFileReader(fileId);
|
||||||
|
var result = hdfFileReader.Read();
|
||||||
|
H5F.close(fileId);
|
||||||
|
H5F.clear_elink_file_cache(fileId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
MatFileHandler/MatFileLevel5Reader.cs
Normal file
97
MatFileHandler/MatFileLevel5Reader.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MatFileHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reader for MATLAB "Level 5" .mat files.
|
||||||
|
/// </summary>
|
||||||
|
internal static class MatFileLevel5Reader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read a sequence of raw variables from .mat file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">Reader.</param>
|
||||||
|
/// <param name="subsystemDataOffset">Offset of subsystem data in the file;
|
||||||
|
/// we need it because we may encounter it during reading, and
|
||||||
|
/// the subsystem data should be parsed in a special way.</param>
|
||||||
|
/// <param name="subsystemData">
|
||||||
|
/// Link to the current file's subsystem data structure; initially it has dummy value
|
||||||
|
/// which will be replaced after we parse the whole subsystem data.</param>
|
||||||
|
/// <returns>List of "raw" variables; the actual variables are constructed from them later.</returns>
|
||||||
|
internal static List<RawVariable> ReadRawVariables(BinaryReader reader, long subsystemDataOffset, SubsystemData subsystemData)
|
||||||
|
{
|
||||||
|
var variables = new List<RawVariable>();
|
||||||
|
var dataElementReader = new DataElementReader(subsystemData);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var position = reader.BaseStream.Position;
|
||||||
|
var dataElement = dataElementReader.Read(reader);
|
||||||
|
if (position == subsystemDataOffset)
|
||||||
|
{
|
||||||
|
var subsystemDataElement = dataElement.Element as IArrayOf<byte>;
|
||||||
|
var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData);
|
||||||
|
subsystemData.Set(newSubsystemData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variables.Add(new RawVariable(position, dataElement.Element, dataElement.Flags, dataElement.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (EndOfStreamException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read raw variables from a .mat file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">Binary reader.</param>
|
||||||
|
/// <param name="subsystemDataOffset">Offset to the subsystem data to use (read from the file header).</param>
|
||||||
|
/// <returns>Raw variables read.</returns>
|
||||||
|
internal static List<RawVariable> ReadRawVariables(BinaryReader reader, long subsystemDataOffset)
|
||||||
|
{
|
||||||
|
var subsystemData = new 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)
|
||||||
|
{
|
||||||
|
var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset);
|
||||||
|
var variables = new List<IVariable>();
|
||||||
|
foreach (var rawVariable in rawVariables)
|
||||||
|
{
|
||||||
|
if (!(rawVariable.DataElement is MatArray array))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
variables.Add(new MatVariable(
|
||||||
|
array,
|
||||||
|
rawVariable.Name,
|
||||||
|
rawVariable.Flags.Variable.HasFlag(Variable.IsGlobal)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MatFile(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SubsystemData ReadSubsystemData(byte[] bytes, SubsystemData subsystemData)
|
||||||
|
{
|
||||||
|
return SubsystemDataReader.Read(bytes, subsystemData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
@ -34,89 +33,23 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read a sequence of raw variables from .mat file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader">Reader.</param>
|
|
||||||
/// <param name="subsystemDataOffset">Offset of subsystem data in the file;
|
|
||||||
/// we need it because we may encounter it during reading, and
|
|
||||||
/// the subsystem data should be parsed in a special way.</param>
|
|
||||||
/// <param name="subsystemData">
|
|
||||||
/// Link to the current file's subsystem data structure; initially it has dummy value
|
|
||||||
/// which will be replaced after we parse the whole subsystem data.</param>
|
|
||||||
/// <returns>List of "raw" variables; the actual variables are constructed from them later.</returns>
|
|
||||||
internal static List<RawVariable> ReadRawVariables(BinaryReader reader, long subsystemDataOffset, SubsystemData subsystemData)
|
|
||||||
{
|
|
||||||
var variables = new List<RawVariable>();
|
|
||||||
var dataElementReader = new DataElementReader(subsystemData);
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var position = reader.BaseStream.Position;
|
|
||||||
var dataElement = dataElementReader.Read(reader);
|
|
||||||
if (position == subsystemDataOffset)
|
|
||||||
{
|
|
||||||
var subsystemDataElement = dataElement as IArrayOf<byte>;
|
|
||||||
var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData);
|
|
||||||
subsystemData.Set(newSubsystemData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
variables.Add(new RawVariable(position, dataElement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (EndOfStreamException)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Read raw variables from a .mat file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reader">Binary reader.</param>
|
|
||||||
/// <param name="subsystemDataOffset">Offset to the subsystem data to use (read from the file header).</param>
|
|
||||||
/// <returns>Raw variables read.</returns>
|
|
||||||
internal static List<RawVariable> ReadRawVariables(BinaryReader reader, long subsystemDataOffset)
|
|
||||||
{
|
|
||||||
var subsystemData = new SubsystemData();
|
|
||||||
return ReadRawVariables(reader, subsystemDataOffset, subsystemData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IMatFile Read(BinaryReader reader)
|
|
||||||
{
|
|
||||||
var header = ReadHeader(reader);
|
|
||||||
var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset);
|
|
||||||
var variables = new List<IVariable>();
|
|
||||||
foreach (var variable in rawVariables)
|
|
||||||
{
|
|
||||||
var array = variable.DataElement as MatArray;
|
|
||||||
if (array is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
variables.Add(new MatVariable(
|
|
||||||
array,
|
|
||||||
array.Name,
|
|
||||||
array.Flags.Variable.HasFlag(Variable.IsGlobal)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MatFile(variables);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Header ReadHeader(BinaryReader reader)
|
private static Header ReadHeader(BinaryReader reader)
|
||||||
{
|
{
|
||||||
return Header.Read(reader);
|
return Header.Read(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SubsystemData ReadSubsystemData(byte[] bytes, SubsystemData subsystemData)
|
private IMatFile Read(BinaryReader reader)
|
||||||
{
|
{
|
||||||
return SubsystemDataReader.Read(bytes, subsystemData);
|
var header = ReadHeader(reader);
|
||||||
|
switch (header.Version)
|
||||||
|
{
|
||||||
|
case 256:
|
||||||
|
return MatFileLevel5Reader.ContinueReadingLevel5File(header, reader);
|
||||||
|
case 512:
|
||||||
|
return MatFileHdfReader.ContinueReadingHdfFile(header, reader.BaseStream);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unknown file format.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -226,14 +226,14 @@ namespace MatFileHandler
|
|||||||
writer.Write(new byte[] { 0, 0, 0, 0, 0, 0 });
|
writer.Write(new byte[] { 0, 0, 0, 0, 0, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags)
|
private void WriteSparseArrayFlags(BinaryWriter writer, ArrayFlags flags, uint nzMax)
|
||||||
{
|
{
|
||||||
var flag = (byte)flags.ArrayFlags.Variable;
|
var flag = (byte)flags.Variable;
|
||||||
WriteTag(writer, new Tag(DataType.MiUInt32, 8));
|
WriteTag(writer, new Tag(DataType.MiUInt32, 8));
|
||||||
writer.Write((byte)flags.ArrayFlags.Class);
|
writer.Write((byte)flags.Class);
|
||||||
writer.Write(flag);
|
writer.Write(flag);
|
||||||
writer.Write(new byte[] { 0, 0 });
|
writer.Write(new byte[] { 0, 0 });
|
||||||
writer.Write(flags.NzMax);
|
writer.Write(nzMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteName(BinaryWriter writer, string name)
|
private void WriteName(BinaryWriter writer, string name)
|
||||||
@ -373,19 +373,16 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SparseArrayFlags GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero)
|
private (ArrayFlags flags, uint nzMax) GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
var flags = GetArrayFlags(array, isGlobal);
|
var flags = GetArrayFlags(array, isGlobal);
|
||||||
return new SparseArrayFlags
|
return (new ArrayFlags
|
||||||
{
|
|
||||||
ArrayFlags = new ArrayFlags
|
|
||||||
{
|
{
|
||||||
Class = ArrayType.MxSparse,
|
Class = ArrayType.MxSparse,
|
||||||
Variable = flags.Variable,
|
Variable = flags.Variable,
|
||||||
},
|
},
|
||||||
NzMax = nonZero,
|
nonZero);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayFlags GetCharArrayFlags(bool isGlobal)
|
private ArrayFlags GetCharArrayFlags(bool isGlobal)
|
||||||
@ -513,7 +510,8 @@ namespace MatFileHandler
|
|||||||
where T : struct, IEquatable<T>
|
where T : struct, IEquatable<T>
|
||||||
{
|
{
|
||||||
(var rows, var columns, var data, var nonZero) = PrepareSparseArrayData(array);
|
(var rows, var columns, var data, var nonZero) = PrepareSparseArrayData(array);
|
||||||
WriteSparseArrayFlags(writer, GetSparseArrayFlags(array, isGlobal, nonZero));
|
var (flags, nzMax) = GetSparseArrayFlags(array, isGlobal, nonZero);
|
||||||
|
WriteSparseArrayFlags(writer, flags, nzMax);
|
||||||
WriteDimensions(writer, array.Dimensions);
|
WriteDimensions(writer, array.Dimensions);
|
||||||
WriteName(writer, name);
|
WriteName(writer, name);
|
||||||
WriteSparseArrayValues(writer, rows, columns, data);
|
WriteSparseArrayValues(writer, rows, columns, data);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -17,12 +17,10 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatNumericalArrayOf{T}"/> class.
|
/// Initializes a new instance of the <see cref="MatNumericalArrayOf{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array parameters.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="data">Array contents.</param>
|
/// <param name="data">Array contents.</param>
|
||||||
public MatNumericalArrayOf(ArrayFlags flags, int[] dimensions, string name, T[] data)
|
public MatNumericalArrayOf(int[] dimensions, T[] data)
|
||||||
: base(flags, dimensions, name)
|
: base(dimensions)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -18,16 +18,10 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatSparseArrayOf{T}"/> class.
|
/// Initializes a new instance of the <see cref="MatSparseArrayOf{T}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array properties.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="data">Array contents.</param>
|
/// <param name="data">Array contents.</param>
|
||||||
public MatSparseArrayOf(
|
public MatSparseArrayOf(int[] dimensions, Dictionary<(int, int), T> data)
|
||||||
SparseArrayFlags flags,
|
: base(dimensions)
|
||||||
int[] dimensions,
|
|
||||||
string name,
|
|
||||||
Dictionary<(int, int), T> data)
|
|
||||||
: base(flags.ArrayFlags, dimensions, name)
|
|
||||||
{
|
{
|
||||||
DataDictionary = data;
|
DataDictionary = data;
|
||||||
}
|
}
|
||||||
@ -49,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;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
@ -15,16 +15,10 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatStructureArray"/> class.
|
/// Initializes a new instance of the <see cref="MatStructureArray"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="flags">Array properties.</param>
|
|
||||||
/// <param name="dimensions">Dimensions of the array.</param>
|
/// <param name="dimensions">Dimensions of the array.</param>
|
||||||
/// <param name="name">Array name.</param>
|
|
||||||
/// <param name="fields">Array contents.</param>
|
/// <param name="fields">Array contents.</param>
|
||||||
public MatStructureArray(
|
public MatStructureArray(int[] dimensions, Dictionary<string, List<IArray>> fields)
|
||||||
ArrayFlags flags,
|
: base(dimensions)
|
||||||
int[] dimensions,
|
|
||||||
string name,
|
|
||||||
Dictionary<string, List<IArray>> fields)
|
|
||||||
: base(flags, dimensions, name)
|
|
||||||
{
|
{
|
||||||
Fields = fields;
|
Fields = fields;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@ -21,13 +21,12 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Opaque"/> class.
|
/// Initializes a new instance of the <see cref="Opaque"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">Name of the object.</param>
|
|
||||||
/// <param name="typeDescription">Type description.</param>
|
/// <param name="typeDescription">Type description.</param>
|
||||||
/// <param name="className">Class name.</param>
|
/// <param name="className">Class name.</param>
|
||||||
/// <param name="dimensions">Dimensions of the object.</param>
|
/// <param name="dimensions">Dimensions of the object.</param>
|
||||||
/// <param name="rawData">Raw object's data.</param>
|
/// <param name="rawData">Raw object's data.</param>
|
||||||
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData)
|
public Opaque(string typeDescription, string className, int[] dimensions, DataElement rawData)
|
||||||
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
|
: base(dimensions)
|
||||||
{
|
{
|
||||||
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
||||||
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
@ -17,7 +17,6 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">Name of the object.</param>
|
|
||||||
/// <param name="typeDescription">Description of object's class.</param>
|
/// <param name="typeDescription">Description of object's class.</param>
|
||||||
/// <param name="className">Name of the object's class.</param>
|
/// <param name="className">Name of the object's class.</param>
|
||||||
/// <param name="dimensions">Dimensions of the object.</param>
|
/// <param name="dimensions">Dimensions of the object.</param>
|
||||||
@ -26,7 +25,6 @@ namespace MatFileHandler
|
|||||||
/// <param name="classIndex">Index of object's class.</param>
|
/// <param name="classIndex">Index of object's class.</param>
|
||||||
/// <param name="subsystemData">Reference to global subsystem data.</param>
|
/// <param name="subsystemData">Reference to global subsystem data.</param>
|
||||||
public OpaqueLink(
|
public OpaqueLink(
|
||||||
string name,
|
|
||||||
string typeDescription,
|
string typeDescription,
|
||||||
string className,
|
string className,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
@ -34,7 +32,7 @@ namespace MatFileHandler
|
|||||||
int[] indexToObjectId,
|
int[] indexToObjectId,
|
||||||
int classIndex,
|
int classIndex,
|
||||||
SubsystemData subsystemData)
|
SubsystemData subsystemData)
|
||||||
: base(name, typeDescription, className, dimensions, data)
|
: base(typeDescription, className, dimensions, data)
|
||||||
{
|
{
|
||||||
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
||||||
ClassIndex = classIndex;
|
ClassIndex = classIndex;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2017-2018 Alexander Luzgarev
|
// Copyright 2017-2019 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@ -17,10 +17,14 @@ 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>
|
||||||
internal RawVariable(long offset, DataElement dataElement)
|
/// <param name="flags">Array flags.</param>
|
||||||
|
/// <param name="name">Variable name.</param>
|
||||||
|
internal RawVariable(long offset, DataElement dataElement, ArrayFlags flags, string name)
|
||||||
{
|
{
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
DataElement = dataElement ?? throw new ArgumentNullException(nameof(dataElement));
|
DataElement = dataElement ?? throw new ArgumentNullException(nameof(dataElement));
|
||||||
|
Flags = flags;
|
||||||
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,6 +32,16 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DataElement DataElement { get; }
|
public DataElement DataElement { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets array flags.
|
||||||
|
/// </summary>
|
||||||
|
public ArrayFlags Flags { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets variable name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets offset of the variable in the .mat file.
|
/// Gets offset of the variable in the .mat file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user