Compare commits
No commits in common. "master" and "issues/19-and-20" have entirely different histories.
master
...
issues/19-
248
.editorconfig
248
.editorconfig
@ -1,248 +0,0 @@
|
|||||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
|
||||||
root = true
|
|
||||||
|
|
||||||
# C# files
|
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
dotnet_analyzer_diagnostic.category-Design.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Documentation.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Globalization.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Interoperability.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Maintainability.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Naming.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Performance.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Reliability.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Security.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Style.severity = warning
|
|
||||||
dotnet_analyzer_diagnostic.category-Usage.severity = warning
|
|
||||||
|
|
||||||
dotnet_diagnostic.IDE0010.severity = none
|
|
||||||
dotnet_diagnostic.IDE0072.severity = none
|
|
||||||
dotnet_diagnostic.CA1707.severity = none
|
|
||||||
dotnet_diagnostic.CA1861.severity = none
|
|
||||||
|
|
||||||
#### Core EditorConfig Options ####
|
|
||||||
|
|
||||||
# Indentation and spacing
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
tab_width = 4
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
end_of_line = crlf
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|
||||||
#### .NET Coding Conventions ####
|
|
||||||
|
|
||||||
# Organize usings
|
|
||||||
dotnet_separate_import_directive_groups = false
|
|
||||||
dotnet_sort_system_directives_first = false
|
|
||||||
file_header_template = unset
|
|
||||||
|
|
||||||
# this. and Me. preferences
|
|
||||||
dotnet_style_qualification_for_event = false
|
|
||||||
dotnet_style_qualification_for_field = false
|
|
||||||
dotnet_style_qualification_for_method = false
|
|
||||||
dotnet_style_qualification_for_property = false
|
|
||||||
|
|
||||||
# Language keywords vs BCL types preferences
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
|
||||||
dotnet_style_predefined_type_for_member_access = true
|
|
||||||
|
|
||||||
# Parentheses preferences
|
|
||||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
|
||||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
|
||||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
|
||||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
dotnet_style_coalesce_expression = true
|
|
||||||
dotnet_style_collection_initializer = true
|
|
||||||
dotnet_style_explicit_tuple_names = true
|
|
||||||
dotnet_style_namespace_match_folder = true
|
|
||||||
dotnet_style_null_propagation = true
|
|
||||||
dotnet_style_object_initializer = true
|
|
||||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
|
||||||
dotnet_style_prefer_auto_properties = true
|
|
||||||
dotnet_style_prefer_collection_expression = false
|
|
||||||
dotnet_style_prefer_compound_assignment = true
|
|
||||||
dotnet_style_prefer_conditional_expression_over_assignment = false
|
|
||||||
dotnet_style_prefer_conditional_expression_over_return = false
|
|
||||||
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
|
||||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
|
||||||
dotnet_style_prefer_inferred_tuple_names = true
|
|
||||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
|
||||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
|
||||||
dotnet_style_prefer_simplified_interpolation = true
|
|
||||||
|
|
||||||
# Field preferences
|
|
||||||
dotnet_style_readonly_field = true
|
|
||||||
|
|
||||||
# Parameter preferences
|
|
||||||
dotnet_code_quality_unused_parameters = all:silent
|
|
||||||
|
|
||||||
# Suppression preferences
|
|
||||||
dotnet_remove_unnecessary_suppression_exclusions = none
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
dotnet_style_allow_multiple_blank_lines_experimental = true
|
|
||||||
dotnet_style_allow_statement_immediately_after_block_experimental = true
|
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
|
||||||
|
|
||||||
# var preferences
|
|
||||||
csharp_style_var_elsewhere = true
|
|
||||||
csharp_style_var_for_built_in_types = true
|
|
||||||
csharp_style_var_when_type_is_apparent = true
|
|
||||||
|
|
||||||
# Expression-bodied members
|
|
||||||
csharp_style_expression_bodied_accessors = true
|
|
||||||
csharp_style_expression_bodied_constructors = false
|
|
||||||
csharp_style_expression_bodied_indexers = true
|
|
||||||
csharp_style_expression_bodied_lambdas = true
|
|
||||||
csharp_style_expression_bodied_local_functions = false
|
|
||||||
csharp_style_expression_bodied_methods = true:none
|
|
||||||
csharp_style_expression_bodied_operators = false
|
|
||||||
csharp_style_expression_bodied_properties = true
|
|
||||||
|
|
||||||
# Pattern matching preferences
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
|
||||||
csharp_style_prefer_extended_property_pattern = true
|
|
||||||
csharp_style_prefer_not_pattern = true
|
|
||||||
csharp_style_prefer_pattern_matching = true
|
|
||||||
csharp_style_prefer_switch_expression = true
|
|
||||||
|
|
||||||
# Null-checking preferences
|
|
||||||
csharp_style_conditional_delegate_call = true
|
|
||||||
|
|
||||||
# Modifier preferences
|
|
||||||
csharp_prefer_static_local_function = true
|
|
||||||
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
|
||||||
csharp_style_prefer_readonly_struct = true
|
|
||||||
csharp_style_prefer_readonly_struct_member = true
|
|
||||||
|
|
||||||
# Code-block preferences
|
|
||||||
csharp_prefer_braces = true
|
|
||||||
csharp_prefer_simple_using_statement = true
|
|
||||||
csharp_style_namespace_declarations = file_scoped:none
|
|
||||||
csharp_style_prefer_method_group_conversion = true
|
|
||||||
csharp_style_prefer_primary_constructors = false
|
|
||||||
csharp_style_prefer_top_level_statements = true
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
csharp_prefer_simple_default_expression = true
|
|
||||||
csharp_style_deconstructed_variable_declaration = true
|
|
||||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
|
||||||
csharp_style_inlined_variable_declaration = true
|
|
||||||
csharp_style_prefer_index_operator = true
|
|
||||||
csharp_style_prefer_local_over_anonymous_function = true
|
|
||||||
csharp_style_prefer_null_check_over_type_check = true
|
|
||||||
csharp_style_prefer_range_operator = true
|
|
||||||
csharp_style_prefer_tuple_swap = true
|
|
||||||
csharp_style_prefer_utf8_string_literals = true
|
|
||||||
csharp_style_throw_expression = true
|
|
||||||
csharp_style_unused_value_assignment_preference = discard_variable
|
|
||||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
|
||||||
|
|
||||||
# 'using' directive preferences
|
|
||||||
csharp_using_directive_placement = outside_namespace
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
|
||||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
|
||||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
|
||||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
|
|
||||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
|
||||||
|
|
||||||
#### C# Formatting Rules ####
|
|
||||||
|
|
||||||
# New line preferences
|
|
||||||
csharp_new_line_before_catch = true
|
|
||||||
csharp_new_line_before_else = true
|
|
||||||
csharp_new_line_before_finally = true
|
|
||||||
csharp_new_line_before_members_in_anonymous_types = true
|
|
||||||
csharp_new_line_before_members_in_object_initializers = true
|
|
||||||
csharp_new_line_before_open_brace = all
|
|
||||||
csharp_new_line_between_query_expression_clauses = true
|
|
||||||
|
|
||||||
# Indentation preferences
|
|
||||||
csharp_indent_block_contents = true
|
|
||||||
csharp_indent_braces = false
|
|
||||||
csharp_indent_case_contents = true
|
|
||||||
csharp_indent_case_contents_when_block = true
|
|
||||||
csharp_indent_labels = one_less_than_current
|
|
||||||
csharp_indent_switch_labels = true
|
|
||||||
|
|
||||||
# Space preferences
|
|
||||||
csharp_space_after_cast = false
|
|
||||||
csharp_space_after_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_after_comma = true
|
|
||||||
csharp_space_after_dot = false
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
|
||||||
csharp_space_around_binary_operators = before_and_after
|
|
||||||
csharp_space_around_declaration_statements = false
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_before_comma = false
|
|
||||||
csharp_space_before_dot = false
|
|
||||||
csharp_space_before_open_square_brackets = false
|
|
||||||
csharp_space_before_semicolon_in_for_statement = false
|
|
||||||
csharp_space_between_empty_square_brackets = false
|
|
||||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
|
||||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
|
||||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_parentheses = false
|
|
||||||
csharp_space_between_square_brackets = false
|
|
||||||
|
|
||||||
# Wrapping preferences
|
|
||||||
csharp_preserve_single_line_blocks = true
|
|
||||||
csharp_preserve_single_line_statements = true
|
|
||||||
|
|
||||||
#### Naming styles ####
|
|
||||||
|
|
||||||
# Naming rules
|
|
||||||
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
|
||||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
|
||||||
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
|
||||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
|
||||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
|
||||||
|
|
||||||
# Symbol specifications
|
|
||||||
|
|
||||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
|
||||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.interface.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
|
||||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.types.required_modifiers =
|
|
||||||
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
|
||||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
|
||||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
|
||||||
|
|
||||||
# Naming styles
|
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case.required_prefix =
|
|
||||||
dotnet_naming_style.pascal_case.required_suffix =
|
|
||||||
dotnet_naming_style.pascal_case.word_separator =
|
|
||||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
|
||||||
|
|
||||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
|
||||||
dotnet_naming_style.begins_with_i.required_suffix =
|
|
||||||
dotnet_naming_style.begins_with_i.word_separator =
|
|
||||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
|
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright 2017-2025 Alexander Luzgarev
|
Copyright 2017-2020 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:
|
||||||
|
|
||||||
|
68
MatFileHandler.Tests/AbstractTestDataFactory.cs
Executable file
68
MatFileHandler.Tests/AbstractTestDataFactory.cs
Executable file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Abstract factory of test data.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TTestData">Type of test data.</typeparam>
|
||||||
|
public abstract class AbstractTestDataFactory<TTestData>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AbstractTestDataFactory{TTestData}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataDirectory">Directory with test files.</param>
|
||||||
|
/// <param name="testFilenameConvention">A convention used to filter test files.</param>
|
||||||
|
protected AbstractTestDataFactory(string dataDirectory, ITestFilenameConvention testFilenameConvention)
|
||||||
|
{
|
||||||
|
DataDirectory = dataDirectory;
|
||||||
|
TestFilenameConvention = testFilenameConvention;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DataDirectory { get; }
|
||||||
|
|
||||||
|
private ITestFilenameConvention TestFilenameConvention { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get test data set by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataSet">Name of the data set.</param>
|
||||||
|
/// <returns>Test data.</returns>
|
||||||
|
public TTestData this[string dataSet] =>
|
||||||
|
ReadTestData(FixPath(TestFilenameConvention.ConvertTestNameToFilename(dataSet)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a sequence of all test data sets in the factory.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A sequence of data sets.</returns>
|
||||||
|
public IEnumerable<TTestData> GetAllTestData()
|
||||||
|
{
|
||||||
|
var files = Directory.EnumerateFiles(DataDirectory).Where(TestFilenameConvention.FilterFile);
|
||||||
|
foreach (var filename in files)
|
||||||
|
{
|
||||||
|
yield return ReadTestData(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read test data from a stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">Input stream.</param>
|
||||||
|
/// <returns>Test data.</returns>
|
||||||
|
protected abstract TTestData ReadDataFromStream(Stream stream);
|
||||||
|
|
||||||
|
private string FixPath(string filename) => Path.Combine(DataDirectory, filename);
|
||||||
|
|
||||||
|
private TTestData ReadTestData(string filename)
|
||||||
|
{
|
||||||
|
using (var stream = new FileStream(filename, FileMode.Open))
|
||||||
|
{
|
||||||
|
return ReadDataFromStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,32 @@
|
|||||||
using System;
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Xunit;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests of Matlab array manipulation.
|
/// Tests of Matlab array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ArrayHandlingTests : IDisposable
|
[TestFixture]
|
||||||
|
public class ArrayHandlingTests
|
||||||
{
|
{
|
||||||
|
private DataBuilder Builder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setup for array handling tests.
|
/// Set up a DataBuilder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ArrayHandlingTests()
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
{
|
{
|
||||||
Builder = new DataBuilder();
|
Builder = new DataBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataBuilder Builder { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test numerical array creation.
|
/// Test numerical array creation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestCreate()
|
public void TestCreate()
|
||||||
{
|
{
|
||||||
TestCreateArrayOf<sbyte>();
|
TestCreateArrayOf<sbyte>();
|
||||||
@ -51,78 +54,70 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test numerical array manipulation.
|
/// Test numerical array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestNumArray()
|
public void TestNumArray()
|
||||||
{
|
{
|
||||||
var array = Builder.NewArray<int>(2, 3);
|
var array = Builder.NewArray<int>(2, 3);
|
||||||
array[0, 1] = 2;
|
array[0, 1] = 2;
|
||||||
Assert.Equal(2, array[0, 1]);
|
Assert.That(array[0, 1], Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test cell array manipulation.
|
/// Test cell array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestCellArray()
|
public void TestCellArray()
|
||||||
{
|
{
|
||||||
var array = Builder.NewCellArray(2, 3);
|
var array = Builder.NewCellArray(2, 3);
|
||||||
Assert.Equal(new[] { 2, 3 }, array.Dimensions);
|
Assert.That(array.Dimensions, Is.EqualTo(new[] { 2, 3 }));
|
||||||
array[0, 1] = Builder.NewArray<int>(1, 2);
|
array[0, 1] = Builder.NewArray<int>(1, 2);
|
||||||
Assert.True(array[1, 2].IsEmpty);
|
Assert.That(array[1, 2].IsEmpty, Is.True);
|
||||||
Assert.False(array[0, 1].IsEmpty);
|
Assert.That(array[0, 1].IsEmpty, Is.False);
|
||||||
var assigned = (IArrayOf<int>)array[0, 1];
|
var assigned = (IArrayOf<int>)array[0, 1];
|
||||||
Assert.NotNull(assigned);
|
Assert.That(assigned, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, assigned.Dimensions);
|
Assert.That(assigned.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test structure array manipulation.
|
/// Test structure array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestStructureArray()
|
public void TestStructureArray()
|
||||||
{
|
{
|
||||||
var array = Builder.NewStructureArray(new[] { "x", "y" }, 2, 3);
|
var array = Builder.NewStructureArray(new[] { "x", "y" }, 2, 3);
|
||||||
array["x", 0, 1] = Builder.NewArray<int>(1, 2);
|
array["x", 0, 1] = Builder.NewArray<int>(1, 2);
|
||||||
Assert.True(array["y", 0, 1].IsEmpty);
|
Assert.That(array["y", 0, 1].IsEmpty, Is.True);
|
||||||
Assert.False(array["x", 0, 1].IsEmpty);
|
Assert.That(array["x", 0, 1].IsEmpty, Is.False);
|
||||||
var assigned = (IArrayOf<int>)array["x", 0, 1];
|
var assigned = (IArrayOf<int>)array["x", 0, 1];
|
||||||
Assert.NotNull(assigned);
|
Assert.That(assigned, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, assigned.Dimensions);
|
Assert.That(assigned.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test character array manipulation.
|
/// Test character array manipulation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestString()
|
public void TestString()
|
||||||
{
|
{
|
||||||
var array = Builder.NewCharArray("🍆");
|
var array = Builder.NewCharArray("🍆");
|
||||||
Assert.Equal(new[] { 1, 2 }, array.Dimensions);
|
Assert.That(array.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test file creation.
|
/// Test file creation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestFile()
|
public void TestFile()
|
||||||
{
|
{
|
||||||
var file = Builder.NewFile(new List<IVariable>());
|
var file = Builder.NewFile(new List<IVariable>());
|
||||||
Assert.NotNull(file);
|
Assert.That(file, Is.Not.Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TestCreateArrayOf<T>()
|
private static void TestCreateArrayOf<T>()
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
var array = new DataBuilder().NewArray<T>(2, 3);
|
var array = new DataBuilder().NewArray<T>(2, 3);
|
||||||
Assert.NotNull(array);
|
Assert.That(array, Is.Not.Null);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cleanup.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,102 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Tests for the <see cref="ChecksumCalculatingStream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
public class ChecksumCalculatingStreamTests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Test writing various things.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bytes">Bytes to write.</param>
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(TestData))]
|
|
||||||
public void Test(byte[] bytes)
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
var sut = new ChecksumCalculatingStream(stream);
|
|
||||||
sut.Write(bytes, 0, bytes.Length);
|
|
||||||
var actual = sut.GetCrc();
|
|
||||||
|
|
||||||
var expected = ReferenceCalculation(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test data for <see cref="Test"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Test data.</returns>
|
|
||||||
public static TheoryData<byte[]> TestData()
|
|
||||||
{
|
|
||||||
var empty = new byte[1234];
|
|
||||||
var nonEmpty = new byte[12345];
|
|
||||||
for (var i = 0; i < 1234; i++)
|
|
||||||
{
|
|
||||||
nonEmpty[i] = (byte)((i * i) % 256);
|
|
||||||
}
|
|
||||||
return new TheoryData<byte[]>()
|
|
||||||
{
|
|
||||||
new byte[] { 0x00 },
|
|
||||||
new byte[] { 0x01 },
|
|
||||||
new byte[] { 0xff },
|
|
||||||
new byte[] { 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
|
||||||
new byte[] { 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, 0x17, 0x1d },
|
|
||||||
empty,
|
|
||||||
nonEmpty,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Action<Stream> BinaryWriterAction(Action<BinaryWriter> action)
|
|
||||||
{
|
|
||||||
return stream =>
|
|
||||||
{
|
|
||||||
using var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true);
|
|
||||||
action(writer);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint ReferenceCalculation(byte[] bytes)
|
|
||||||
{
|
|
||||||
using var stream = new MemoryStream();
|
|
||||||
stream.Write(bytes, 0, bytes.Length);
|
|
||||||
stream.Position = 0;
|
|
||||||
return CalculateAdler32Checksum(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint CalculateAdler32Checksum(MemoryStream stream)
|
|
||||||
{
|
|
||||||
uint s1 = 1;
|
|
||||||
uint s2 = 0;
|
|
||||||
const uint bigPrime = 0xFFF1;
|
|
||||||
const int bufferSize = 2048;
|
|
||||||
var buffer = new byte[bufferSize];
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var bytesRead = stream.Read(buffer, 0, bufferSize);
|
|
||||||
for (var i = 0; i < bytesRead; i++)
|
|
||||||
{
|
|
||||||
s1 = (s1 + buffer[i]) % bigPrime;
|
|
||||||
s2 = (s2 + s1) % bigPrime;
|
|
||||||
}
|
|
||||||
if (bytesRead < bufferSize)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (s2 << 16) | s1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,48 +1,51 @@
|
|||||||
using Xunit;
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests of the ComplexOf value type.
|
/// Tests of the ComplexOf value type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
public class ComplexOfTests
|
public class ComplexOfTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test getting real and imaginary parts.
|
/// Test getting real and imaginary parts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestAccessors()
|
public void TestAccessors()
|
||||||
{
|
{
|
||||||
var c = new ComplexOf<byte>(1, 2);
|
var c = new ComplexOf<byte>(1, 2);
|
||||||
Assert.Equal(1, c.Real);
|
Assert.That(c.Real, Is.EqualTo(1));
|
||||||
Assert.Equal(2, c.Imaginary);
|
Assert.That(c.Imaginary, Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test equality operators.
|
/// Test equality operators.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestEquals()
|
public void TestEquals()
|
||||||
{
|
{
|
||||||
var c1 = new ComplexOf<byte>(1, 2);
|
var c1 = new ComplexOf<byte>(1, 2);
|
||||||
var c2 = new ComplexOf<byte>(3, 4);
|
var c2 = new ComplexOf<byte>(3, 4);
|
||||||
var c3 = new ComplexOf<byte>(1, 2);
|
var c3 = new ComplexOf<byte>(1, 2);
|
||||||
Assert.True(c1 == c3);
|
Assert.That(c1 == c3, Is.True);
|
||||||
Assert.True(c1 != c2);
|
Assert.That(c1 != c2, Is.True);
|
||||||
Assert.True(c2 != c3);
|
Assert.That(c2 != c3, Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test hash code calculation.
|
/// Test hash code calculation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestGetHashCode()
|
public void TestGetHashCode()
|
||||||
{
|
{
|
||||||
var c1 = new ComplexOf<byte>(1, 2);
|
var c1 = new ComplexOf<byte>(1, 2);
|
||||||
var c2 = new ComplexOf<byte>(1, 2);
|
var c2 = new ComplexOf<byte>(1, 2);
|
||||||
var h1 = c1.GetHashCode();
|
var h1 = c1.GetHashCode();
|
||||||
var h2 = c2.GetHashCode();
|
var h2 = c2.GetHashCode();
|
||||||
Assert.Equal(h1, h2);
|
Assert.That(h1, Is.EqualTo(h2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
43
MatFileHandler.Tests/ExtensionTestFilenameConvention.cs
Executable file
43
MatFileHandler.Tests/ExtensionTestFilenameConvention.cs
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A filename convention based on file extensions.
|
||||||
|
/// </summary>
|
||||||
|
internal class ExtensionTestFilenameConvention : ITestFilenameConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ExtensionTestFilenameConvention"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="extension">File extension.</param>
|
||||||
|
public ExtensionTestFilenameConvention(string extension)
|
||||||
|
{
|
||||||
|
Extension = extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Extension { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert test name to filename by adding the extension.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testName">Test name.</param>
|
||||||
|
/// <returns>The corresponding filename.</returns>
|
||||||
|
public string ConvertTestNameToFilename(string testName)
|
||||||
|
{
|
||||||
|
return Path.ChangeExtension(testName, Extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compare file's extension to the one specified during initialization.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">Filename.</param>
|
||||||
|
/// <returns>True iff the file has the extension stored in the class.</returns>
|
||||||
|
public bool FilterFile(string filename)
|
||||||
|
{
|
||||||
|
return Path.GetExtension(filename) == "." + Extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
MatFileHandler.Tests/ITestFilenameConvention.cs
Executable file
24
MatFileHandler.Tests/ITestFilenameConvention.cs
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
namespace MatFileHandler.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for handling filtering tests based on filenames.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITestFilenameConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert test name to a filename (e.g., by adding an appropriate extension).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testName">Name of a test.</param>
|
||||||
|
/// <returns>Filename.</returns>
|
||||||
|
string ConvertTestNameToFilename(string testName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decide if a file contains a test based on the filename.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">A filename.</param>
|
||||||
|
/// <returns>True iff the file should contain a test.</returns>
|
||||||
|
bool FilterFile(string filename);
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,19 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;net472;net8.0</TargetFrameworks>
|
<TargetFrameworks>net5.0;net472</TargetFrameworks>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
||||||
<DocumentationFile>bin\Debug\net5.0\MatFileHandler.Tests.xml</DocumentationFile>
|
<DocumentationFile>bin\Debug\net5.0\MatFileHandler.Tests.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Include="..\stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||||
<PackageReference Include="xunit" Version="2.9.0" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Condition=" '$(TargetFramework)' != 'net461' " Include="xunit.runner.visualstudio" Version="2.8.2">
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Condition=" '$(TargetFramework)' == 'net461' " Include="xunit.runner.visualstudio" Version="2.4.3">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MatFileHandler\MatFileHandler.csproj" />
|
<ProjectReference Include="..\MatFileHandler\MatFileHandler.csproj" />
|
||||||
@ -25,4 +21,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="test-data\**\*.mat" CopyToOutputDirectory="PreserveNewest" />
|
<Content Include="test-data\**\*.mat" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||||
|
<PrivateAssets>All</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,15 +1,17 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Xunit;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests of file reading API.
|
/// Tests of file reading API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
public class MatFileReaderTests
|
public class MatFileReaderTests
|
||||||
{
|
{
|
||||||
private const string TestDirectory = "test-data";
|
private const string TestDirectory = "test-data";
|
||||||
@ -17,26 +19,27 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading all files in a given test set.
|
/// Test reading all files in a given test set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
/// <param name="testSet">Name of the set.</param>
|
||||||
public void TestReader(MatFileReadingMethod method)
|
[TestCase("good")]
|
||||||
|
public void TestReader(string testSet)
|
||||||
{
|
{
|
||||||
foreach (var matFile in ReadAllTestFiles(method))
|
foreach (var matFile in GetTests(testSet).GetAllTestData())
|
||||||
{
|
{
|
||||||
Assert.NotEmpty(matFile.Variables);
|
Assert.That(matFile.Variables, Is.Not.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading lower and upper limits of integer data types.
|
/// Test reading lower and upper limits of integer data types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestLimits(MatFileReadingMethod method)
|
public void TestLimits()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("limits", method);
|
var matFile = GetTests("good")["limits"];
|
||||||
IArray array;
|
IArray array;
|
||||||
array = matFile["int8_"].Value;
|
array = matFile["int8_"].Value;
|
||||||
CheckLimits(array as IArrayOf<sbyte>, CommonData.Int8Limits);
|
CheckLimits(array as IArrayOf<sbyte>, CommonData.Int8Limits);
|
||||||
Assert.Equal(new[] { -128.0, 127.0 }, array.ConvertToDoubleArray());
|
Assert.That(array.ConvertToDoubleArray(), Is.EqualTo(new[] { -128.0, 127.0 }));
|
||||||
|
|
||||||
array = matFile["uint8_"].Value;
|
array = matFile["uint8_"].Value;
|
||||||
CheckLimits(array as IArrayOf<byte>, CommonData.UInt8Limits);
|
CheckLimits(array as IArrayOf<byte>, CommonData.UInt8Limits);
|
||||||
@ -63,16 +66,16 @@ namespace MatFileHandler.Tests
|
|||||||
/// <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>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestComplexLimits(MatFileReadingMethod method)
|
public void TestComplexLimits()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("limits_complex", method);
|
var matFile = GetTests("good")["limits_complex"];
|
||||||
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);
|
||||||
Assert.Equal(
|
Assert.That(
|
||||||
new[] { -128.0 + (127.0 * Complex.ImaginaryOne), 127.0 - (128.0 * Complex.ImaginaryOne) },
|
array.ConvertToComplexArray(),
|
||||||
array.ConvertToComplexArray());
|
Is.EqualTo(new[] { -128.0 + (127.0 * Complex.ImaginaryOne), 127.0 - (128.0 * Complex.ImaginaryOne) }));
|
||||||
|
|
||||||
array = matFile["uint8_complex"].Value;
|
array = matFile["uint8_complex"].Value;
|
||||||
CheckComplexLimits(array as IArrayOf<ComplexOf<byte>>, CommonData.UInt8Limits);
|
CheckComplexLimits(array as IArrayOf<ComplexOf<byte>>, CommonData.UInt8Limits);
|
||||||
@ -99,467 +102,395 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading an ASCII-encoded string.
|
/// Test reading an ASCII-encoded string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestAscii(MatFileReadingMethod method)
|
public void TestAscii()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("ascii", method);
|
var matFile = GetTests("good")["ascii"];
|
||||||
var arrayAscii = matFile["s"].Value as ICharArray;
|
var arrayAscii = matFile["s"].Value as ICharArray;
|
||||||
Assert.NotNull(arrayAscii);
|
Assert.That(arrayAscii, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 3 }, arrayAscii.Dimensions);
|
Assert.That(arrayAscii.Dimensions, Is.EqualTo(new[] { 1, 3 }));
|
||||||
Assert.Equal("abc", arrayAscii.String);
|
Assert.That(arrayAscii.String, Is.EqualTo("abc"));
|
||||||
Assert.Equal('c', arrayAscii[2]);
|
Assert.That(arrayAscii[2], Is.EqualTo('c'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a Unicode string.
|
/// Test reading a Unicode string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestUnicode(MatFileReadingMethod method)
|
public void TestUnicode()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("unicode", method);
|
var matFile = GetTests("good")["unicode"];
|
||||||
var arrayUnicode = matFile["s"].Value as ICharArray;
|
var arrayUnicode = matFile["s"].Value as ICharArray;
|
||||||
Assert.NotNull(arrayUnicode);
|
Assert.That(arrayUnicode, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, arrayUnicode.Dimensions);
|
Assert.That(arrayUnicode.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
Assert.Equal("必フ", arrayUnicode.String);
|
Assert.That(arrayUnicode.String, Is.EqualTo("必フ"));
|
||||||
Assert.Equal('必', arrayUnicode[0]);
|
Assert.That(arrayUnicode[0], Is.EqualTo('必'));
|
||||||
Assert.Equal('フ', arrayUnicode[1]);
|
Assert.That(arrayUnicode[1], Is.EqualTo('フ'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a wide Unicode string.
|
/// Test reading a wide Unicode string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestUnicodeWide(MatFileReadingMethod method)
|
public void TestUnicodeWide()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("unicode-wide", method);
|
var matFile = GetTests("good")["unicode-wide"];
|
||||||
var arrayUnicodeWide = matFile["s"].Value as ICharArray;
|
var arrayUnicodeWide = matFile["s"].Value as ICharArray;
|
||||||
Assert.NotNull(arrayUnicodeWide);
|
Assert.That(arrayUnicodeWide, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, arrayUnicodeWide.Dimensions);
|
Assert.That(arrayUnicodeWide.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
Assert.Equal("🍆", arrayUnicodeWide.String);
|
Assert.That(arrayUnicodeWide.String, Is.EqualTo("🍆"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test converting a structure array to a Double array.
|
/// Test converting a structure array to a Double array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
/// <returns>Should return null.</returns>
|
||||||
public void TestConvertToDoubleArray(MatFileReadingMethod method)
|
[Test(ExpectedResult = null)]
|
||||||
|
public double[] TestConvertToDoubleArray()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("struct", method);
|
var matFile = GetTests("good")["struct"];
|
||||||
var array = matFile.Variables[0].Value;
|
var array = matFile.Variables[0].Value;
|
||||||
Assert.Null(array.ConvertToDoubleArray());
|
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>
|
/// <returns>Should return null.</returns>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test(ExpectedResult = null)]
|
||||||
public void TestConvertToComplexArray(MatFileReadingMethod method)
|
public Complex[] TestConvertToComplexArray()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("struct", method);
|
var matFile = GetTests("good")["struct"];
|
||||||
var array = matFile.Variables[0].Value;
|
var array = matFile.Variables[0].Value;
|
||||||
Assert.Null(array.ConvertToComplexArray());
|
return array.ConvertToComplexArray();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading an enumeration.
|
|
||||||
/// </summary>
|
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
|
||||||
public void TestEnum(MatFileReadingMethod method)
|
|
||||||
{
|
|
||||||
var matFile = ReadTestFile("enum", method);
|
|
||||||
var days = matFile["days"].Value;
|
|
||||||
var enumeration = new EnumAdapter(days);
|
|
||||||
Assert.Equal(5, enumeration.Values.Count);
|
|
||||||
Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[0]]);
|
|
||||||
Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[1]]);
|
|
||||||
Assert.Equal("Monday", enumeration.ValueNames[enumeration.Values[2]]);
|
|
||||||
Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[3]]);
|
|
||||||
Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[4]]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a structure array.
|
/// Test reading a structure array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestStruct(MatFileReadingMethod method)
|
public void TestStruct()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("struct", method);
|
var matFile = GetTests("good")["struct"];
|
||||||
var structure = matFile["struct_"].Value as IStructureArray;
|
var structure = matFile["struct_"].Value as IStructureArray;
|
||||||
Assert.NotNull(structure);
|
Assert.That(structure, Is.Not.Null);
|
||||||
Assert.Equal(new[] { "x", "y" }, structure.FieldNames);
|
Assert.That(structure.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
var element = structure[0, 0];
|
var element = structure[0, 0];
|
||||||
Assert.True(element.ContainsKey("x"));
|
Assert.That(element.ContainsKey("x"), Is.True);
|
||||||
Assert.Equal(2, element.Count);
|
Assert.That(element.Count, Is.EqualTo(2));
|
||||||
Assert.True(element.TryGetValue("x", out var _));
|
Assert.That(element.TryGetValue("x", out var _), Is.True);
|
||||||
Assert.False(element.TryGetValue("z", out var _));
|
Assert.That(element.TryGetValue("z", out var _), Is.False);
|
||||||
Assert.Equal(2, element.Keys.Count());
|
Assert.That(element.Keys, Has.Exactly(2).Items);
|
||||||
Assert.Equal(2, element.Values.Count());
|
Assert.That(element.Values, Has.Exactly(2).Items);
|
||||||
var keys = element.Select(pair => pair.Key);
|
var keys = element.Select(pair => pair.Key);
|
||||||
Assert.Equal(new[] { "x", "y" }, keys);
|
Assert.That(keys, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
|
|
||||||
Assert.Equal(12.345, (element["x"] as IArrayOf<double>)?[0]);
|
Assert.That((element["x"] as IArrayOf<double>)?[0], Is.EqualTo(12.345));
|
||||||
|
|
||||||
Assert.Equal(12.345, (structure["x", 0, 0] as IArrayOf<double>)?[0]);
|
Assert.That((structure["x", 0, 0] as IArrayOf<double>)?[0], Is.EqualTo(12.345));
|
||||||
Assert.Equal(2.0, (structure["x", 0, 1] as IArrayOf<double>)?[0]);
|
Assert.That((structure["y", 0, 0] as ICharArray)?.String, Is.EqualTo("abc"));
|
||||||
Assert.Equal("x", ((structure["x", 0, 2] as ICellArray)?[0] as ICharArray)?.String);
|
Assert.That((structure["x", 1, 0] as ICharArray)?.String, Is.EqualTo("xyz"));
|
||||||
Assert.Equal("yz", ((structure["x", 0, 2] as ICellArray)?[1] as ICharArray)?.String);
|
Assert.That(structure["y", 1, 0].IsEmpty, Is.True);
|
||||||
Assert.Equal("xyz", (structure["x", 1, 0] as ICharArray)?.String);
|
Assert.That((structure["x", 0, 1] as IArrayOf<double>)?[0], Is.EqualTo(2.0));
|
||||||
Assert.True(structure["x", 1, 1].IsEmpty);
|
Assert.That((structure["y", 0, 1] as IArrayOf<double>)?[0], Is.EqualTo(13.0));
|
||||||
Assert.Equal(1.5f, (structure["x", 1, 2] as IArrayOf<float>)?[0]);
|
Assert.That(structure["x", 1, 1].IsEmpty, Is.True);
|
||||||
|
Assert.That((structure["y", 1, 1] as ICharArray)?[0, 0], Is.EqualTo('a'));
|
||||||
|
Assert.That(((structure["x", 0, 2] as ICellArray)?[0] as ICharArray)?.String, Is.EqualTo("x"));
|
||||||
|
Assert.That(((structure["x", 0, 2] as ICellArray)?[1] as ICharArray)?.String, Is.EqualTo("yz"));
|
||||||
|
Assert.That((structure["y", 0, 2] as IArrayOf<double>)?.Dimensions, Is.EqualTo(new[] { 2, 3 }));
|
||||||
|
Assert.That((structure["y", 0, 2] as IArrayOf<double>)?[0, 2], Is.EqualTo(3.0));
|
||||||
|
Assert.That((structure["x", 1, 2] as IArrayOf<float>)?[0], Is.EqualTo(1.5f));
|
||||||
|
Assert.That(structure["y", 1, 2].IsEmpty, Is.True);
|
||||||
|
|
||||||
Assert.Equal("abc", (structure["y", 0, 0] as ICharArray)?.String);
|
Assert.That(structure["y", 0, 2].ConvertTo2dDoubleArray(), Is.EqualTo(
|
||||||
Assert.Equal(13.0, (structure["y", 0, 1] as IArrayOf<double>)?[0]);
|
|
||||||
Assert.Equal(new[] { 2, 3 }, (structure["y", 0, 2] as IArrayOf<double>)?.Dimensions);
|
|
||||||
Assert.Equal(3.0, (structure["y", 0, 2] as IArrayOf<double>)?[0, 2]);
|
|
||||||
Assert.True(structure["y", 1, 0].IsEmpty);
|
|
||||||
Assert.Equal('a', (structure["y", 1, 1] as ICharArray)?[0, 0]);
|
|
||||||
Assert.True(structure["y", 1, 2].IsEmpty);
|
|
||||||
|
|
||||||
Assert.Equal(
|
|
||||||
new double[,]
|
new double[,]
|
||||||
{
|
{
|
||||||
{ 1, 2, 3 },
|
{ 1, 2, 3 },
|
||||||
{ 4, 5, 6 },
|
{ 4, 5, 6 },
|
||||||
},
|
}));
|
||||||
structure["y", 0, 2].ConvertTo2dDoubleArray());
|
Assert.That(structure["y", 0, 2].ConvertToMultidimensionalDoubleArray(), Is.EqualTo(
|
||||||
Assert.Equal(
|
|
||||||
new double[,]
|
new double[,]
|
||||||
{
|
{
|
||||||
{ 1, 2, 3 },
|
{ 1, 2, 3 },
|
||||||
{ 4, 5, 6 },
|
{ 4, 5, 6 },
|
||||||
},
|
}));
|
||||||
structure["y", 0, 2].ConvertToMultidimensionalDoubleArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a sparse array.
|
/// Test reading a sparse array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestSparse(MatFileReadingMethod method)
|
public void TestSparse()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("sparse", method);
|
var matFile = GetTests("good")["sparse"];
|
||||||
var sparseArray = matFile["sparse_"].Value as ISparseArrayOf<double>;
|
var sparseArray = matFile["sparse_"].Value as ISparseArrayOf<double>;
|
||||||
Assert.NotNull(sparseArray);
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 4, 5 }, sparseArray.Dimensions);
|
Assert.That(sparseArray.Dimensions, Is.EqualTo(new[] { 4, 5 }));
|
||||||
Assert.Equal(1.0, sparseArray.Data[(1, 1)]);
|
Assert.That(sparseArray.Data[(1, 1)], Is.EqualTo(1.0));
|
||||||
Assert.Equal(1.0, sparseArray[1, 1]);
|
Assert.That(sparseArray[1, 1], Is.EqualTo(1.0));
|
||||||
Assert.Equal(2.0, sparseArray[1, 2]);
|
Assert.That(sparseArray[1, 2], Is.EqualTo(2.0));
|
||||||
Assert.Equal(3.0, sparseArray[2, 1]);
|
Assert.That(sparseArray[2, 1], Is.EqualTo(3.0));
|
||||||
Assert.Equal(4.0, sparseArray[2, 3]);
|
Assert.That(sparseArray[2, 3], Is.EqualTo(4.0));
|
||||||
Assert.Equal(0.0, sparseArray[0, 4]);
|
Assert.That(sparseArray[0, 4], Is.EqualTo(0.0));
|
||||||
Assert.Equal(0.0, sparseArray[3, 0]);
|
Assert.That(sparseArray[3, 0], Is.EqualTo(0.0));
|
||||||
Assert.Equal(0.0, sparseArray[3, 4]);
|
Assert.That(sparseArray[3, 4], Is.EqualTo(0.0));
|
||||||
|
|
||||||
Assert.Equal(
|
Assert.That(sparseArray.ConvertTo2dDoubleArray(), Is.EqualTo(
|
||||||
new double[,]
|
new double[,]
|
||||||
{
|
{
|
||||||
{ 0, 0, 0, 0, 0 },
|
{ 0, 0, 0, 0, 0 },
|
||||||
{ 0, 1, 2, 0, 0 },
|
{ 0, 1, 2, 0, 0 },
|
||||||
{ 0, 3, 0, 4, 0 },
|
{ 0, 3, 0, 4, 0 },
|
||||||
{ 0, 0, 0, 0, 0 },
|
{ 0, 0, 0, 0, 0 },
|
||||||
},
|
}));
|
||||||
sparseArray.ConvertTo2dDoubleArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a logical array.
|
/// Test reading a logical array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestLogical(MatFileReadingMethod method)
|
public void TestLogical()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("logical", method);
|
var matFile = GetTests("good")["logical"];
|
||||||
var array = matFile["logical_"].Value;
|
var array = matFile["logical_"].Value;
|
||||||
var logicalArray = array as IArrayOf<bool>;
|
var logicalArray = array as IArrayOf<bool>;
|
||||||
Assert.NotNull(logicalArray);
|
Assert.That(logicalArray, Is.Not.Null);
|
||||||
Assert.True(logicalArray[0, 0]);
|
Assert.That(logicalArray[0, 0], Is.True);
|
||||||
Assert.True(logicalArray[0, 1]);
|
Assert.That(logicalArray[0, 1], Is.True);
|
||||||
Assert.False(logicalArray[0, 2]);
|
Assert.That(logicalArray[0, 2], Is.False);
|
||||||
Assert.False(logicalArray[1, 0]);
|
Assert.That(logicalArray[1, 0], Is.False);
|
||||||
Assert.True(logicalArray[1, 1]);
|
Assert.That(logicalArray[1, 1], Is.True);
|
||||||
Assert.True(logicalArray[1, 2]);
|
Assert.That(logicalArray[1, 2], Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a sparse logical array.
|
/// Test reading a sparse logical array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestSparseLogical(MatFileReadingMethod method)
|
public void TestSparseLogical()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("sparse_logical", method);
|
var matFile = GetTests("good")["sparse_logical"];
|
||||||
var array = matFile["sparse_logical"].Value;
|
var array = matFile["sparse_logical"].Value;
|
||||||
var sparseArray = array as ISparseArrayOf<bool>;
|
var sparseArray = array as ISparseArrayOf<bool>;
|
||||||
Assert.NotNull (sparseArray);
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
Assert.True(sparseArray.Data[(0, 0)]);
|
Assert.That(sparseArray.Data[(0, 0)], Is.True);
|
||||||
Assert.True(sparseArray[0, 0]);
|
Assert.That(sparseArray[0, 0], Is.True);
|
||||||
Assert.True(sparseArray[0, 1]);
|
Assert.That(sparseArray[0, 1], Is.True);
|
||||||
Assert.False(sparseArray[0, 2]);
|
Assert.That(sparseArray[0, 2], Is.False);
|
||||||
Assert.False(sparseArray[1, 0]);
|
Assert.That(sparseArray[1, 0], Is.False);
|
||||||
Assert.True(sparseArray[1, 1]);
|
Assert.That(sparseArray[1, 1], Is.True);
|
||||||
Assert.True(sparseArray[1, 2]);
|
Assert.That(sparseArray[1, 2], Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a global variable.
|
/// Test reading a global variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestGlobal(MatFileReadingMethod method)
|
public void TestGlobal()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("global", method);
|
var matFile = GetTests("good")["global"];
|
||||||
var variable = matFile.Variables.First();
|
var variable = matFile.Variables.First();
|
||||||
Assert.True(variable.IsGlobal);
|
Assert.That(variable.IsGlobal, Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a sparse complex array.
|
/// Test reading a sparse complex array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TextSparseComplex(MatFileReadingMethod method)
|
public void TextSparseComplex()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("sparse_complex", method);
|
var matFile = GetTests("good")["sparse_complex"];
|
||||||
var array = matFile["sparse_complex"].Value;
|
var array = matFile["sparse_complex"].Value;
|
||||||
var sparseArray = array as ISparseArrayOf<Complex>;
|
var sparseArray = array as ISparseArrayOf<Complex>;
|
||||||
Assert.NotNull(sparseArray);
|
Assert.That(sparseArray, Is.Not.Null);
|
||||||
Assert.Equal(-1.5 + (2.5 * Complex.ImaginaryOne), sparseArray[0, 0]);
|
Assert.That(sparseArray[0, 0], Is.EqualTo(-1.5 + (2.5 * Complex.ImaginaryOne)));
|
||||||
Assert.Equal(2 - (3 * Complex.ImaginaryOne), sparseArray[1, 0]);
|
Assert.That(sparseArray[1, 0], Is.EqualTo(2 - (3 * Complex.ImaginaryOne)));
|
||||||
Assert.Equal(Complex.Zero, sparseArray[0, 1]);
|
Assert.That(sparseArray[0, 1], Is.EqualTo(Complex.Zero));
|
||||||
Assert.Equal(0.5 + (1.0 * Complex.ImaginaryOne), sparseArray[1, 1]);
|
Assert.That(sparseArray[1, 1], Is.EqualTo(0.5 + (1.0 * Complex.ImaginaryOne)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading an object.
|
/// Test reading an object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestObject(MatFileReadingMethod method)
|
public void TestObject()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("object", method);
|
var matFile = GetTests("good")["object"];
|
||||||
var obj = matFile["object_"].Value as IMatObject;
|
var obj = matFile["object_"].Value as IMatObject;
|
||||||
Assert.NotNull(obj);
|
Assert.IsNotNull(obj);
|
||||||
Assert.Equal("Point", obj.ClassName);
|
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
||||||
Assert.Equal(new[] { "x", "y" }, obj.FieldNames);
|
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
Assert.Equal(new[] { 3.0 }, obj["x", 0].ConvertToDoubleArray());
|
Assert.That(obj["x", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
||||||
Assert.Equal(new[] { 5.0 }, obj["y", 0].ConvertToDoubleArray());
|
Assert.That(obj["y", 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
||||||
Assert.Equal(new[] { -2.0 }, obj["x", 1].ConvertToDoubleArray());
|
Assert.That(obj["x", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
Assert.Equal(new[] { 6.0 }, obj["y", 1].ConvertToDoubleArray());
|
Assert.That(obj["y", 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading another object.
|
/// Test reading another object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestObject2(MatFileReadingMethod method)
|
public void TestObject2()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("object2", method);
|
var matFile = GetTests("good")["object2"];
|
||||||
var obj = matFile["object2"].Value as IMatObject;
|
var obj = matFile["object2"].Value as IMatObject;
|
||||||
Assert.NotNull(obj);
|
Assert.IsNotNull(obj);
|
||||||
Assert.Equal("Point", obj.ClassName);
|
Assert.That(obj.ClassName, Is.EqualTo("Point"));
|
||||||
Assert.Equal(new[] { "x", "y" }, obj.FieldNames);
|
Assert.That(obj.FieldNames, Is.EquivalentTo(new[] { "x", "y" }));
|
||||||
Assert.Equal(new[] { 3.0 }, obj["x", 0, 0].ConvertToDoubleArray());
|
Assert.That(obj["x", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 3.0 }));
|
||||||
Assert.Equal(new[] { -2.0 }, obj["x", 0, 1].ConvertToDoubleArray());
|
Assert.That(obj["y", 0, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 5.0 }));
|
||||||
Assert.Equal(new[] { 1.0 }, obj["x", 1, 0].ConvertToDoubleArray());
|
Assert.That(obj["x", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
||||||
Assert.Equal(new[] { 0.0 }, obj["x", 1, 1].ConvertToDoubleArray());
|
Assert.That(obj["y", 1, 0].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
||||||
Assert.Equal(new[] { 5.0 }, obj["y", 0, 0].ConvertToDoubleArray());
|
Assert.That(obj["x", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
Assert.Equal(new[] { 6.0 }, obj["y", 0, 1].ConvertToDoubleArray());
|
Assert.That(obj["y", 0, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 6.0 }));
|
||||||
Assert.Equal(new[] { 0.0 }, obj["y", 1, 0].ConvertToDoubleArray());
|
Assert.That(obj["x", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 0.0 }));
|
||||||
Assert.Equal(new[] { 1.0 }, obj["y", 1, 1].ConvertToDoubleArray());
|
Assert.That(obj["y", 1, 1].ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0 }));
|
||||||
Assert.Equal(new[] { -2.0 }, obj[0, 1]["x"].ConvertToDoubleArray());
|
Assert.That(obj[0, 1]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
Assert.Equal(new[] { -2.0 }, obj[2]["x"].ConvertToDoubleArray());
|
Assert.That(obj[2]["x"].ConvertToDoubleArray(), Is.EqualTo(new[] { -2.0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test reading a table.
|
/// Test reading a table.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestTable(MatFileReadingMethod method)
|
public void TestTable()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("table", method);
|
var matFile = GetTests("good")["table"];
|
||||||
var obj = matFile["table_"].Value as IMatObject;
|
var obj = matFile["table_"].Value as IMatObject;
|
||||||
var table = new TableAdapter(obj);
|
var table = new TableAdapter(obj);
|
||||||
Assert.Equal(3, table.NumberOfRows);
|
Assert.That(table.NumberOfRows, Is.EqualTo(3));
|
||||||
Assert.Equal(2, table.NumberOfVariables);
|
Assert.That(table.NumberOfVariables, Is.EqualTo(2));
|
||||||
Assert.Equal("Some table", table.Description);
|
Assert.That(table.Description, Is.EqualTo("Some table"));
|
||||||
Assert.Equal(new[] { "variable1", "variable2" }, table.VariableNames);
|
Assert.That(table.VariableNames, Is.EqualTo(new[] { "variable1", "variable2" }));
|
||||||
var variable1 = table["variable1"] as ICellArray;
|
var variable1 = table["variable1"] as ICellArray;
|
||||||
Assert.Equal("First row", (variable1[0] as ICharArray).String);
|
Assert.That((variable1[0] as ICharArray).String, Is.EqualTo("First row"));
|
||||||
Assert.Equal("Second row", (variable1[1] as ICharArray).String);
|
Assert.That((variable1[1] as ICharArray).String, Is.EqualTo("Second row"));
|
||||||
Assert.Equal("Third row", (variable1[2] as ICharArray).String);
|
Assert.That((variable1[2] as ICharArray).String, Is.EqualTo("Third row"));
|
||||||
var variable2 = table["variable2"];
|
var variable2 = table["variable2"];
|
||||||
Assert.Equal(new[] { 1.0, 3.0, 5.0, 2.0, 4.0, 6.0 }, variable2.ConvertToDoubleArray());
|
Assert.That(variable2.ConvertToDoubleArray(), Is.EqualTo(new[] { 1.0, 3.0, 5.0, 2.0, 4.0, 6.0 }));
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a deeply nested table.
|
|
||||||
/// </summary>
|
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
|
||||||
public void TestDeepTable(MatFileReadingMethod method)
|
|
||||||
{
|
|
||||||
var matFile = ReadTestFile("table-deep", method);
|
|
||||||
var obj = matFile["t"].Value as IMatObject;
|
|
||||||
var table = new TableAdapter(obj);
|
|
||||||
Assert.Equal(1, table.NumberOfRows);
|
|
||||||
Assert.Equal(2, table.NumberOfVariables);
|
|
||||||
Assert.Equal(new[] { "s", "another" }, table.VariableNames);
|
|
||||||
var s = table["s"] as IStructureArray;
|
|
||||||
Assert.Equal(new[] { "a", "b", "c" }, s.FieldNames);
|
|
||||||
var c = s["c", 0];
|
|
||||||
var internalTable = new TableAdapter(c);
|
|
||||||
Assert.Equal(2, internalTable.NumberOfRows);
|
|
||||||
Assert.Equal(2, internalTable.NumberOfVariables);
|
|
||||||
Assert.Equal(new[] { "x", "y" }, internalTable.VariableNames);
|
|
||||||
var y = new StringAdapter(internalTable["y"]);
|
|
||||||
Assert.Equal("3", y[0]);
|
|
||||||
Assert.Equal("abc", y[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Test reading a table with strings
|
|
||||||
/// </summary>
|
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
|
||||||
public void TestTableWithStrings(MatFileReadingMethod method)
|
|
||||||
{
|
|
||||||
var matFile = ReadTestFile("table-with-strings", method);
|
|
||||||
var obj = matFile["t"].Value as IMatObject;
|
|
||||||
var table = new TableAdapter(obj);
|
|
||||||
Assert.Equal(5, table.NumberOfRows);
|
|
||||||
Assert.Equal(2, table.NumberOfVariables);
|
|
||||||
Assert.Equal(new[] { "Numbers", "Names" }, table.VariableNames);
|
|
||||||
var variable = table["Names"] as ICellArray;
|
|
||||||
var name0 = new StringAdapter(variable[0]);
|
|
||||||
Assert.Equal("One", name0[0]);
|
|
||||||
var name1 = new StringAdapter(variable[1]);
|
|
||||||
Assert.Equal("Two", name1[0]);
|
|
||||||
var name2 = new StringAdapter(variable[2]);
|
|
||||||
Assert.Equal("Three", name2[0]);
|
|
||||||
var name3 = new StringAdapter(variable[3]);
|
|
||||||
Assert.Equal("Four", name3[0]);
|
|
||||||
var name4 = new StringAdapter(variable[4]);
|
|
||||||
Assert.Equal("Five", name4[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test subobjects within objects.
|
/// Test subobjects within objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestSubobjects(MatFileReadingMethod method)
|
public void TestSubobjects()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("pointWithSubpoints", method);
|
var matFile = GetTests("good")["pointWithSubpoints"];
|
||||||
var p = matFile["p"].Value as IMatObject;
|
var p = matFile["p"].Value as IMatObject;
|
||||||
Assert.Equal("Point", p.ClassName);
|
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
||||||
var x = p["x"] as IMatObject;
|
var x = p["x"] as IMatObject;
|
||||||
Assert.Equal("SubPoint", x.ClassName);
|
Assert.That(x.ClassName, Is.EqualTo("SubPoint"));
|
||||||
Assert.Equal(new[] { "a", "b", "c" }, x.FieldNames);
|
Assert.That(x.FieldNames, Is.EquivalentTo(new[] { "a", "b", "c" }));
|
||||||
var y = p["y"] as IMatObject;
|
var y = p["y"] as IMatObject;
|
||||||
Assert.Equal("SubPoint", y.ClassName);
|
Assert.That(y.ClassName, Is.EqualTo("SubPoint"));
|
||||||
Assert.Equal(new[] { "a", "b", "c" }, y.FieldNames);
|
Assert.That(y.FieldNames, Is.EquivalentTo(new[] { "a", "b", "c" }));
|
||||||
Assert.Equal(new[] { 1.0 }, x["a"].ConvertToDoubleArray());
|
Assert.That(x["a"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 1.0 }));
|
||||||
Assert.Equal(new[] { 2.0 }, x["b"].ConvertToDoubleArray());
|
Assert.That(x["b"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 2.0 }));
|
||||||
Assert.Equal(new[] { 3.0 }, x["c"].ConvertToDoubleArray());
|
Assert.That(x["c"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 3.0 }));
|
||||||
Assert.Equal(new[] { 14.0 }, y["a"].ConvertToDoubleArray());
|
Assert.That(y["a"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 14.0 }));
|
||||||
Assert.Equal(new[] { 15.0 }, y["b"].ConvertToDoubleArray());
|
Assert.That(y["b"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 15.0 }));
|
||||||
Assert.Equal(new[] { 16.0 }, y["c"].ConvertToDoubleArray());
|
Assert.That(y["c"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 16.0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test nested objects.
|
/// Test nested objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestNestedObjects(MatFileReadingMethod method)
|
public void TestNestedObjects()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("subsubPoint", method);
|
var matFile = GetTests("good")["subsubPoint"];
|
||||||
var p = matFile["p"].Value as IMatObject;
|
var p = matFile["p"].Value as IMatObject;
|
||||||
Assert.Equal("Point", p.ClassName);
|
Assert.That(p.ClassName, Is.EqualTo("Point"));
|
||||||
Assert.Equal(new[] { 1.0 }, p["x"].ConvertToDoubleArray());
|
Assert.That(p["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 1.0 }));
|
||||||
var pp = p["y"] as IMatObject;
|
var pp = p["y"] as IMatObject;
|
||||||
Assert.True(pp.ClassName == "Point");
|
Assert.That(pp.ClassName == "Point");
|
||||||
Assert.Equal(new[] { 10.0 }, pp["x"].ConvertToDoubleArray());
|
Assert.That(pp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 10.0 }));
|
||||||
var ppp = pp["y"] as IMatObject;
|
var ppp = pp["y"] as IMatObject;
|
||||||
Assert.Equal(new[] { 100.0 }, ppp["x"].ConvertToDoubleArray());
|
Assert.That(ppp["x"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 100.0 }));
|
||||||
Assert.Equal(new[] { 200.0 }, ppp["y"].ConvertToDoubleArray());
|
Assert.That(ppp["y"].ConvertToDoubleArray(), Is.EquivalentTo(new[] { 200.0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test datetime objects.
|
/// Test datetime objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestDatetime(MatFileReadingMethod method)
|
public void TestDatetime()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("datetime", method);
|
var matFile = GetTests("good")["datetime"];
|
||||||
var d = matFile["d"].Value as IMatObject;
|
var d = matFile["d"].Value as IMatObject;
|
||||||
var datetime = new DatetimeAdapter(d);
|
var datetime = new DatetimeAdapter(d);
|
||||||
Assert.Equal(new[] { 1, 2 }, datetime.Dimensions);
|
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 2 }));
|
||||||
Assert.Equal(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero), datetime[0]);
|
Assert.That(datetime[0], Is.EqualTo(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero)));
|
||||||
Assert.Equal(new DateTimeOffset(1987, 1, 2, 3, 4, 5, TimeSpan.Zero), datetime[1]);
|
Assert.That(datetime[1], Is.EqualTo(new DateTimeOffset(1987, 1, 2, 3, 4, 5, TimeSpan.Zero)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Another test for datetime objects.
|
/// Another test for datetime objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestDatetime2(MatFileReadingMethod method)
|
public void TestDatetime2()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("datetime2", method);
|
var matFile = GetTests("good")["datetime2"];
|
||||||
var d = matFile["d"].Value as IMatObject;
|
var d = matFile["d"].Value as IMatObject;
|
||||||
var datetime = new DatetimeAdapter(d);
|
var datetime = new DatetimeAdapter(d);
|
||||||
Assert.Equal(new[] { 1, 1 }, datetime.Dimensions);
|
Assert.That(datetime.Dimensions, Is.EquivalentTo(new[] { 1, 1 }));
|
||||||
var diff = new DateTimeOffset(2, 1, 1, 1, 1, 1, 235, TimeSpan.Zero);
|
var diff = new DateTimeOffset(2, 1, 1, 1, 1, 1, 235, TimeSpan.Zero);
|
||||||
Assert.True(datetime[0] - diff < TimeSpan.FromMilliseconds(1));
|
Assert.That(datetime[0] - diff < TimeSpan.FromMilliseconds(1));
|
||||||
Assert.True(diff - datetime[0] < TimeSpan.FromMilliseconds(1));
|
Assert.That(diff - datetime[0] < TimeSpan.FromMilliseconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test string objects.
|
/// Test string objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestString(MatFileReadingMethod method)
|
public void TestString()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("string", method);
|
var matFile = GetTests("good")["string"];
|
||||||
var s = matFile["s"].Value as IMatObject;
|
var s = matFile["s"].Value as IMatObject;
|
||||||
var str = new StringAdapter(s);
|
var str = new StringAdapter(s);
|
||||||
Assert.Equal(new[] { 4, 1 }, str.Dimensions);
|
Assert.That(str.Dimensions, Is.EquivalentTo(new[] { 4, 1 }));
|
||||||
Assert.Equal("abc", str[0]);
|
Assert.That(str[0], Is.EqualTo("abc"));
|
||||||
Assert.Equal("defgh", str[1]);
|
Assert.That(str[1], Is.EqualTo("defgh"));
|
||||||
Assert.Equal("абвгд", str[2]);
|
Assert.That(str[2], Is.EqualTo("абвгд"));
|
||||||
Assert.Equal("æøå", str[3]);
|
Assert.That(str[3], Is.EqualTo("æøå"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test duration objects.
|
/// Test duration objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestDuration(MatFileReadingMethod method)
|
public void TestDuration()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("duration", method);
|
var matFile = GetTests("good")["duration"];
|
||||||
var d = matFile["d"].Value as IMatObject;
|
var d = matFile["d"].Value as IMatObject;
|
||||||
var duration = new DurationAdapter(d);
|
var duration = new DurationAdapter(d);
|
||||||
Assert.Equal(new[] { 1, 3 }, duration.Dimensions);
|
Assert.That(duration.Dimensions, Is.EquivalentTo(new[] { 1, 3 }));
|
||||||
Assert.Equal(TimeSpan.FromTicks(12345678L), duration[0]);
|
Assert.That(duration[0], Is.EqualTo(TimeSpan.FromTicks(12345678L)));
|
||||||
Assert.Equal(new TimeSpan(0, 2, 4), duration[1]);
|
Assert.That(duration[1], Is.EqualTo(new TimeSpan(0, 2, 4)));
|
||||||
Assert.Equal(new TimeSpan(1, 3, 5), duration[2]);
|
Assert.That(duration[2], Is.EqualTo(new TimeSpan(1, 3, 5)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test unrepresentable datetime.
|
/// Test unrepresentable datetime.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
[Test]
|
||||||
public void TestDatetime_Unrepresentable(MatFileReadingMethod method)
|
public void TestDatetime_Unrepresentable()
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("datetime-unrepresentable", method);
|
var matFile = GetTests("good")["datetime-unrepresentable"];
|
||||||
var obj = matFile["d"].Value as IMatObject;
|
var obj = matFile["d"].Value as IMatObject;
|
||||||
var datetime = new DatetimeAdapter(obj);
|
var datetime = new DatetimeAdapter(obj);
|
||||||
var d0 = datetime[0];
|
var d0 = datetime[0];
|
||||||
Assert.Null(d0);
|
Assert.That(d0, Is.Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
[Test]
|
||||||
/// Test 3-dimensional arrays.
|
public void Test_3DArrays()
|
||||||
/// </summary>
|
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
|
||||||
public void Test_3DArrays(MatFileReadingMethod method)
|
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("issue20", method);
|
var matFile = GetTests("good")["issue20.mat"];
|
||||||
var obj = matFile["a3d"].Value;
|
var obj = matFile["a3d"].Value;
|
||||||
var values = obj.ConvertToDoubleArray();
|
var values = obj.ConvertToDoubleArray();
|
||||||
Assert.Equal(Enumerable.Range(1, 24).Select(x => (double)x).ToArray(), values);
|
Assert.That(values, Is.EqualTo(Enumerable.Range(1, 24)));
|
||||||
var expected = new double[3, 4, 2]
|
var expected = new double[3, 4, 2]
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -581,70 +512,37 @@ namespace MatFileHandler.Tests
|
|||||||
{ 12, 24 },
|
{ 12, 24 },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Assert.Equal(expected, obj.ConvertToMultidimensionalDoubleArray());
|
Assert.That(obj.ConvertToMultidimensionalDoubleArray(), Is.EqualTo(expected));
|
||||||
Assert.Null(obj.ConvertTo2dDoubleArray());
|
Assert.That(obj.ConvertTo2dDoubleArray(), Is.EqualTo(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
[Test]
|
||||||
/// Test four-dimensional arrays.
|
public void Test_4DArrays()
|
||||||
/// </summary>
|
|
||||||
[Theory, MemberData(nameof(TestDataFactories))]
|
|
||||||
public void Test4DArrays(MatFileReadingMethod method)
|
|
||||||
{
|
{
|
||||||
var matFile = ReadTestFile("issue20", method);
|
var matFile = GetTests("good")["issue20.mat"];
|
||||||
var obj = matFile["a4d"].Value;
|
var obj = matFile["a4d"].Value;
|
||||||
Assert.Equal(Enumerable.Range(1, 120).Select(x => (double)x).ToArray(), obj.ConvertToDoubleArray());
|
Assert.That(obj.ConvertToDoubleArray(), Is.EqualTo(Enumerable.Range(1, 120)));
|
||||||
Assert.Null(obj.ConvertTo2dDoubleArray());
|
Assert.That(obj.ConvertTo2dDoubleArray(), Is.EqualTo(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static AbstractTestDataFactory<IMatFile> GetTests(string factoryName) =>
|
||||||
/// Returns the factories that provide test data in various configurations.
|
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
|
||||||
/// </summary>
|
|
||||||
public static TheoryData<MatFileReadingMethod> TestDataFactories
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new TheoryData<MatFileReadingMethod>
|
|
||||||
{
|
|
||||||
MatFileReadingMethod.NormalStream,
|
|
||||||
MatFileReadingMethod.PartialStream,
|
|
||||||
MatFileReadingMethod.UnalignedStream,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IMatFile ReadTestFile(string fileName, MatFileReadingMethod method)
|
|
||||||
{
|
|
||||||
var fullFileName = Path.Combine("test-data", "good", $"{fileName}.mat");
|
|
||||||
return MatFileReadingMethods.ReadMatFile(method, fullFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<IMatFile> ReadAllTestFiles(MatFileReadingMethod method)
|
|
||||||
{
|
|
||||||
foreach (var fileName in Directory.EnumerateFiles(
|
|
||||||
Path.Combine("test-data", "good"),
|
|
||||||
"*.mat"))
|
|
||||||
{
|
|
||||||
var fullFileName = fileName;
|
|
||||||
yield return MatFileReadingMethods.ReadMatFile(method, fullFileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
|
private static void CheckLimits<T>(IArrayOf<T> array, T[] limits)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
Assert.NotNull(array);
|
Assert.That(array, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, array.Dimensions);
|
Assert.That(array.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
Assert.Equal(limits, array.Data);
|
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)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
Assert.NotNull(array);
|
Assert.That(array, Is.Not.Null);
|
||||||
Assert.Equal(new[] { 1, 2 }, array.Dimensions);
|
Assert.That(array.Dimensions, Is.EqualTo(new[] { 1, 2 }));
|
||||||
Assert.Equal(new ComplexOf<T>(limits[0], limits[1]), array[0]);
|
Assert.That(array[0], Is.EqualTo(new ComplexOf<T>(limits[0], limits[1])));
|
||||||
Assert.Equal(new ComplexOf<T>(limits[1], limits[0]), array[1]);
|
Assert.That(array[1], Is.EqualTo(new ComplexOf<T>(limits[1], limits[0])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,27 +0,0 @@
|
|||||||
namespace MatFileHandler.Tests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Method of reading .mat files for testing.
|
|
||||||
/// </summary>
|
|
||||||
public enum MatFileReadingMethod
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Undefined.
|
|
||||||
/// </summary>
|
|
||||||
Undefined = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normal stream (like memory or file stream).
|
|
||||||
/// </summary>
|
|
||||||
NormalStream,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Partial stream (only is capable of reading one byte at a time).
|
|
||||||
/// </summary>
|
|
||||||
PartialStream,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unaligned stream (what happens if the data don't start at the beginning?).
|
|
||||||
/// </summary>
|
|
||||||
UnalignedStream,
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler.Tests;
|
|
||||||
|
|
||||||
internal static class MatFileReadingMethods
|
|
||||||
{
|
|
||||||
public static IMatFile ReadMatFile(MatFileReadingMethod method, string fullFileName)
|
|
||||||
{
|
|
||||||
using var stream = File.OpenRead(fullFileName);
|
|
||||||
switch (method)
|
|
||||||
{
|
|
||||||
case MatFileReadingMethod.NormalStream:
|
|
||||||
return ReadFromStream(stream);
|
|
||||||
case MatFileReadingMethod.PartialStream:
|
|
||||||
{
|
|
||||||
using var wrapper = new PartialUnseekableReadStream(stream);
|
|
||||||
return ReadFromStream(wrapper);
|
|
||||||
}
|
|
||||||
case MatFileReadingMethod.UnalignedStream:
|
|
||||||
{
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
ms.Seek(3, SeekOrigin.Begin);
|
|
||||||
stream.CopyTo(ms);
|
|
||||||
ms.Seek(3, SeekOrigin.Begin);
|
|
||||||
return ReadFromStream(ms);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IMatFile ReadFromStream(Stream stream)
|
|
||||||
{
|
|
||||||
var reader = new MatFileReader(stream);
|
|
||||||
return reader.Read();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
namespace MatFileHandler.Tests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Options to give to MatFileWriter constructor for testing it.
|
|
||||||
/// </summary>
|
|
||||||
public enum MatFileWriterOptionsForTests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Undefined.
|
|
||||||
/// </summary>
|
|
||||||
Undefined = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// No options.
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Option to always use compression.
|
|
||||||
/// </summary>
|
|
||||||
Always,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Option to never use compression.
|
|
||||||
/// </summary>
|
|
||||||
Never,
|
|
||||||
}
|
|
@ -1,13 +1,16 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Xunit;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
namespace MatFileHandler.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests of file writing API.
|
/// Tests of file writing API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
public class MatFileWriterTests
|
public class MatFileWriterTests
|
||||||
{
|
{
|
||||||
private const string TestDirectory = "test-data";
|
private const string TestDirectory = "test-data";
|
||||||
@ -15,8 +18,8 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a simple Double array.
|
/// Test writing a simple Double array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestWrite(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestWrite()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var array = builder.NewArray<double>(1, 2);
|
var array = builder.NewArray<double>(1, 2);
|
||||||
@ -24,13 +27,13 @@ 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, method, options);
|
MatCompareWithTestData("good", "double-array", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a large file.
|
/// Test writing a large file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Test]
|
||||||
public void TestHuge()
|
public void TestHuge()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
@ -49,8 +52,8 @@ namespace MatFileHandler.Tests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing lower and upper limits of integer data types.
|
/// Test writing lower and upper limits of integer data types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestLimits(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestLimits()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var int8 = builder.NewVariable("int8_", builder.NewArray(CommonData.Int8Limits, 1, 2));
|
var int8 = builder.NewVariable("int8_", builder.NewArray(CommonData.Int8Limits, 1, 2));
|
||||||
@ -62,14 +65,14 @@ 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, method, options);
|
MatCompareWithTestData("good", "limits", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestLimitsComplex(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestLimitsComplex()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var int8Complex = builder.NewVariable(
|
var int8Complex = builder.NewVariable(
|
||||||
@ -101,26 +104,26 @@ namespace MatFileHandler.Tests
|
|||||||
int16Complex, int32Complex, int64Complex, int8Complex,
|
int16Complex, int32Complex, int64Complex, int8Complex,
|
||||||
uint16Complex, uint32Complex, uint64Complex, uint8Complex,
|
uint16Complex, uint32Complex, uint64Complex, uint8Complex,
|
||||||
});
|
});
|
||||||
MatCompareWithTestData("good", "limits_complex", actual, method, options);
|
MatCompareWithTestData("good", "limits_complex", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a wide-Unicode symbol.
|
/// Test writing a wide-Unicode symbol.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestUnicodeWide(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestUnicodeWide()
|
||||||
{
|
{
|
||||||
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, method, options);
|
MatCompareWithTestData("good", "unicode-wide", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a sparse array.
|
/// Test writing a sparse array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestSparseArray(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestSparseArray()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var sparseArray = builder.NewSparseArray<double>(4, 5);
|
var sparseArray = builder.NewSparseArray<double>(4, 5);
|
||||||
@ -130,14 +133,14 @@ 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, method, options);
|
MatCompareWithTestData("good", "sparse", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a structure array.
|
/// Test writing a structure array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestStructure(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestStructure()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var structure = builder.NewStructureArray(new[] { "x", "y" }, 2, 3);
|
var structure = builder.NewStructureArray(new[] { "x", "y" }, 2, 3);
|
||||||
@ -158,27 +161,27 @@ 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, method, options);
|
MatCompareWithTestData("good", "struct", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a logical array.
|
/// Test writing a logical array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestLogical(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestLogical()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
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, method, options);
|
MatCompareWithTestData("good", "logical", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a sparse logical array.
|
/// Test writing a sparse logical array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestSparseLogical(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestSparseLogical()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var array = builder.NewSparseArray<bool>(2, 3);
|
var array = builder.NewSparseArray<bool>(2, 3);
|
||||||
@ -188,14 +191,14 @@ 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, method, options);
|
MatCompareWithTestData("good", "sparse_logical", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a sparse complex array.
|
/// Test writing a sparse complex array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestSparseComplex(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestSparseComplex()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
var array = builder.NewSparseArray<Complex>(2, 2);
|
var array = builder.NewSparseArray<Complex>(2, 2);
|
||||||
@ -204,60 +207,38 @@ 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, method, options);
|
MatCompareWithTestData("good", "sparse_complex", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Test writing a global variable.
|
/// Test writing a global variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Theory, MemberData(nameof(MatFileWritingTestData))]
|
[Test]
|
||||||
public void TestGlobal(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
|
public void TestGlobal()
|
||||||
{
|
{
|
||||||
var builder = new DataBuilder();
|
var builder = new DataBuilder();
|
||||||
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, method, options);
|
MatCompareWithTestData("good", "global", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static AbstractTestDataFactory<IMatFile> GetMatTestData(string factoryName) =>
|
||||||
/// Various writing methods for testing writing of .mat files.
|
new MatTestDataFactory(Path.Combine(TestDirectory, factoryName));
|
||||||
/// </summary>
|
|
||||||
public static TheoryData<MatFileWritingMethod, MatFileWriterOptionsForTests> MatFileWritingTestData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var always = new MatFileWriterOptions { UseCompression = CompressionUsage.Always};
|
|
||||||
var never = new MatFileWriterOptions { UseCompression = CompressionUsage.Never };
|
|
||||||
var data = new TheoryData<MatFileWritingMethod, MatFileWriterOptionsForTests>
|
|
||||||
{
|
|
||||||
{ MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.None },
|
|
||||||
{ MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.Always },
|
|
||||||
{ MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.Never },
|
|
||||||
{ MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.None },
|
|
||||||
{ MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.Always },
|
|
||||||
{ MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.Never },
|
|
||||||
{ MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.None },
|
|
||||||
{ MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.Always },
|
|
||||||
{ MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.Never },
|
|
||||||
};
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CompareSparseArrays<T>(ISparseArrayOf<T> expected, ISparseArrayOf<T> actual)
|
private void CompareSparseArrays<T>(ISparseArrayOf<T> expected, ISparseArrayOf<T> actual)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
Assert.NotNull(actual);
|
Assert.That(actual, Is.Not.Null);
|
||||||
Assert.Equal(expected.Dimensions, actual.Dimensions);
|
Assert.That(expected.Dimensions, Is.EqualTo(actual.Dimensions));
|
||||||
Assert.Equal(expected.Data, actual.Data);
|
Assert.That(expected.Data, Is.EquivalentTo(actual.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareStructureArrays(IStructureArray expected, IStructureArray actual)
|
private void CompareStructureArrays(IStructureArray expected, IStructureArray actual)
|
||||||
{
|
{
|
||||||
Assert.NotNull(actual);
|
Assert.That(actual, Is.Not.Null);
|
||||||
Assert.Equal(expected.Dimensions, actual.Dimensions);
|
Assert.That(expected.Dimensions, Is.EqualTo(actual.Dimensions));
|
||||||
Assert.Equal(expected.FieldNames, actual.FieldNames);
|
Assert.That(expected.FieldNames, Is.EquivalentTo(actual.FieldNames));
|
||||||
foreach (var name in expected.FieldNames)
|
foreach (var name in expected.FieldNames)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < expected.Count; i++)
|
for (var i = 0; i < expected.Count; i++)
|
||||||
@ -267,31 +248,31 @@ namespace MatFileHandler.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareCellArrays(ICellArray expected, ICellArray actual)
|
private void CompareCellArrays(ICellArray expected, ICellArray actual)
|
||||||
{
|
{
|
||||||
Assert.NotNull(actual);
|
Assert.That(actual, Is.Not.Null);
|
||||||
Assert.Equal(expected.Dimensions, actual.Dimensions);
|
Assert.That(expected.Dimensions, Is.EqualTo(actual.Dimensions));
|
||||||
for (var i = 0; i < expected.Count; i++)
|
for (var i = 0; i < expected.Count; i++)
|
||||||
{
|
{
|
||||||
CompareMatArrays(expected[i], actual[i]);
|
CompareMatArrays(expected[i], actual[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareNumericalArrays<T>(IArrayOf<T> expected, IArrayOf<T> actual)
|
private void CompareNumericalArrays<T>(IArrayOf<T> expected, IArrayOf<T> actual)
|
||||||
{
|
{
|
||||||
Assert.NotNull(actual);
|
Assert.That(actual, Is.Not.Null);
|
||||||
Assert.Equal(expected.Dimensions, actual.Dimensions);
|
Assert.That(expected.Dimensions, Is.EqualTo(actual.Dimensions));
|
||||||
Assert.Equal(expected.Data, actual.Data);
|
Assert.That(expected.Data, Is.EqualTo(actual.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareCharArrays(ICharArray expected, ICharArray actual)
|
private void CompareCharArrays(ICharArray expected, ICharArray actual)
|
||||||
{
|
{
|
||||||
Assert.NotNull(actual);
|
Assert.That(actual, Is.Not.Null);
|
||||||
Assert.Equal(expected.Dimensions, actual.Dimensions);
|
Assert.That(expected.Dimensions, Is.EqualTo(actual.Dimensions));
|
||||||
Assert.Equal(expected.String, actual.String);
|
Assert.That(expected.String, Is.EqualTo(actual.String));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareMatArrays(IArray expected, IArray actual)
|
private void CompareMatArrays(IArray expected, IArray actual)
|
||||||
{
|
{
|
||||||
switch (expected)
|
switch (expected)
|
||||||
{
|
{
|
||||||
@ -376,45 +357,63 @@ namespace MatFileHandler.Tests
|
|||||||
}
|
}
|
||||||
if (expected.IsEmpty)
|
if (expected.IsEmpty)
|
||||||
{
|
{
|
||||||
Assert.True(actual.IsEmpty);
|
Assert.That(actual.IsEmpty, Is.True);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompareMatFiles(IMatFile expected, IMatFile actual)
|
private void CompareMatFiles(IMatFile expected, IMatFile actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.Variables.Length, actual.Variables.Length);
|
Assert.That(expected.Variables.Length, Is.EqualTo(actual.Variables.Length));
|
||||||
for (var i = 0; i < expected.Variables.Length; i++)
|
for (var i = 0; i < expected.Variables.Length; i++)
|
||||||
{
|
{
|
||||||
var expectedVariable = expected.Variables[i];
|
var expectedVariable = expected.Variables[i];
|
||||||
var actualVariable = actual.Variables[i];
|
var actualVariable = actual.Variables[i];
|
||||||
Assert.Equal(expectedVariable.Name, actualVariable.Name);
|
Assert.That(expectedVariable.Name, Is.EqualTo(actualVariable.Name));
|
||||||
Assert.Equal(expectedVariable.IsGlobal, actualVariable.IsGlobal);
|
Assert.That(expectedVariable.IsGlobal, Is.EqualTo(actualVariable.IsGlobal));
|
||||||
CompareMatArrays(expectedVariable.Value, actualVariable.Value);
|
CompareMatArrays(expectedVariable.Value, actualVariable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MatCompareWithTestData(
|
private void CompareTestDataWithWritingOptions(
|
||||||
string factoryName,
|
IMatFile expected,
|
||||||
string testName,
|
|
||||||
IMatFile actual,
|
IMatFile actual,
|
||||||
MatFileWritingMethod method,
|
MatFileWriterOptions? maybeOptions)
|
||||||
MatFileWriterOptionsForTests options)
|
|
||||||
{
|
{
|
||||||
var fullFileName = Path.Combine("test-data", "good", $"{testName}.mat");
|
byte[] buffer;
|
||||||
var expected = MatFileReadingMethods.ReadMatFile(
|
using (var stream = new MemoryStream())
|
||||||
MatFileReadingMethod.NormalStream,
|
{
|
||||||
fullFileName);
|
var writer = maybeOptions is MatFileWriterOptions options
|
||||||
var buffer = MatFileWritingMethods.WriteMatFile(method, options, actual);
|
? new MatFileWriter(stream, options)
|
||||||
using var stream = new MemoryStream(buffer);
|
: new MatFileWriter(stream);
|
||||||
var reader = new MatFileReader(stream);
|
writer.Write(actual);
|
||||||
var actualRead = reader.Read();
|
buffer = stream.ToArray();
|
||||||
CompareMatFiles(expected, actualRead);
|
}
|
||||||
|
using (var stream = new MemoryStream(buffer))
|
||||||
|
{
|
||||||
|
var reader = new MatFileReader(stream);
|
||||||
|
var actualRead = reader.Read();
|
||||||
|
CompareMatFiles(expected, actualRead);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ComplexOf<T>[] CreateComplexLimits<T>(T[] limits)
|
private void MatCompareWithTestData(string factoryName, string testName, IMatFile actual)
|
||||||
where T : struct
|
{
|
||||||
|
var expected = GetMatTestData(factoryName)[testName];
|
||||||
|
CompareTestDataWithWritingOptions(expected, actual, null);
|
||||||
|
CompareTestDataWithWritingOptions(
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
new MatFileWriterOptions { UseCompression = CompressionUsage.Always });
|
||||||
|
CompareTestDataWithWritingOptions(
|
||||||
|
expected,
|
||||||
|
actual,
|
||||||
|
new MatFileWriterOptions { UseCompression = CompressionUsage.Never });
|
||||||
|
}
|
||||||
|
|
||||||
|
private ComplexOf<T>[] CreateComplexLimits<T>(T[] limits)
|
||||||
|
where T : struct
|
||||||
{
|
{
|
||||||
return new[] { new ComplexOf<T>(limits[0], limits[1]), new ComplexOf<T>(limits[1], limits[0]) };
|
return new[] { new ComplexOf<T>(limits[0], limits[1]), new ComplexOf<T>(limits[1], limits[0]) };
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
namespace MatFileHandler.Tests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Method of writing .mat files for testing.
|
|
||||||
/// </summary>
|
|
||||||
public enum MatFileWritingMethod
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Undefined.
|
|
||||||
/// </summary>
|
|
||||||
Undefined = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Normal stream (like memory or file stream).
|
|
||||||
/// </summary>
|
|
||||||
NormalStream,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A stream that cannot be seeked (like a deflate stream).
|
|
||||||
/// </summary>
|
|
||||||
UnseekableStream,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unaligned stream (what happens if the data don't start at the beginning?).
|
|
||||||
/// </summary>
|
|
||||||
UnalignedStream,
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler.Tests;
|
|
||||||
|
|
||||||
internal static class MatFileWritingMethods
|
|
||||||
{
|
|
||||||
public static byte[] WriteMatFile(MatFileWritingMethod method, MatFileWriterOptionsForTests options, IMatFile matFile)
|
|
||||||
{
|
|
||||||
switch (method)
|
|
||||||
{
|
|
||||||
case MatFileWritingMethod.NormalStream:
|
|
||||||
{
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
var matFileWriter = CreateWriter(options, memoryStream);
|
|
||||||
matFileWriter.Write(matFile);
|
|
||||||
return memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
case MatFileWritingMethod.UnseekableStream:
|
|
||||||
{
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
using var unseekableStream = new UnseekableWriteStream(memoryStream);
|
|
||||||
var matFileWriter = CreateWriter(options, unseekableStream);
|
|
||||||
matFileWriter.Write(matFile);
|
|
||||||
return memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
case MatFileWritingMethod.UnalignedStream:
|
|
||||||
{
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
memoryStream.Seek(3, SeekOrigin.Begin);
|
|
||||||
var matFileWriter = CreateWriter(options, memoryStream);
|
|
||||||
matFileWriter.Write(matFile);
|
|
||||||
var fullArray = memoryStream.ToArray();
|
|
||||||
var length = fullArray.Length - 3;
|
|
||||||
var result = new byte[length];
|
|
||||||
Buffer.BlockCopy(fullArray, 3, result, 0, length);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MatFileWriter CreateWriter(MatFileWriterOptionsForTests options, Stream stream)
|
|
||||||
{
|
|
||||||
return options switch
|
|
||||||
{
|
|
||||||
MatFileWriterOptionsForTests.None => new MatFileWriter(stream),
|
|
||||||
MatFileWriterOptionsForTests.Always => new MatFileWriter(
|
|
||||||
stream,
|
|
||||||
new MatFileWriterOptions { UseCompression = CompressionUsage.Always }),
|
|
||||||
MatFileWriterOptionsForTests.Never => new MatFileWriter(
|
|
||||||
stream,
|
|
||||||
new MatFileWriterOptions { UseCompression = CompressionUsage.Never }),
|
|
||||||
_ => throw new NotImplementedException(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
35
MatFileHandler.Tests/MatTestDataFactory.cs
Executable file
35
MatFileHandler.Tests/MatTestDataFactory.cs
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MatFileHandler.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Factory providing the parsed contents of .mat files.
|
||||||
|
/// </summary>
|
||||||
|
public class MatTestDataFactory : AbstractTestDataFactory<IMatFile>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MatTestDataFactory"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="testDirectory">Directory containing test files.</param>
|
||||||
|
public MatTestDataFactory(string testDirectory)
|
||||||
|
: base(
|
||||||
|
testDirectory,
|
||||||
|
new ExtensionTestFilenameConvention("mat"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and parse data from a .mat file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">Input stream.</param>
|
||||||
|
/// <returns>Parsed contents of the file.</returns>
|
||||||
|
protected override IMatFile ReadDataFromStream(Stream stream)
|
||||||
|
{
|
||||||
|
var matFileReader = new MatFileReader(stream);
|
||||||
|
var matFile = matFileReader.Read();
|
||||||
|
return matFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A stream which wraps another stream and only reads one byte at a time,
|
|
||||||
/// while forbidding seeking in it.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class PartialUnseekableReadStream : Stream
|
|
||||||
{
|
|
||||||
private readonly Stream _baseStream;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="PartialUnseekableReadStream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseStream">The stream to wrap.</param>
|
|
||||||
public PartialUnseekableReadStream(Stream baseStream)
|
|
||||||
{
|
|
||||||
_baseStream = baseStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanRead => _baseStream.CanRead;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Length => _baseStream.Length;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => throw new NotSupportedException();
|
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
_baseStream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
return _baseStream.Read(buffer, offset, Math.Min(1, count));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_baseStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler.Tests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A stream which wraps another stream and forbids seeking in it.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class UnseekableWriteStream : Stream
|
|
||||||
{
|
|
||||||
public UnseekableWriteStream(Stream baseStream)
|
|
||||||
{
|
|
||||||
_baseStream = baseStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Stream _baseStream;
|
|
||||||
|
|
||||||
public override bool CanRead => false;
|
|
||||||
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
public override bool CanWrite => _baseStream.CanWrite;
|
|
||||||
|
|
||||||
public override long Length => _baseStream.Length;
|
|
||||||
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => throw new NotSupportedException();
|
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
_baseStream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
_baseStream.Write(buffer, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_baseStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A stream that calculates Adler32 checksum of everything
|
|
||||||
/// written to it before passing to another stream.
|
|
||||||
/// </summary>
|
|
||||||
internal class ChecksumCalculatingStream : Stream
|
|
||||||
{
|
|
||||||
private const uint BigPrime = 0xFFF1;
|
|
||||||
private readonly Stream _stream;
|
|
||||||
private uint s1;
|
|
||||||
private uint s2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ChecksumCalculatingStream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">Wrapped stream.</param>
|
|
||||||
public ChecksumCalculatingStream(Stream stream)
|
|
||||||
{
|
|
||||||
_stream = stream;
|
|
||||||
s1 = 1;
|
|
||||||
s2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanRead => false;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanWrite => true;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override long Length => throw new NotImplementedException();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => throw new NotImplementedException();
|
|
||||||
set => throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
_stream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
for (var i = offset; i < offset + count; i++)
|
|
||||||
{
|
|
||||||
s1 = (s1 + buffer[i]) % BigPrime;
|
|
||||||
s2 = (s2 + s1) % BigPrime;
|
|
||||||
}
|
|
||||||
|
|
||||||
_stream.Write(buffer, offset, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculate the checksum of everything written to the stream so far.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Checksum of everything written to the stream so far.</returns>
|
|
||||||
public uint GetCrc()
|
|
||||||
{
|
|
||||||
return (s2 << 16) | s1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
@ -6,7 +8,7 @@ namespace MatFileHandler
|
|||||||
/// A structure representing a complex number where real and imaginary parts are of type T.
|
/// A structure representing a complex number where real and imaginary parts are of type T.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of real and imaginary parts.</typeparam>
|
/// <typeparam name="T">Type of real and imaginary parts.</typeparam>
|
||||||
public readonly struct ComplexOf<T> : IEquatable<ComplexOf<T>>
|
public struct ComplexOf<T> : IEquatable<ComplexOf<T>>
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -69,11 +71,10 @@ namespace MatFileHandler
|
|||||||
/// <returns>True iff another object is a complex number equal to this.</returns>
|
/// <returns>True iff another object is a complex number equal to this.</returns>
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
if (ReferenceEquals(null, obj))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj is ComplexOf<T> other && Equals(other);
|
return obj is ComplexOf<T> other && Equals(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
#pragma warning disable CA1822
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -51,7 +52,7 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
if (data.Length != dimensions.NumberOfElements())
|
if (data.Length != dimensions.NumberOfElements())
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Data size does not match the specified dimensions", nameof(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>(GetStandardFlags<T>(), dimensions, string.Empty, data);
|
||||||
}
|
}
|
||||||
@ -156,7 +157,7 @@ namespace MatFileHandler
|
|||||||
return new MatFile(variables);
|
return new MatFile(variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayFlags ConstructArrayFlags(ArrayType class_, bool isComplex = false, bool isLogical = false)
|
private ArrayFlags ConstructArrayFlags(ArrayType class_, bool isComplex = false, bool isLogical = false)
|
||||||
{
|
{
|
||||||
return new ArrayFlags
|
return new ArrayFlags
|
||||||
{
|
{
|
||||||
@ -166,7 +167,7 @@ namespace MatFileHandler
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayFlags GetStandardFlags<T>()
|
private ArrayFlags GetStandardFlags<T>()
|
||||||
{
|
{
|
||||||
if (typeof(T) == typeof(sbyte))
|
if (typeof(T) == typeof(sbyte))
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -69,21 +71,16 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
throw new NotSupportedException("Only 2-dimensional sparse arrays are supported");
|
throw new NotSupportedException("Only 2-dimensional sparse arrays are supported");
|
||||||
}
|
}
|
||||||
if (data is null)
|
if (data == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Null data found.", nameof(data));
|
throw new ArgumentException("Null data found.", "data");
|
||||||
}
|
}
|
||||||
|
var elements =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var maybeElements =
|
|
||||||
ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical));
|
ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical));
|
||||||
if (maybeElements is not { } elements)
|
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]);
|
ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
|
||||||
return new MatSparseArrayOf<T>(flags, dimensions, name, dataDictionary);
|
return new MatSparseArrayOf<T>(flags, dimensions, name, dataDictionary);
|
||||||
@ -120,12 +117,15 @@ namespace MatFileHandler
|
|||||||
switch (flags.Class)
|
switch (flags.Class)
|
||||||
{
|
{
|
||||||
case ArrayType.MxChar:
|
case ArrayType.MxChar:
|
||||||
return realData switch
|
switch (realData)
|
||||||
{
|
{
|
||||||
MiNum<byte> dataByte => ConvertToMatCharArray(flags, dimensions, name, dataByte),
|
case MiNum<byte> dataByte:
|
||||||
MiNum<ushort> dataUshort => ConvertToMatCharArray(flags, dimensions, name, dataUshort),
|
return ConvertToMatCharArray(flags, dimensions, name, dataByte);
|
||||||
_ => throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported."),
|
case MiNum<ushort> dataUshort:
|
||||||
};
|
return ConvertToMatCharArray(flags, dimensions, name, dataUshort);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported.");
|
||||||
|
}
|
||||||
case ArrayType.MxDouble:
|
case ArrayType.MxDouble:
|
||||||
case ArrayType.MxSingle:
|
case ArrayType.MxSingle:
|
||||||
case ArrayType.MxInt8:
|
case ArrayType.MxInt8:
|
||||||
@ -184,12 +184,13 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
return DataExtraction.GetDataAsUInt8(data).Select(x => x != 0).ToArray() as T[];
|
return DataExtraction.GetDataAsUInt8(data).Select(x => x != 0).ToArray() as T[];
|
||||||
}
|
}
|
||||||
|
switch (data)
|
||||||
return data switch
|
|
||||||
{
|
{
|
||||||
MiNum<double> => DataExtraction.GetDataAsDouble(data) as T[],
|
case MiNum<double> _:
|
||||||
_ => throw new NotSupportedException(),
|
return DataExtraction.GetDataAsDouble(data) as T[];
|
||||||
};
|
default:
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MatCharArrayOf<ushort> ConvertToMatCharArray(
|
private static MatCharArrayOf<ushort> ConvertToMatCharArray(
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -28,33 +30,54 @@ 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 DataElement Read(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var maybeTagPair = ReadTag(reader);
|
var (dataReader, tag) = ReadTag(reader);
|
||||||
if (maybeTagPair is not { } tagPair)
|
DataElement result;
|
||||||
|
switch (tag.Type)
|
||||||
{
|
{
|
||||||
return null;
|
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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var (dataReader, tag) = tagPair;
|
|
||||||
|
|
||||||
var result = tag.Type switch
|
|
||||||
{
|
|
||||||
DataType.MiInt8 => ReadNum<sbyte>(tag, dataReader),
|
|
||||||
DataType.MiUInt8 or DataType.MiUtf8 => ReadNum<byte>(tag, dataReader),
|
|
||||||
DataType.MiInt16 => ReadNum<short>(tag, dataReader),
|
|
||||||
DataType.MiUInt16 or DataType.MiUtf16 => ReadNum<ushort>(tag, dataReader),
|
|
||||||
DataType.MiInt32 => ReadNum<int>(tag, dataReader),
|
|
||||||
DataType.MiUInt32 => ReadNum<uint>(tag, dataReader),
|
|
||||||
DataType.MiSingle => ReadNum<float>(tag, dataReader),
|
|
||||||
DataType.MiDouble => ReadNum<double>(tag, dataReader),
|
|
||||||
DataType.MiInt64 => ReadNum<long>(tag, dataReader),
|
|
||||||
DataType.MiUInt64 => ReadNum<ulong>(tag, dataReader),
|
|
||||||
DataType.MiMatrix => ReadMatrix(tag, dataReader),
|
|
||||||
DataType.MiCompressed => ReadCompressed(tag, dataReader),
|
|
||||||
_ => 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;
|
||||||
@ -99,7 +122,7 @@ namespace MatFileHandler
|
|||||||
private static ArrayFlags ReadArrayFlags(DataElement element)
|
private static ArrayFlags ReadArrayFlags(DataElement element)
|
||||||
{
|
{
|
||||||
var flagData = (element as MiNum<uint>)?.Data ??
|
var flagData = (element as MiNum<uint>)?.Data ??
|
||||||
throw new HandlerException("Unexpected type in array flags.");
|
throw new HandlerException("Unexpected type in array flags.");
|
||||||
var class_ = (ArrayType)(flagData[0] & 0xff);
|
var class_ = (ArrayType)(flagData[0] & 0xff);
|
||||||
var variableFlags = (flagData[0] >> 8) & 0x0e;
|
var variableFlags = (flagData[0] >> 8) & 0x0e;
|
||||||
return new ArrayFlags
|
return new ArrayFlags
|
||||||
@ -171,31 +194,9 @@ namespace MatFileHandler
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int? TryReadInt32(BinaryReader reader)
|
private static (BinaryReader reader, Tag tag) ReadTag(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var buffer = new byte[4];
|
var type = reader.ReadInt32();
|
||||||
var position = 0;
|
|
||||||
while (position < 4)
|
|
||||||
{
|
|
||||||
var actually = reader.BaseStream.Read(buffer, position, 4 - position);
|
|
||||||
if (actually == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
position += actually;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BitConverter.ToInt32(buffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (BinaryReader reader, Tag tag)? ReadTag(BinaryReader reader)
|
|
||||||
{
|
|
||||||
var maybeType = TryReadInt32(reader);
|
|
||||||
if (maybeType is not int type)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeHi = type >> 16;
|
var typeHi = type >> 16;
|
||||||
if (typeHi == 0)
|
if (typeHi == 0)
|
||||||
{
|
{
|
||||||
@ -205,13 +206,13 @@ namespace MatFileHandler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var length = typeHi;
|
var length = typeHi;
|
||||||
type &= 0xffff;
|
type = type & 0xffff;
|
||||||
var smallReader = new BinaryReader(new MemoryStream(reader.ReadBytes(4)));
|
var smallReader = new BinaryReader(new MemoryStream(reader.ReadBytes(4)));
|
||||||
return (smallReader, new Tag((DataType)type, length));
|
return (smallReader, new Tag((DataType)type, length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatCellArray ContinueReadingCellArray(
|
private DataElement ContinueReadingCellArray(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
ArrayFlags flags,
|
ArrayFlags flags,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
@ -240,7 +241,7 @@ namespace MatFileHandler
|
|||||||
var classNameElement = Read(reader) as MiNum<sbyte> ??
|
var classNameElement = Read(reader) 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) ?? throw new HandlerException("Missing opaque data element.");
|
var dataElement = Read(reader);
|
||||||
var data = ReadData(dataElement);
|
var data = ReadData(dataElement);
|
||||||
if (data is MatNumericalArrayOf<uint> linkElement)
|
if (data is MatNumericalArrayOf<uint> linkElement)
|
||||||
{
|
{
|
||||||
@ -257,11 +258,11 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Opaque(name, typeDescription, className, Array.Empty<int>(), data, subsystemData);
|
return new Opaque(name, typeDescription, className, new int[] { }, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatArray ContinueReadingSparseArray(
|
private DataElement ContinueReadingSparseArray(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
DataElement firstElement,
|
DataElement firstElement,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
@ -272,7 +273,7 @@ namespace MatFileHandler
|
|||||||
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) 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) ?? throw new HandlerException("Missing sparse array data.");
|
var data = Read(reader);
|
||||||
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsLogical))
|
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsLogical))
|
||||||
{
|
{
|
||||||
return DataElementConverter.ConvertToMatSparseArrayOf<bool>(
|
return DataElementConverter.ConvertToMatSparseArrayOf<bool>(
|
||||||
@ -286,7 +287,7 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsComplex))
|
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsComplex))
|
||||||
{
|
{
|
||||||
var imaginaryData = Read(reader) ?? throw new HandlerException("Missing imaginary part of sparse array data.");
|
var imaginaryData = Read(reader);
|
||||||
return DataElementConverter.ConvertToMatSparseArrayOfComplex(
|
return DataElementConverter.ConvertToMatSparseArrayOfComplex(
|
||||||
sparseArrayFlags,
|
sparseArrayFlags,
|
||||||
dimensions,
|
dimensions,
|
||||||
@ -297,20 +298,22 @@ namespace MatFileHandler
|
|||||||
imaginaryData);
|
imaginaryData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data switch
|
switch (data)
|
||||||
{
|
{
|
||||||
MiNum<double> => DataElementConverter.ConvertToMatSparseArrayOf<double>(
|
case MiNum<double> _:
|
||||||
sparseArrayFlags,
|
return DataElementConverter.ConvertToMatSparseArrayOf<double>(
|
||||||
dimensions,
|
sparseArrayFlags,
|
||||||
name,
|
dimensions,
|
||||||
rowIndex.Data,
|
name,
|
||||||
columnIndex.Data,
|
rowIndex.Data,
|
||||||
data),
|
columnIndex.Data,
|
||||||
_ => throw new NotSupportedException("Only double and logical sparse arrays are supported."),
|
data);
|
||||||
};
|
default:
|
||||||
|
throw new NotSupportedException("Only double and logical sparse arrays are supported.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatStructureArray ContinueReadingStructure(
|
private DataElement ContinueReadingStructure(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
ArrayFlags flags,
|
ArrayFlags flags,
|
||||||
int[] dimensions,
|
int[] dimensions,
|
||||||
@ -340,33 +343,31 @@ namespace MatFileHandler
|
|||||||
return new MatStructureArray(flags, dimensions, name, fields);
|
return new MatStructureArray(flags, dimensions, name, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataElement Read(Stream stream)
|
||||||
|
{
|
||||||
|
using (var reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
return Read(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DataElement ReadCompressed(Tag tag, BinaryReader reader)
|
private DataElement ReadCompressed(Tag tag, BinaryReader reader)
|
||||||
{
|
{
|
||||||
reader.ReadBytes(2);
|
reader.ReadBytes(2);
|
||||||
|
var compressedData = new byte[tag.Length - 6];
|
||||||
DataElement element;
|
reader.BaseStream.Read(compressedData, 0, tag.Length - 6);
|
||||||
|
reader.ReadBytes(4);
|
||||||
using (var substream = new Substream(reader.BaseStream, tag.Length - 6))
|
var resultStream = new MemoryStream();
|
||||||
|
using (var compressedStream = new MemoryStream(compressedData))
|
||||||
{
|
{
|
||||||
using (var deflateStream = new DeflateStream(substream, CompressionMode.Decompress))
|
using (var stream = new DeflateStream(compressedStream, CompressionMode.Decompress, leaveOpen: true))
|
||||||
using (var bufferedStream = new BufferedStream(deflateStream))
|
|
||||||
using (var positionTrackingStream = new PositionTrackingStream(bufferedStream))
|
|
||||||
using (var innerReader = new BinaryReader(positionTrackingStream))
|
|
||||||
{
|
{
|
||||||
element = Read(innerReader) ?? throw new HandlerException("Missing compressed data.");
|
stream.CopyTo(resultStream);
|
||||||
}
|
|
||||||
|
|
||||||
if (substream.Position != substream.Length)
|
|
||||||
{
|
|
||||||
// In the pathological case that the deflate stream did not read the full
|
|
||||||
// length, then read out the rest manually (normally 1 byte).
|
|
||||||
reader.ReadBytes((int)(substream.Length - substream.Position));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.ReadBytes(4);
|
resultStream.Position = 0;
|
||||||
|
return Read(resultStream);
|
||||||
return element;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataElement ReadMatrix(Tag tag, BinaryReader reader)
|
private DataElement ReadMatrix(Tag tag, BinaryReader reader)
|
||||||
@ -376,7 +377,7 @@ namespace MatFileHandler
|
|||||||
return MatArray.Empty();
|
return MatArray.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var element1 = Read(reader) ?? throw new HandlerException("Missing matrix data.");
|
var element1 = Read(reader);
|
||||||
var flags = ReadArrayFlags(element1);
|
var flags = ReadArrayFlags(element1);
|
||||||
if (flags.Class == ArrayType.MxOpaque)
|
if (flags.Class == ArrayType.MxOpaque)
|
||||||
{
|
{
|
||||||
@ -398,12 +399,12 @@ namespace MatFileHandler
|
|||||||
return ContinueReadingSparseArray(reader, element1, dimensions, name);
|
return ContinueReadingSparseArray(reader, element1, dimensions, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var element4 = Read(reader) ?? throw new HandlerException("Missing matrix data.");
|
var element4 = Read(reader);
|
||||||
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) ?? throw new HandlerException("Missing complex matrix data.");
|
var element5 = Read(reader);
|
||||||
imaginaryData = ReadData(element5);
|
imaginaryData = ReadData(element5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,23 +419,26 @@ namespace MatFileHandler
|
|||||||
switch (flags.Class)
|
switch (flags.Class)
|
||||||
{
|
{
|
||||||
case ArrayType.MxChar:
|
case ArrayType.MxChar:
|
||||||
return data switch
|
switch (data)
|
||||||
{
|
{
|
||||||
MiNum<byte> => DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
case MiNum<byte> _:
|
||||||
flags,
|
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
|
||||||
dimensions,
|
flags,
|
||||||
name,
|
dimensions,
|
||||||
data,
|
name,
|
||||||
imaginaryData),
|
data,
|
||||||
MiNum<ushort> => DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
imaginaryData);
|
||||||
flags,
|
case MiNum<ushort> _:
|
||||||
dimensions,
|
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
|
||||||
name,
|
flags,
|
||||||
data,
|
dimensions,
|
||||||
imaginaryData),
|
name,
|
||||||
_ => throw new NotSupportedException(
|
data,
|
||||||
$"This type of char array ({data.GetType()}) is not supported."),
|
imaginaryData);
|
||||||
};
|
default:
|
||||||
|
throw new NotSupportedException(
|
||||||
|
$"This type of char array ({data.GetType()}) is not supported.");
|
||||||
|
}
|
||||||
case ArrayType.MxInt8:
|
case ArrayType.MxInt8:
|
||||||
return DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
|
return DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
|
||||||
flags,
|
flags,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
@ -14,21 +16,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Double.</returns>
|
/// <returns>Contents of the elements, converted to Double.</returns>
|
||||||
public static double[] GetDataAsDouble(DataElement element)
|
public static double[] GetDataAsDouble(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToDouble(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToDouble(byteElement.Data),
|
return SbyteToDouble(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToDouble(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToDouble(uintElement.Data),
|
return ByteToDouble(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToDouble(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToDouble(ushortElement.Data),
|
return IntToDouble(intElement.Data);
|
||||||
MiNum<long> longElement => LongToDouble(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToDouble(ulongElement.Data),
|
return UintToDouble(uintElement.Data);
|
||||||
MiNum<float> floatElement => FloatToDouble(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => doubleElement.Data,
|
return ShortToDouble(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to double, found {element.GetType()}."),
|
return UshortToDouble(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToDouble(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToDouble(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return FloatToDouble(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return doubleElement.Data;
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to double, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -38,21 +50,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Single.</returns>
|
/// <returns>Contents of the elements, converted to Single.</returns>
|
||||||
public static float[] GetDataAsSingle(DataElement element)
|
public static float[] GetDataAsSingle(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToSingle(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToSingle(byteElement.Data),
|
return SbyteToSingle(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToSingle(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToSingle(uintElement.Data),
|
return ByteToSingle(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToSingle(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToSingle(ushortElement.Data),
|
return IntToSingle(intElement.Data);
|
||||||
MiNum<long> longElement => LongToSingle(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToSingle(ulongElement.Data),
|
return UintToSingle(uintElement.Data);
|
||||||
MiNum<float> floatElement => floatElement.Data,
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToSingle(doubleElement.Data),
|
return ShortToSingle(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to float, found {element.GetType()}."),
|
return UshortToSingle(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToSingle(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToSingle(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return floatElement.Data;
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToSingle(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to float, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -62,21 +84,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Int8.</returns>
|
/// <returns>Contents of the elements, converted to Int8.</returns>
|
||||||
public static sbyte[] GetDataAsInt8(DataElement element)
|
public static sbyte[] GetDataAsInt8(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => sbyteElement.Data,
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToSByte(byteElement.Data),
|
return sbyteElement.Data;
|
||||||
MiNum<int> intElement => IntToSByte(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToSByte(uintElement.Data),
|
return ByteToSByte(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToSByte(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToSByte(ushortElement.Data),
|
return IntToSByte(intElement.Data);
|
||||||
MiNum<long> longElement => LongToSByte(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToSByte(ulongElement.Data),
|
return UintToSByte(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToSByte(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToSByte(doubleElement.Data),
|
return ShortToSByte(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to int8, found {element.GetType()}."),
|
return UshortToSByte(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToSByte(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToSByte(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToSByte(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToSByte(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to int8, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -86,21 +118,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to UInt8.</returns>
|
/// <returns>Contents of the elements, converted to UInt8.</returns>
|
||||||
public static byte[] GetDataAsUInt8(DataElement element)
|
public static byte[] GetDataAsUInt8(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToByte(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => byteElement.Data,
|
return SbyteToByte(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToByte(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToByte(uintElement.Data),
|
return byteElement.Data;
|
||||||
MiNum<short> shortElement => ShortToByte(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToByte(ushortElement.Data),
|
return IntToByte(intElement.Data);
|
||||||
MiNum<long> longElement => LongToByte(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToByte(ulongElement.Data),
|
return UintToByte(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToByte(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToByte(doubleElement.Data),
|
return ShortToByte(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to uint8, found {element.GetType()}."),
|
return UshortToByte(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToByte(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToByte(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToByte(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToByte(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to uint8, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -110,21 +152,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Int16.</returns>
|
/// <returns>Contents of the elements, converted to Int16.</returns>
|
||||||
public static short[] GetDataAsInt16(DataElement element)
|
public static short[] GetDataAsInt16(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToInt16(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToInt16(byteElement.Data),
|
return SbyteToInt16(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToInt16(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToInt16(uintElement.Data),
|
return ByteToInt16(byteElement.Data);
|
||||||
MiNum<short> shortElement => shortElement.Data,
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToInt16(ushortElement.Data),
|
return IntToInt16(intElement.Data);
|
||||||
MiNum<long> longElement => LongToInt16(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToInt16(ulongElement.Data),
|
return UintToInt16(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToInt16(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToInt16(doubleElement.Data),
|
return shortElement.Data;
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to int16, found {element.GetType()}."),
|
return UshortToInt16(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToInt16(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToInt16(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToInt16(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToInt16(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to int16, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -134,21 +186,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to UInt16.</returns>
|
/// <returns>Contents of the elements, converted to UInt16.</returns>
|
||||||
public static ushort[] GetDataAsUInt16(DataElement element)
|
public static ushort[] GetDataAsUInt16(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToUInt16(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToUInt16(byteElement.Data),
|
return SbyteToUInt16(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToUInt16(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToUInt16(uintElement.Data),
|
return ByteToUInt16(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToUInt16(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => ushortElement.Data,
|
return IntToUInt16(intElement.Data);
|
||||||
MiNum<long> longElement => LongToUInt16(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToUInt16(ulongElement.Data),
|
return UintToUInt16(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToUInt16(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToUInt16(doubleElement.Data),
|
return ShortToUInt16(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to uint16, found {element.GetType()}."),
|
return ushortElement.Data;
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToUInt16(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToUInt16(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToUInt16(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToUInt16(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to uint16, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -158,21 +220,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Int32.</returns>
|
/// <returns>Contents of the elements, converted to Int32.</returns>
|
||||||
public static int[] GetDataAsInt32(DataElement element)
|
public static int[] GetDataAsInt32(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToInt32(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToInt32(byteElement.Data),
|
return SbyteToInt32(sbyteElement.Data);
|
||||||
MiNum<int> intElement => intElement.Data,
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToInt32(uintElement.Data),
|
return ByteToInt32(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToInt32(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToInt32(ushortElement.Data),
|
return intElement.Data;
|
||||||
MiNum<long> longElement => LongToInt32(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToInt32(ulongElement.Data),
|
return UintToInt32(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToInt32(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToInt32(doubleElement.Data),
|
return ShortToInt32(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to int32, found {element.GetType()}."),
|
return UshortToInt32(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToInt32(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToInt32(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToInt32(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToInt32(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to int32, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -182,21 +254,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to UInt32.</returns>
|
/// <returns>Contents of the elements, converted to UInt32.</returns>
|
||||||
public static uint[] GetDataAsUInt32(DataElement element)
|
public static uint[] GetDataAsUInt32(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToUInt32(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToUInt32(byteElement.Data),
|
return SbyteToUInt32(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToUInt32(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => uintElement.Data,
|
return ByteToUInt32(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToUInt32(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToUInt32(ushortElement.Data),
|
return IntToUInt32(intElement.Data);
|
||||||
MiNum<long> longElement => LongToUInt32(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToUInt32(ulongElement.Data),
|
return uintElement.Data;
|
||||||
MiNum<float> floatElement => SingleToUInt32(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToUInt32(doubleElement.Data),
|
return ShortToUInt32(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to uint32, found {element.GetType()}."),
|
return UshortToUInt32(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToUInt32(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToUInt32(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToUInt32(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToUInt32(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to uint32, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -206,21 +288,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to Int64.</returns>
|
/// <returns>Contents of the elements, converted to Int64.</returns>
|
||||||
public static long[] GetDataAsInt64(DataElement element)
|
public static long[] GetDataAsInt64(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToInt64(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToInt64(byteElement.Data),
|
return SbyteToInt64(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToInt64(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToInt64(uintElement.Data),
|
return ByteToInt64(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToInt64(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToInt64(ushortElement.Data),
|
return IntToInt64(intElement.Data);
|
||||||
MiNum<long> longElement => longElement.Data,
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => UlongToInt64(ulongElement.Data),
|
return UintToInt64(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToInt64(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToInt64(doubleElement.Data),
|
return ShortToInt64(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to int64, found {element.GetType()}."),
|
return UshortToInt64(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return longElement.Data;
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return UlongToInt64(ulongElement.Data);
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToInt64(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToInt64(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to int64, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -230,21 +322,31 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the elements, converted to UInt64.</returns>
|
/// <returns>Contents of the elements, converted to UInt64.</returns>
|
||||||
public static ulong[] GetDataAsUInt64(DataElement element)
|
public static ulong[] GetDataAsUInt64(DataElement element)
|
||||||
{
|
{
|
||||||
return element switch
|
switch (element)
|
||||||
{
|
{
|
||||||
MiNum<sbyte> sbyteElement => SbyteToUInt64(sbyteElement.Data),
|
case MiNum<sbyte> sbyteElement:
|
||||||
MiNum<byte> byteElement => ByteToUInt64(byteElement.Data),
|
return SbyteToUInt64(sbyteElement.Data);
|
||||||
MiNum<int> intElement => IntToUInt64(intElement.Data),
|
case MiNum<byte> byteElement:
|
||||||
MiNum<uint> uintElement => UintToUInt64(uintElement.Data),
|
return ByteToUInt64(byteElement.Data);
|
||||||
MiNum<short> shortElement => ShortToUInt64(shortElement.Data),
|
case MiNum<int> intElement:
|
||||||
MiNum<ushort> ushortElement => UshortToUInt64(ushortElement.Data),
|
return IntToUInt64(intElement.Data);
|
||||||
MiNum<long> longElement => LongToUInt64(longElement.Data),
|
case MiNum<uint> uintElement:
|
||||||
MiNum<ulong> ulongElement => ulongElement.Data,
|
return UintToUInt64(uintElement.Data);
|
||||||
MiNum<float> floatElement => SingleToUInt64(floatElement.Data),
|
case MiNum<short> shortElement:
|
||||||
MiNum<double> doubleElement => DoubleToUInt64(doubleElement.Data),
|
return ShortToUInt64(shortElement.Data);
|
||||||
_ => throw new HandlerException(
|
case MiNum<ushort> ushortElement:
|
||||||
$"Expected data element that would be convertible to uint64, found {element.GetType()}."),
|
return UshortToUInt64(ushortElement.Data);
|
||||||
};
|
case MiNum<long> longElement:
|
||||||
|
return LongToUInt64(longElement.Data);
|
||||||
|
case MiNum<ulong> ulongElement:
|
||||||
|
return ulongElement.Data;
|
||||||
|
case MiNum<float> floatElement:
|
||||||
|
return SingleToUInt64(floatElement.Data);
|
||||||
|
case MiNum<double> doubleElement:
|
||||||
|
return DoubleToUInt64(doubleElement.Data);
|
||||||
|
}
|
||||||
|
throw new HandlerException(
|
||||||
|
$"Expected data element that would be convertible to uint64, found {element.GetType()}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// * to double
|
// * to double
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
@ -14,21 +16,41 @@ namespace MatFileHandler
|
|||||||
/// <returns>Size in bytes.</returns>
|
/// <returns>Size in bytes.</returns>
|
||||||
public static int Size(this DataType type)
|
public static int Size(this DataType type)
|
||||||
{
|
{
|
||||||
return type switch
|
switch (type)
|
||||||
{
|
{
|
||||||
DataType.MiInt8 or DataType.MiUInt8 => 1,
|
case DataType.MiInt8:
|
||||||
DataType.MiInt16 or DataType.MiUInt16 => 2,
|
return 1;
|
||||||
DataType.MiInt32 or DataType.MiUInt32 => 4,
|
case DataType.MiUInt8:
|
||||||
DataType.MiSingle => 4,
|
return 1;
|
||||||
DataType.MiDouble => 8,
|
case DataType.MiInt16:
|
||||||
DataType.MiInt64 or DataType.MiUInt64 => 8,
|
return 2;
|
||||||
DataType.MiMatrix => 0,
|
case DataType.MiUInt16:
|
||||||
DataType.MiCompressed => 0,
|
return 2;
|
||||||
DataType.MiUtf8 => 1,
|
case DataType.MiInt32:
|
||||||
DataType.MiUtf16 => 2,
|
return 4;
|
||||||
DataType.MiUtf32 => 4,
|
case DataType.MiUInt32:
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
|
return 4;
|
||||||
};
|
case DataType.MiSingle:
|
||||||
|
return 4;
|
||||||
|
case DataType.MiDouble:
|
||||||
|
return 8;
|
||||||
|
case DataType.MiInt64:
|
||||||
|
return 8;
|
||||||
|
case DataType.MiUInt64:
|
||||||
|
return 8;
|
||||||
|
case DataType.MiMatrix:
|
||||||
|
return 0;
|
||||||
|
case DataType.MiCompressed:
|
||||||
|
return 0;
|
||||||
|
case DataType.MiUtf8:
|
||||||
|
return 1;
|
||||||
|
case DataType.MiUtf16:
|
||||||
|
return 2;
|
||||||
|
case DataType.MiUtf32:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@ -10,6 +12,8 @@ namespace MatFileHandler
|
|||||||
public class DatetimeAdapter
|
public class DatetimeAdapter
|
||||||
{
|
{
|
||||||
private readonly double[] data;
|
private readonly double[] data;
|
||||||
|
private readonly double[] data2;
|
||||||
|
private readonly int[] dimensions;
|
||||||
|
|
||||||
private readonly DateTimeOffset epoch;
|
private readonly DateTimeOffset epoch;
|
||||||
|
|
||||||
@ -32,13 +36,15 @@ namespace MatFileHandler
|
|||||||
case IArrayOf<double> dataArray:
|
case IArrayOf<double> dataArray:
|
||||||
data = dataArray.ConvertToDoubleArray()
|
data = dataArray.ConvertToDoubleArray()
|
||||||
?? throw new HandlerException("Cannot extract data for the datetime adapter.");
|
?? throw new HandlerException("Cannot extract data for the datetime adapter.");
|
||||||
Dimensions = dataArray.Dimensions;
|
data2 = new double[data.Length];
|
||||||
|
dimensions = dataArray.Dimensions;
|
||||||
break;
|
break;
|
||||||
case IArrayOf<Complex> dataComplex:
|
case IArrayOf<Complex> dataComplex:
|
||||||
var complexData = dataComplex.ConvertToComplexArray()
|
var complexData = dataComplex.ConvertToComplexArray()
|
||||||
?? throw new HandlerException("Cannot extract data for the datetime adapter.");
|
?? throw new HandlerException("Cannot extract data for the datetime adapter.");
|
||||||
data = complexData.Select(c => c.Real).ToArray();
|
data = complexData.Select(c => c.Real).ToArray();
|
||||||
Dimensions = dataComplex.Dimensions;
|
data2 = complexData.Select(c => c.Imaginary).ToArray();
|
||||||
|
dimensions = dataComplex.Dimensions;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new HandlerException("Datetime data not found.");
|
throw new HandlerException("Datetime data not found.");
|
||||||
@ -48,7 +54,7 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets datetime array dimensions.
|
/// Gets datetime array dimensions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int[] Dimensions { get; }
|
public int[] Dimensions => dimensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets values of datetime object at given position in the array converted to <see cref="DateTimeOffset"/>.
|
/// Gets values of datetime object at given position in the array converted to <see cref="DateTimeOffset"/>.
|
||||||
@ -60,11 +66,11 @@ namespace MatFileHandler
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var milliseconds = data[Dimensions.DimFlatten(list)];
|
var milliseconds = data[Dimensions.DimFlatten(list)];
|
||||||
return milliseconds switch
|
if (milliseconds < -62_135_596_800_000.0 || milliseconds > 253_402_300_799_999.0)
|
||||||
{
|
{
|
||||||
< -62_135_596_800_000.0 or > 253_402_300_799_999.0 => null,
|
return null;
|
||||||
_ => epoch.AddMilliseconds(milliseconds),
|
}
|
||||||
};
|
return epoch.AddMilliseconds(milliseconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
@ -7,6 +9,7 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DurationAdapter
|
public class DurationAdapter
|
||||||
{
|
{
|
||||||
|
private readonly int[] dimensions;
|
||||||
private readonly double[] data;
|
private readonly double[] data;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -24,13 +27,13 @@ namespace MatFileHandler
|
|||||||
var dataObject = matObject["millis", 0];
|
var dataObject = matObject["millis", 0];
|
||||||
data = dataObject.ConvertToDoubleArray()
|
data = dataObject.ConvertToDoubleArray()
|
||||||
?? throw new HandlerException("Cannot extract data for the duration adapter.");
|
?? throw new HandlerException("Cannot extract data for the duration adapter.");
|
||||||
Dimensions = dataObject.Dimensions;
|
dimensions = dataObject.Dimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets duration array dimensions.
|
/// Gets duration array dimensions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int[] Dimensions { get; }
|
public int[] Dimensions => dimensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets duration object at given position.
|
/// Gets duration object at given position.
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
namespace MatFileHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A better interface for using enum adapter.
|
|
||||||
/// </summary>
|
|
||||||
public class EnumAdapter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnumAdapter"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">Source enum object.</param>
|
|
||||||
public EnumAdapter(IArray array)
|
|
||||||
{
|
|
||||||
var matObject = array as Opaque;
|
|
||||||
if (matObject?.RawData is not IStructureArray rawData)
|
|
||||||
{
|
|
||||||
throw new HandlerException("Cannot extract data for the enum adapter.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawData["ValueNames"] is not IArrayOf<uint> valueNamesData)
|
|
||||||
{
|
|
||||||
throw new HandlerException("Cannot extract data for the enum adapter.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var numberOfNames = valueNamesData.Count;
|
|
||||||
var valueNames = new string[numberOfNames];
|
|
||||||
var names = matObject.SubsystemData.FieldNames;
|
|
||||||
for (var i = 0; i < numberOfNames; i++)
|
|
||||||
{
|
|
||||||
valueNames[i] = names[valueNamesData[i] - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawData["ValueIndices"] is not IArrayOf<uint> valueIndices)
|
|
||||||
{
|
|
||||||
throw new HandlerException("Cannot extract data for the enum adapter.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassName = matObject.ClassName;
|
|
||||||
ValueNames = valueNames;
|
|
||||||
Values = valueIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets name of the enumeration class.
|
|
||||||
/// </summary>
|
|
||||||
public string ClassName { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets names of the enumeration values.
|
|
||||||
/// </summary>
|
|
||||||
public string[] ValueNames { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets indices of values stored in the variable.
|
|
||||||
/// </summary>
|
|
||||||
public IArrayOf<uint> Values { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,391 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MatFileHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A simulated writer of .mat files that just calculate the length of data that would be written.
|
|
||||||
/// </summary>
|
|
||||||
internal class FakeWriter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets current position of the writer.
|
|
||||||
/// </summary>
|
|
||||||
public int Position { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write contents of a numerical array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">A numerical array.</param>
|
|
||||||
/// <param name="name">Name of the array.</param>
|
|
||||||
public void WriteNumericalArrayContents(IArray array, string name)
|
|
||||||
{
|
|
||||||
WriteArrayFlags();
|
|
||||||
WriteDimensions(array.Dimensions);
|
|
||||||
WriteName(name);
|
|
||||||
WriteNumericalArrayValues(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write contents of a char array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="charArray">A char array.</param>
|
|
||||||
/// <param name="name">Name of the array.</param>
|
|
||||||
public void WriteCharArrayContents(ICharArray charArray, string name)
|
|
||||||
{
|
|
||||||
WriteArrayFlags();
|
|
||||||
WriteDimensions(charArray.Dimensions);
|
|
||||||
WriteName(name);
|
|
||||||
WriteDataElement(GetLengthOfByteArray<ushort>(charArray.String.Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write contents of a sparse array.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">Array element type.</typeparam>
|
|
||||||
/// <param name="array">A sparse array.</param>
|
|
||||||
/// <param name="name">Name of the array.</param>
|
|
||||||
public void WriteSparseArrayContents<T>(
|
|
||||||
ISparseArrayOf<T> array,
|
|
||||||
string name)
|
|
||||||
where T : unmanaged, IEquatable<T>
|
|
||||||
{
|
|
||||||
(var rowsLength, var columnsLength, var dataLength, var nonZero) = PrepareSparseArrayData(array);
|
|
||||||
WriteSparseArrayFlags();
|
|
||||||
WriteDimensions(array.Dimensions);
|
|
||||||
WriteName(name);
|
|
||||||
WriteSparseArrayValues<T>(rowsLength, columnsLength, dataLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write contents of a structure array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">A structure array.</param>
|
|
||||||
/// <param name="name">Name of the array.</param>
|
|
||||||
public void WriteStructureArrayContents(IStructureArray array, string name)
|
|
||||||
{
|
|
||||||
WriteArrayFlags();
|
|
||||||
WriteDimensions(array.Dimensions);
|
|
||||||
WriteName(name);
|
|
||||||
WriteFieldNames(array.FieldNames);
|
|
||||||
WriteStructureArrayValues(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Write contents of a cell array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">A cell array.</param>
|
|
||||||
/// <param name="name">Name of the array.</param>
|
|
||||||
public void WriteCellArrayContents(ICellArray array, string name)
|
|
||||||
{
|
|
||||||
WriteArrayFlags();
|
|
||||||
WriteDimensions(array.Dimensions);
|
|
||||||
WriteName(name);
|
|
||||||
WriteCellArrayValues(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteTag()
|
|
||||||
{
|
|
||||||
Position += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteShortTag()
|
|
||||||
{
|
|
||||||
Position += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteWrappingContents<T>(T array, Action<FakeWriter> writeContents)
|
|
||||||
where T : IArray
|
|
||||||
{
|
|
||||||
if (array.IsEmpty)
|
|
||||||
{
|
|
||||||
WriteTag();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteTag();
|
|
||||||
writeContents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteNumericalArrayValues(IArray value)
|
|
||||||
{
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case IArrayOf<sbyte> sbyteArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<sbyte>(sbyteArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<byte> byteArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<byte>(byteArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<short> shortArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<short>(shortArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ushort> ushortArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<ushort>(ushortArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<int> intArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<int>(intArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<uint> uintArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<uint>(uintArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<long> longArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<long>(longArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ulong> ulongArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<ulong>(ulongArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<float> floatArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<float>(floatArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<double> doubleArray:
|
|
||||||
WriteDataElement(GetLengthOfByteArray<double>(doubleArray.Data.Length));
|
|
||||||
break;
|
|
||||||
case IArrayOf<bool> boolArray:
|
|
||||||
WriteDataElement(boolArray.Data.Length);
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<sbyte>> complexSbyteArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexSbyteArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<byte>> complexByteArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexByteArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<short>> complexShortArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexShortArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<ushort>> complexUshortArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexUshortArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<int>> complexIntArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexIntArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<uint>> complexUintArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexUintArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<long>> complexLongArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexLongArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<ulong>> complexUlongArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexUlongArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<ComplexOf<float>> complexFloatArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexFloatArray.Data));
|
|
||||||
break;
|
|
||||||
case IArrayOf<Complex> complexDoubleArray:
|
|
||||||
WriteComplexValues(GetLengthOfPairOfByteArrays(complexDoubleArray.Data));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteName(string name)
|
|
||||||
{
|
|
||||||
var nameBytes = Encoding.ASCII.GetBytes(name);
|
|
||||||
WriteDataElement(nameBytes.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteArrayFlags()
|
|
||||||
{
|
|
||||||
WriteTag();
|
|
||||||
Position += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteDimensions(int[] dimensions)
|
|
||||||
{
|
|
||||||
var buffer = GetLengthOfByteArray<int>(dimensions.Length);
|
|
||||||
WriteDataElement(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe int GetLengthOfByteArray<T>(int dataLength)
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
return dataLength * sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe int GetLengthOfPairOfByteArrays<T>(ComplexOf<T>[] data)
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
return data.Length * sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe int GetLengthOfPairOfByteArrays(Complex[] data)
|
|
||||||
{
|
|
||||||
return data.Length * sizeof(double);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int CalculatePadding(int length)
|
|
||||||
{
|
|
||||||
var rem = length % 8;
|
|
||||||
return rem == 0 ? 0 : 8 - rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteDataElement(int dataLength)
|
|
||||||
{
|
|
||||||
var maybePadding = 0;
|
|
||||||
if (dataLength > 4)
|
|
||||||
{
|
|
||||||
WriteTag();
|
|
||||||
Position += dataLength;
|
|
||||||
maybePadding = CalculatePadding(dataLength + 8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteShortTag();
|
|
||||||
Position += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
Position += maybePadding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteComplexValues(
|
|
||||||
int dataLength)
|
|
||||||
{
|
|
||||||
WriteDataElement(dataLength);
|
|
||||||
WriteDataElement(dataLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteSparseArrayValues<T>(int rowsLength, int columnsLength, int dataLength)
|
|
||||||
where T : unmanaged
|
|
||||||
{
|
|
||||||
WriteDataElement(GetLengthOfByteArray<int>(rowsLength));
|
|
||||||
WriteDataElement(GetLengthOfByteArray<int>(columnsLength));
|
|
||||||
if (typeof(T) == typeof(double))
|
|
||||||
{
|
|
||||||
WriteDataElement(GetLengthOfByteArray<double>(dataLength));
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(Complex))
|
|
||||||
{
|
|
||||||
WriteDataElement(GetLengthOfByteArray<double>(dataLength));
|
|
||||||
WriteDataElement(GetLengthOfByteArray<double>(dataLength));
|
|
||||||
}
|
|
||||||
else if (typeof(T) == typeof(bool))
|
|
||||||
{
|
|
||||||
WriteDataElement(dataLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (int rowIndexLength, int columnIndexLength, int dataLength, uint nonZero) PrepareSparseArrayData<T>(
|
|
||||||
ISparseArrayOf<T> array)
|
|
||||||
where T : struct, IEquatable<T>
|
|
||||||
{
|
|
||||||
var numberOfColumns = array.Dimensions[1];
|
|
||||||
var numberOfElements = array.Data.Values.Count(value => !value.Equals(default));
|
|
||||||
return (numberOfElements, numberOfColumns + 1, numberOfElements, (uint)numberOfElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteSparseArrayFlags()
|
|
||||||
{
|
|
||||||
WriteTag();
|
|
||||||
Position += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteFieldNames(IEnumerable<string> fieldNames)
|
|
||||||
{
|
|
||||||
var fieldNamesArray = fieldNames.Select(name => Encoding.ASCII.GetBytes(name)).ToArray();
|
|
||||||
var maxFieldName = fieldNamesArray.Max(name => name.Length) + 1;
|
|
||||||
WriteDataElement(GetLengthOfByteArray<int>(1));
|
|
||||||
var buffer = new byte[fieldNamesArray.Length * maxFieldName];
|
|
||||||
var startPosition = 0;
|
|
||||||
foreach (var name in fieldNamesArray)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < name.Length; i++)
|
|
||||||
{
|
|
||||||
buffer[startPosition + i] = name[i];
|
|
||||||
}
|
|
||||||
startPosition += maxFieldName;
|
|
||||||
}
|
|
||||||
WriteDataElement(buffer.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteStructureArrayValues(IStructureArray array)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < array.Count; i++)
|
|
||||||
{
|
|
||||||
foreach (var name in array.FieldNames)
|
|
||||||
{
|
|
||||||
WriteArray(array[name, i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteArray(IArray array, string variableName = "", bool isGlobal = false)
|
|
||||||
{
|
|
||||||
switch (array)
|
|
||||||
{
|
|
||||||
case ICharArray charArray:
|
|
||||||
WriteCharArray(charArray, variableName);
|
|
||||||
break;
|
|
||||||
case ISparseArrayOf<double> doubleSparseArray:
|
|
||||||
WriteSparseArray(doubleSparseArray, variableName);
|
|
||||||
break;
|
|
||||||
case ISparseArrayOf<Complex> complexSparseArray:
|
|
||||||
WriteSparseArray(complexSparseArray, variableName);
|
|
||||||
break;
|
|
||||||
case ISparseArrayOf<bool> boolSparseArray:
|
|
||||||
WriteSparseArray(boolSparseArray, variableName);
|
|
||||||
break;
|
|
||||||
case ICellArray cellArray:
|
|
||||||
WriteCellArray(cellArray, variableName);
|
|
||||||
break;
|
|
||||||
case IStructureArray structureArray:
|
|
||||||
WriteStructureArray(structureArray, variableName);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WriteNumericalArray(array, variableName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteCharArray(ICharArray charArray, string name)
|
|
||||||
{
|
|
||||||
WriteWrappingContents(
|
|
||||||
charArray,
|
|
||||||
fakeWriter => fakeWriter.WriteCharArrayContents(charArray, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteSparseArray<T>(ISparseArrayOf<T> sparseArray, string name)
|
|
||||||
where T : unmanaged, IEquatable<T>
|
|
||||||
{
|
|
||||||
WriteWrappingContents(
|
|
||||||
sparseArray,
|
|
||||||
fakeWriter => fakeWriter.WriteSparseArrayContents(sparseArray, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteCellArray(ICellArray cellArray, string name)
|
|
||||||
{
|
|
||||||
WriteWrappingContents(
|
|
||||||
cellArray,
|
|
||||||
fakeWriter => fakeWriter.WriteCellArrayContents(cellArray, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteCellArrayValues(ICellArray array)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < array.Count; i++)
|
|
||||||
{
|
|
||||||
WriteArray(array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteStructureArray(
|
|
||||||
IStructureArray structureArray,
|
|
||||||
string name)
|
|
||||||
{
|
|
||||||
WriteWrappingContents(
|
|
||||||
structureArray,
|
|
||||||
fakeWriter => fakeWriter.WriteStructureArrayContents(structureArray, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteNumericalArray(
|
|
||||||
IArray numericalArray,
|
|
||||||
string name = "")
|
|
||||||
{
|
|
||||||
WriteWrappingContents(
|
|
||||||
numericalArray,
|
|
||||||
fakeWriter => fakeWriter.WriteNumericalArrayContents(numericalArray, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
#if !NET461
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
@ -72,9 +72,11 @@ namespace MatFileHandler
|
|||||||
var version = reader.ReadInt16();
|
var version = reader.ReadInt16();
|
||||||
var endian = reader.ReadInt16();
|
var endian = reader.ReadInt16();
|
||||||
var isLittleEndian = endian == 19785;
|
var isLittleEndian = endian == 19785;
|
||||||
return isLittleEndian
|
if (!isLittleEndian)
|
||||||
? new Header(text, subsystemDataOffset, version)
|
{
|
||||||
: throw new NotSupportedException("Big-endian files are not supported.");
|
throw new NotSupportedException("Big-endian files are not supported.");
|
||||||
|
}
|
||||||
|
return new Header(text, subsystemDataOffset, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetOperatingSystem()
|
private static string GetOperatingSystem()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -8,8 +10,6 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the contained string.
|
/// Gets the contained string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#pragma warning disable CA1716, CA1720
|
|
||||||
string String { get; }
|
string String { get; }
|
||||||
#pragma warning restore CA1716, CA1720
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -25,6 +27,6 @@ namespace MatFileHandler
|
|||||||
/// <param name="name">The name of the variable to get.</param>
|
/// <param name="name">The name of the variable to get.</param>
|
||||||
/// <param name="variable">When this method returns, contains the variable with the specified name, if it is found; otherwise, null.</param>
|
/// <param name="variable">When this method returns, contains the variable with the specified name, if it is found; otherwise, null.</param>
|
||||||
/// <returns>True if the file contains a variable with the specified name; otherwise, false.</returns>
|
/// <returns>True if the file contains a variable with the specified name; otherwise, false.</returns>
|
||||||
bool TryGetVariable(string name, out IVariable? variable);
|
public bool TryGetVariable(string name, out IVariable? variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
@ -49,7 +51,7 @@ namespace MatFileHandler
|
|||||||
/// <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 }, Array.Empty<int>(), string.Empty);
|
return new MatArray(new ArrayFlags { Class = ArrayType.MxCell, Variable = 0 }, new int[] { }, string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@ -16,7 +18,11 @@ namespace MatFileHandler
|
|||||||
/// <param name="variables">List of variables.</param>
|
/// <param name="variables">List of variables.</param>
|
||||||
public MatFile(IEnumerable<IVariable> variables)
|
public MatFile(IEnumerable<IVariable> variables)
|
||||||
{
|
{
|
||||||
_variables = variables.ToDictionary(v => v.Name, v => v);
|
_variables = new Dictionary<string, IVariable>();
|
||||||
|
foreach (var variable in variables)
|
||||||
|
{
|
||||||
|
_variables[variable.Name] = variable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,45 +1,47 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net461;net472</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net461;net472</TargetFrameworks>
|
||||||
<PackageVersion>1.4.0-beta6</PackageVersion>
|
<PackageVersion>1.4.0-beta1</PackageVersion>
|
||||||
<PackageId>MatFileHandler</PackageId>
|
<PackageId>MatFileHandler</PackageId>
|
||||||
<Title>A library for reading and writing MATLAB .mat files.</Title>
|
<Title>A library for reading and writing MATLAB .mat files.</Title>
|
||||||
<Authors>Alexander Luzgarev</Authors>
|
<Authors>Alexander Luzgarev</Authors>
|
||||||
<Description>MatFileHandler provides a simple interface for reading and writing MATLAB .mat files (of so-called "Level 5") and extracting the contents of numerical arrays, logical arrays, sparse arrays, char arrays, cell arrays and structure arrays.</Description>
|
<Description>MatFileHandler provides a simple interface for reading and writing MATLAB .mat files (of so-called "Level 5") and extracting the contents of numerical arrays, logical arrays, sparse arrays, char arrays, cell arrays and structure arrays.</Description>
|
||||||
<Copyright>Copyright 2017-2020 Alexander Luzgarev</Copyright>
|
<Copyright>Copyright 2017-2020 Alexander Luzgarev</Copyright>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||||
<PackageProjectUrl>https://git.mahalex.net/mahalex/MatFileHandler</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/mahalex/MatFileHandler</PackageProjectUrl>
|
||||||
<PackageReleaseNotes>https://git.mahalex.net/mahalex/MatFileHandler/releases/</PackageReleaseNotes>
|
<PackageReleaseNotes>First release.</PackageReleaseNotes>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
<PackageTags>Matlab</PackageTags>
|
<PackageTags>Matlab</PackageTags>
|
||||||
<RepositoryUrl>https://git.mahalex.net/mahalex/MatFileHandler</RepositoryUrl>
|
<RepositoryUrl>https://github.com/mahalex/MatFileHandler</RepositoryUrl>
|
||||||
<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>
|
||||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
<LangVersion>8.0</LangVersion>
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<IncludeSymbols>true</IncludeSymbols>
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<AnalysisLevel>latest-Recommended</AnalysisLevel>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<CodeAnalysisRuleSet>..\MatFileHandler.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Include="..\stylecop.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.66">
|
||||||
|
<PrivateAssets>All</PrivateAssets>
|
||||||
|
</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>
|
||||||
<PackageReference Include="Microsoft.SourceLink.Gitea" Version="8.0.0" PrivateAssets="All"/>
|
<None Include="..\LICENSE.md" Pack="true" PackagePath=""/>
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<InternalsVisibleTo Include="MatFileHandler.Tests" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
@ -25,8 +28,10 @@ namespace MatFileHandler
|
|||||||
/// <returns>Contents of the file.</returns>
|
/// <returns>Contents of the file.</returns>
|
||||||
public IMatFile Read()
|
public IMatFile Read()
|
||||||
{
|
{
|
||||||
using var reader = new BinaryReader(new PositionTrackingStream(Stream));
|
using (var reader = new BinaryReader(Stream))
|
||||||
return Read(reader);
|
{
|
||||||
|
return Read(reader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -46,24 +51,26 @@ namespace MatFileHandler
|
|||||||
var dataElementReader = new DataElementReader(subsystemData);
|
var dataElementReader = new DataElementReader(subsystemData);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var position = reader.BaseStream.Position;
|
try
|
||||||
var dataElement = dataElementReader.Read(reader);
|
{
|
||||||
if (dataElement is null)
|
var position = reader.BaseStream.Position;
|
||||||
|
var dataElement = dataElementReader.Read(reader);
|
||||||
|
if (position == subsystemDataOffset)
|
||||||
|
{
|
||||||
|
var subsystemDataElement = dataElement as IArrayOf<byte>
|
||||||
|
?? throw new HandlerException("Cannot parse subsystem data element.");
|
||||||
|
var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData);
|
||||||
|
subsystemData.Set(newSubsystemData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
variables.Add(new RawVariable(position, dataElement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (EndOfStreamException)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position == subsystemDataOffset)
|
|
||||||
{
|
|
||||||
var subsystemDataElement = dataElement as IArrayOf<byte>
|
|
||||||
?? throw new HandlerException("Cannot parse subsystem data element.");
|
|
||||||
var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData);
|
|
||||||
subsystemData.Set(newSubsystemData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
variables.Add(new RawVariable(position, dataElement));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return variables;
|
return variables;
|
||||||
@ -81,21 +88,23 @@ namespace MatFileHandler
|
|||||||
return ReadRawVariables(reader, subsystemDataOffset, subsystemData);
|
return ReadRawVariables(reader, subsystemDataOffset, subsystemData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MatFile Read(BinaryReader reader)
|
private static IMatFile Read(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var header = ReadHeader(reader);
|
var header = ReadHeader(reader);
|
||||||
var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset);
|
var rawVariables = ReadRawVariables(reader, header.SubsystemDataOffset);
|
||||||
var variables = new List<IVariable>();
|
var variables = new List<IVariable>();
|
||||||
foreach (var variable in rawVariables)
|
foreach (var variable in rawVariables)
|
||||||
{
|
{
|
||||||
if (variable.DataElement is MatArray array)
|
var array = variable.DataElement as MatArray;
|
||||||
|
if (array is null)
|
||||||
{
|
{
|
||||||
variables.Add(
|
continue;
|
||||||
new MatVariable(
|
|
||||||
array,
|
|
||||||
array.Name,
|
|
||||||
array.Flags.Variable.HasFlag(Variable.IsGlobal)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variables.Add(new MatVariable(
|
||||||
|
array,
|
||||||
|
array.Name,
|
||||||
|
array.Flags.Variable.HasFlag(Variable.IsGlobal)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatFile(variables);
|
return new MatFile(variables);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -45,28 +47,22 @@ namespace MatFileHandler
|
|||||||
public void Write(IMatFile file)
|
public void Write(IMatFile file)
|
||||||
{
|
{
|
||||||
var header = Header.CreateNewHeader();
|
var header = Header.CreateNewHeader();
|
||||||
using var writer = new BinaryWriter(Stream);
|
using (var writer = new BinaryWriter(Stream))
|
||||||
WriteHeader(writer, header);
|
|
||||||
foreach (var variable in file.Variables)
|
|
||||||
{
|
{
|
||||||
switch (_options.UseCompression)
|
WriteHeader(writer, header);
|
||||||
|
foreach (var variable in file.Variables)
|
||||||
{
|
{
|
||||||
case CompressionUsage.Always:
|
switch (_options.UseCompression)
|
||||||
if (Stream.CanSeek)
|
{
|
||||||
{
|
case CompressionUsage.Always:
|
||||||
WriteCompressedVariableToSeekableStream(writer, variable);
|
WriteCompressedVariable(writer, variable);
|
||||||
}
|
break;
|
||||||
else
|
case CompressionUsage.Never:
|
||||||
{
|
WriteVariable(writer, variable);
|
||||||
WriteCompressedVariableToUnseekableStream(writer, variable);
|
break;
|
||||||
}
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
break;
|
}
|
||||||
case CompressionUsage.Never:
|
|
||||||
WriteVariable(writer, variable);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +90,7 @@ namespace MatFileHandler
|
|||||||
return (s2 << 16) | s1;
|
return (s2 << 16) | s1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteHeader(BinaryWriter writer, Header header)
|
private void WriteHeader(BinaryWriter writer, Header header)
|
||||||
{
|
{
|
||||||
writer.Write(Encoding.UTF8.GetBytes(header.Text));
|
writer.Write(Encoding.UTF8.GetBytes(header.Text));
|
||||||
writer.Write(header.SubsystemDataOffset);
|
writer.Write(header.SubsystemDataOffset);
|
||||||
@ -102,30 +98,33 @@ namespace MatFileHandler
|
|||||||
writer.Write((short)19785); // Magic number, 'IM'.
|
writer.Write((short)19785); // Magic number, 'IM'.
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteTag(BinaryWriter writer, Tag tag)
|
private void WriteTag(BinaryWriter writer, Tag tag)
|
||||||
{
|
{
|
||||||
writer.Write((int)tag.Type);
|
writer.Write((int)tag.Type);
|
||||||
writer.Write(tag.Length);
|
writer.Write(tag.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteShortTag(BinaryWriter writer, Tag tag)
|
private void WriteShortTag(BinaryWriter writer, Tag tag)
|
||||||
{
|
{
|
||||||
writer.Write((short)tag.Type);
|
writer.Write((short)tag.Type);
|
||||||
writer.Write((short)tag.Length);
|
writer.Write((short)tag.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteDataElement(BinaryWriter writer, DataType type, byte[] data)
|
private void WritePadding(BinaryWriter writer)
|
||||||
|
{
|
||||||
|
var positionMod8 = writer.BaseStream.Position % 8;
|
||||||
|
if (positionMod8 != 0)
|
||||||
|
{
|
||||||
|
writer.Write(new byte[8 - positionMod8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteDataElement(BinaryWriter writer, DataType type, byte[] data)
|
||||||
{
|
{
|
||||||
if (data.Length > 4)
|
if (data.Length > 4)
|
||||||
{
|
{
|
||||||
WriteTag(writer, new Tag(type, data.Length));
|
WriteTag(writer, new Tag(type, data.Length));
|
||||||
writer.Write(data);
|
writer.Write(data);
|
||||||
var rem = data.Length % 8;
|
|
||||||
if (rem > 0)
|
|
||||||
{
|
|
||||||
var padding = new byte[8 - rem];
|
|
||||||
writer.Write(padding);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -137,16 +136,17 @@ namespace MatFileHandler
|
|||||||
writer.Write(padding);
|
writer.Write(padding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WritePadding(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteDimensions(BinaryWriter writer, int[] dimensions)
|
private void WriteDimensions(BinaryWriter writer, int[] dimensions)
|
||||||
{
|
{
|
||||||
var buffer = ConvertToByteArray(dimensions);
|
var buffer = ConvertToByteArray(dimensions);
|
||||||
WriteDataElement(writer, DataType.MiInt32, buffer);
|
WriteDataElement(writer, DataType.MiInt32, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] ConvertToByteArray<T>(T[] data)
|
private byte[] ConvertToByteArray<T>(T[] data)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
if (typeof(T) == typeof(sbyte))
|
if (typeof(T) == typeof(sbyte))
|
||||||
@ -189,10 +189,6 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
size = sizeof(double);
|
size = sizeof(double);
|
||||||
}
|
}
|
||||||
else if (typeof(T) == typeof(bool))
|
|
||||||
{
|
|
||||||
size = sizeof(bool);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
@ -202,51 +198,51 @@ namespace MatFileHandler
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (byte[] real, byte[] imaginary) ConvertToPairOfByteArrays<T>(ComplexOf<T>[] data)
|
private (byte[] real, byte[] imaginary) ConvertToPairOfByteArrays<T>(ComplexOf<T>[] data)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
return (ConvertToByteArray(data.Select(x => x.Real).ToArray()),
|
return (ConvertToByteArray(data.Select(x => x.Real).ToArray()),
|
||||||
ConvertToByteArray(data.Select(x => x.Imaginary).ToArray()));
|
ConvertToByteArray(data.Select(x => x.Imaginary).ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (byte[] real, byte[] imaginary) ConvertToPairOfByteArrays(Complex[] data)
|
private (byte[] real, byte[] imaginary) ConvertToPairOfByteArrays(Complex[] data)
|
||||||
{
|
{
|
||||||
return (ConvertToByteArray(data.Select(x => x.Real).ToArray()),
|
return (ConvertToByteArray(data.Select(x => x.Real).ToArray()),
|
||||||
ConvertToByteArray(data.Select(x => x.Imaginary).ToArray()));
|
ConvertToByteArray(data.Select(x => x.Imaginary).ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteComplexValues(BinaryWriter writer, DataType type, (byte[] real, byte[] complex) data)
|
private void WriteComplexValues(BinaryWriter writer, DataType type, (byte[] real, byte[] complex) data)
|
||||||
{
|
{
|
||||||
WriteDataElement(writer, type, data.real);
|
WriteDataElement(writer, type, data.real);
|
||||||
WriteDataElement(writer, type, data.complex);
|
WriteDataElement(writer, type, data.complex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteArrayFlags(BinaryWriter writer, ArrayFlags flags)
|
private void WriteArrayFlags(BinaryWriter writer, ArrayFlags flags)
|
||||||
{
|
{
|
||||||
var flag = (byte)flags.Variable;
|
var flag = (byte)flags.Variable;
|
||||||
WriteTag(writer, new Tag(DataType.MiUInt32, 8));
|
WriteTag(writer, new Tag(DataType.MiUInt32, 8));
|
||||||
writer.Write((byte)flags.Class);
|
writer.Write((byte)flags.Class);
|
||||||
writer.Write(flag);
|
writer.Write(flag);
|
||||||
writer.Write([0, 0, 0, 0, 0, 0]);
|
writer.Write(new byte[] { 0, 0, 0, 0, 0, 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags)
|
private void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags)
|
||||||
{
|
{
|
||||||
var flag = (byte)flags.ArrayFlags.Variable;
|
var flag = (byte)flags.ArrayFlags.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.ArrayFlags.Class);
|
||||||
writer.Write(flag);
|
writer.Write(flag);
|
||||||
writer.Write([0, 0]);
|
writer.Write(new byte[] { 0, 0 });
|
||||||
writer.Write(flags.NzMax);
|
writer.Write(flags.NzMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteName(BinaryWriter writer, string name)
|
private void WriteName(BinaryWriter writer, string name)
|
||||||
{
|
{
|
||||||
var nameBytes = Encoding.ASCII.GetBytes(name);
|
var nameBytes = Encoding.ASCII.GetBytes(name);
|
||||||
WriteDataElement(writer, DataType.MiInt8, nameBytes);
|
WriteDataElement(writer, DataType.MiInt8, nameBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteNumericalArrayValues(BinaryWriter writer, IArray value)
|
private void WriteNumericalArrayValues(BinaryWriter writer, IArray value)
|
||||||
{
|
{
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
@ -281,7 +277,10 @@ namespace MatFileHandler
|
|||||||
WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(doubleArray.Data));
|
WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(doubleArray.Data));
|
||||||
break;
|
break;
|
||||||
case IArrayOf<bool> boolArray:
|
case IArrayOf<bool> boolArray:
|
||||||
WriteDataElement(writer, DataType.MiUInt8, ConvertToByteArray(boolArray.Data));
|
WriteDataElement(
|
||||||
|
writer,
|
||||||
|
DataType.MiUInt8,
|
||||||
|
boolArray.Data.Select(element => element ? (byte)1 : (byte)0).ToArray());
|
||||||
break;
|
break;
|
||||||
case IArrayOf<ComplexOf<sbyte>> complexSbyteArray:
|
case IArrayOf<ComplexOf<sbyte>> complexSbyteArray:
|
||||||
WriteComplexValues(writer, DataType.MiInt8, ConvertToPairOfByteArrays(complexSbyteArray.Data));
|
WriteComplexValues(writer, DataType.MiInt8, ConvertToPairOfByteArrays(complexSbyteArray.Data));
|
||||||
@ -318,39 +317,63 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayFlags GetArrayFlags(IArray array, bool isGlobal)
|
private ArrayFlags GetArrayFlags(IArray array, bool isGlobal)
|
||||||
{
|
{
|
||||||
var variableFlags = isGlobal ? Variable.IsGlobal : 0;
|
var variableFlags = isGlobal ? Variable.IsGlobal : 0;
|
||||||
return array switch
|
switch (array)
|
||||||
{
|
{
|
||||||
IArrayOf<sbyte> => new ArrayFlags(ArrayType.MxInt8, variableFlags),
|
case IArrayOf<sbyte> _:
|
||||||
IArrayOf<byte> => new ArrayFlags(ArrayType.MxUInt8, variableFlags),
|
return new ArrayFlags(ArrayType.MxInt8, variableFlags);
|
||||||
IArrayOf<short> => new ArrayFlags(ArrayType.MxInt16, variableFlags),
|
case IArrayOf<byte> _:
|
||||||
IArrayOf<ushort> => new ArrayFlags(ArrayType.MxUInt16, variableFlags),
|
return new ArrayFlags(ArrayType.MxUInt8, variableFlags);
|
||||||
IArrayOf<int> => new ArrayFlags(ArrayType.MxInt32, variableFlags),
|
case IArrayOf<short> _:
|
||||||
IArrayOf<uint> => new ArrayFlags(ArrayType.MxUInt32, variableFlags),
|
return new ArrayFlags(ArrayType.MxInt16, variableFlags);
|
||||||
IArrayOf<long> => new ArrayFlags(ArrayType.MxInt64, variableFlags),
|
case IArrayOf<ushort> _:
|
||||||
IArrayOf<ulong> => new ArrayFlags(ArrayType.MxUInt64, variableFlags),
|
return new ArrayFlags(ArrayType.MxUInt16, variableFlags);
|
||||||
IArrayOf<float> => new ArrayFlags(ArrayType.MxSingle, variableFlags),
|
case IArrayOf<int> _:
|
||||||
IArrayOf<double> => new ArrayFlags(ArrayType.MxDouble, variableFlags),
|
return new ArrayFlags(ArrayType.MxInt32, variableFlags);
|
||||||
IArrayOf<bool> => new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsLogical),
|
case IArrayOf<uint> _:
|
||||||
IArrayOf<ComplexOf<sbyte>> => new ArrayFlags(ArrayType.MxInt8, variableFlags | Variable.IsComplex),
|
return new ArrayFlags(ArrayType.MxUInt32, variableFlags);
|
||||||
IArrayOf<ComplexOf<byte>> => new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsComplex),
|
case IArrayOf<long> _:
|
||||||
IArrayOf<ComplexOf<short>> => new ArrayFlags(ArrayType.MxInt16, variableFlags | Variable.IsComplex),
|
return new ArrayFlags(ArrayType.MxInt64, variableFlags);
|
||||||
IArrayOf<ComplexOf<ushort>> => new ArrayFlags(ArrayType.MxUInt16, variableFlags | Variable.IsComplex),
|
case IArrayOf<ulong> _:
|
||||||
IArrayOf<ComplexOf<int>> => new ArrayFlags(ArrayType.MxInt32, variableFlags | Variable.IsComplex),
|
return new ArrayFlags(ArrayType.MxUInt64, variableFlags);
|
||||||
IArrayOf<ComplexOf<uint>> => new ArrayFlags(ArrayType.MxUInt32, variableFlags | Variable.IsComplex),
|
case IArrayOf<float> _:
|
||||||
IArrayOf<ComplexOf<long>> => new ArrayFlags(ArrayType.MxInt64, variableFlags | Variable.IsComplex),
|
return new ArrayFlags(ArrayType.MxSingle, variableFlags);
|
||||||
IArrayOf<ComplexOf<ulong>> => new ArrayFlags(ArrayType.MxUInt64, variableFlags | Variable.IsComplex),
|
case IArrayOf<double> _:
|
||||||
IArrayOf<ComplexOf<float>> => new ArrayFlags(ArrayType.MxSingle, variableFlags | Variable.IsComplex),
|
return new ArrayFlags(ArrayType.MxDouble, variableFlags);
|
||||||
IArrayOf<Complex> => new ArrayFlags(ArrayType.MxDouble, variableFlags | Variable.IsComplex),
|
case IArrayOf<bool> _:
|
||||||
IStructureArray => new ArrayFlags(ArrayType.MxStruct, variableFlags),
|
return new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsLogical);
|
||||||
ICellArray => new ArrayFlags(ArrayType.MxCell, variableFlags),
|
case IArrayOf<ComplexOf<sbyte>> _:
|
||||||
_ => throw new NotSupportedException(),
|
return new ArrayFlags(ArrayType.MxInt8, variableFlags | Variable.IsComplex);
|
||||||
};
|
case IArrayOf<ComplexOf<byte>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<short>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxInt16, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<ushort>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxUInt16, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<int>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxInt32, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<uint>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxUInt32, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<long>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxInt64, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<ulong>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxUInt64, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<ComplexOf<float>> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxSingle, variableFlags | Variable.IsComplex);
|
||||||
|
case IArrayOf<Complex> _:
|
||||||
|
return new ArrayFlags(ArrayType.MxDouble, variableFlags | Variable.IsComplex);
|
||||||
|
case IStructureArray _:
|
||||||
|
return new ArrayFlags(ArrayType.MxStruct, variableFlags);
|
||||||
|
case ICellArray _:
|
||||||
|
return new ArrayFlags(ArrayType.MxCell, variableFlags);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SparseArrayFlags GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero)
|
private SparseArrayFlags 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);
|
||||||
@ -365,16 +388,12 @@ namespace MatFileHandler
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayFlags GetCharArrayFlags(bool isGlobal)
|
private ArrayFlags GetCharArrayFlags(bool isGlobal)
|
||||||
{
|
{
|
||||||
return new ArrayFlags(ArrayType.MxChar, isGlobal ? Variable.IsGlobal : 0);
|
return new ArrayFlags(ArrayType.MxChar, isGlobal ? Variable.IsGlobal : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteWrappingContents<T>(
|
private void WriteWrappingContents<T>(BinaryWriter writer, T array, Action<BinaryWriter> writeContents)
|
||||||
BinaryWriter writer,
|
|
||||||
T array,
|
|
||||||
Action<FakeWriter> lengthCalculator,
|
|
||||||
Action<BinaryWriter> writeContents)
|
|
||||||
where T : IArray
|
where T : IArray
|
||||||
{
|
{
|
||||||
if (array.IsEmpty)
|
if (array.IsEmpty)
|
||||||
@ -382,15 +401,19 @@ namespace MatFileHandler
|
|||||||
WriteTag(writer, new Tag(DataType.MiMatrix, 0));
|
WriteTag(writer, new Tag(DataType.MiMatrix, 0));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
using (var contents = new MemoryStream())
|
||||||
var fakeWriter = new FakeWriter();
|
{
|
||||||
lengthCalculator(fakeWriter);
|
using (var contentsWriter = new BinaryWriter(contents))
|
||||||
var calculatedLength = fakeWriter.Position;
|
{
|
||||||
WriteTag(writer, new Tag(DataType.MiMatrix, calculatedLength));
|
writeContents(contentsWriter);
|
||||||
writeContents(writer);
|
WriteTag(writer, new Tag(DataType.MiMatrix, (int)contents.Length));
|
||||||
|
contents.Position = 0;
|
||||||
|
contents.CopyTo(writer.BaseStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteNumericalArrayContents(BinaryWriter writer, IArray array, string name, bool isGlobal)
|
private void WriteNumericalArrayContents(BinaryWriter writer, IArray array, string name, bool isGlobal)
|
||||||
{
|
{
|
||||||
WriteArrayFlags(writer, GetArrayFlags(array, isGlobal));
|
WriteArrayFlags(writer, GetArrayFlags(array, isGlobal));
|
||||||
WriteDimensions(writer, array.Dimensions);
|
WriteDimensions(writer, array.Dimensions);
|
||||||
@ -398,7 +421,7 @@ namespace MatFileHandler
|
|||||||
WriteNumericalArrayValues(writer, array);
|
WriteNumericalArrayValues(writer, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteNumericalArray(
|
private void WriteNumericalArray(
|
||||||
BinaryWriter writer,
|
BinaryWriter writer,
|
||||||
IArray numericalArray,
|
IArray numericalArray,
|
||||||
string name = "",
|
string name = "",
|
||||||
@ -407,11 +430,10 @@ namespace MatFileHandler
|
|||||||
WriteWrappingContents(
|
WriteWrappingContents(
|
||||||
writer,
|
writer,
|
||||||
numericalArray,
|
numericalArray,
|
||||||
fakeWriter => fakeWriter.WriteNumericalArrayContents(numericalArray, name),
|
|
||||||
contentsWriter => { WriteNumericalArrayContents(contentsWriter, numericalArray, name, isGlobal); });
|
contentsWriter => { WriteNumericalArrayContents(contentsWriter, numericalArray, name, isGlobal); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteCharArrayContents(BinaryWriter writer, ICharArray charArray, string name, bool isGlobal)
|
private void WriteCharArrayContents(BinaryWriter writer, ICharArray charArray, string name, bool isGlobal)
|
||||||
{
|
{
|
||||||
WriteArrayFlags(writer, GetCharArrayFlags(isGlobal));
|
WriteArrayFlags(writer, GetCharArrayFlags(isGlobal));
|
||||||
WriteDimensions(writer, charArray.Dimensions);
|
WriteDimensions(writer, charArray.Dimensions);
|
||||||
@ -420,16 +442,15 @@ namespace MatFileHandler
|
|||||||
WriteDataElement(writer, DataType.MiUtf16, ConvertToByteArray(array));
|
WriteDataElement(writer, DataType.MiUtf16, ConvertToByteArray(array));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteCharArray(BinaryWriter writer, ICharArray charArray, string name, bool isGlobal)
|
private void WriteCharArray(BinaryWriter writer, ICharArray charArray, string name, bool isGlobal)
|
||||||
{
|
{
|
||||||
WriteWrappingContents(
|
WriteWrappingContents(
|
||||||
writer,
|
writer,
|
||||||
charArray,
|
charArray,
|
||||||
fakeWriter => fakeWriter.WriteCharArrayContents(charArray, name),
|
|
||||||
contentsWriter => { WriteCharArrayContents(contentsWriter, charArray, name, isGlobal); });
|
contentsWriter => { WriteCharArrayContents(contentsWriter, charArray, name, isGlobal); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteSparseArrayValues<T>(
|
private void WriteSparseArrayValues<T>(
|
||||||
BinaryWriter writer, int[] rows, int[] columns, T[] data)
|
BinaryWriter writer, int[] rows, int[] columns, T[] data)
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
@ -439,8 +460,9 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(data));
|
WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(data));
|
||||||
}
|
}
|
||||||
else if (data is Complex[] complexData)
|
else if (data is Complex[])
|
||||||
{
|
{
|
||||||
|
var complexData = data as Complex[];
|
||||||
WriteDataElement(
|
WriteDataElement(
|
||||||
writer,
|
writer,
|
||||||
DataType.MiDouble,
|
DataType.MiDouble,
|
||||||
@ -450,16 +472,17 @@ namespace MatFileHandler
|
|||||||
DataType.MiDouble,
|
DataType.MiDouble,
|
||||||
ConvertToByteArray(complexData.Select(c => c.Imaginary).ToArray()));
|
ConvertToByteArray(complexData.Select(c => c.Imaginary).ToArray()));
|
||||||
}
|
}
|
||||||
else if (data is bool[] boolData)
|
else if (data is bool[])
|
||||||
{
|
{
|
||||||
|
var boolData = data as bool[];
|
||||||
WriteDataElement(
|
WriteDataElement(
|
||||||
writer,
|
writer,
|
||||||
DataType.MiUInt8,
|
DataType.MiUInt8,
|
||||||
ConvertToByteArray(boolData));
|
boolData.Select(element => element ? (byte)1 : (byte)0).ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (int[] rowIndex, int[] columnIndex, T[] data, uint nonZero) PrepareSparseArrayData<T>(
|
private (int[] rowIndex, int[] columnIndex, T[] data, uint nonZero) PrepareSparseArrayData<T>(
|
||||||
ISparseArrayOf<T> array)
|
ISparseArrayOf<T> array)
|
||||||
where T : struct, IEquatable<T>
|
where T : struct, IEquatable<T>
|
||||||
{
|
{
|
||||||
@ -482,7 +505,7 @@ namespace MatFileHandler
|
|||||||
return (rowIndexList.ToArray(), columnIndex, valuesList.ToArray(), (uint)rowIndexList.Count);
|
return (rowIndexList.ToArray(), columnIndex, valuesList.ToArray(), (uint)rowIndexList.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteSparseArrayContents<T>(
|
private void WriteSparseArrayContents<T>(
|
||||||
BinaryWriter writer,
|
BinaryWriter writer,
|
||||||
ISparseArrayOf<T> array,
|
ISparseArrayOf<T> array,
|
||||||
string name,
|
string name,
|
||||||
@ -496,21 +519,20 @@ namespace MatFileHandler
|
|||||||
WriteSparseArrayValues(writer, rows, columns, data);
|
WriteSparseArrayValues(writer, rows, columns, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteSparseArray<T>(BinaryWriter writer, ISparseArrayOf<T> sparseArray, string name, bool isGlobal)
|
private void WriteSparseArray<T>(BinaryWriter writer, ISparseArrayOf<T> sparseArray, string name, bool isGlobal)
|
||||||
where T : unmanaged, IEquatable<T>
|
where T : struct, IEquatable<T>
|
||||||
{
|
{
|
||||||
WriteWrappingContents(
|
WriteWrappingContents(
|
||||||
writer,
|
writer,
|
||||||
sparseArray,
|
sparseArray,
|
||||||
fakeWriter => fakeWriter.WriteSparseArrayContents(sparseArray, name),
|
|
||||||
contentsWriter => { WriteSparseArrayContents(contentsWriter, sparseArray, name, isGlobal); });
|
contentsWriter => { WriteSparseArrayContents(contentsWriter, sparseArray, name, isGlobal); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteFieldNames(BinaryWriter writer, IEnumerable<string> fieldNames)
|
private void WriteFieldNames(BinaryWriter writer, IEnumerable<string> fieldNames)
|
||||||
{
|
{
|
||||||
var fieldNamesArray = fieldNames.Select(name => Encoding.ASCII.GetBytes(name)).ToArray();
|
var fieldNamesArray = fieldNames.Select(name => Encoding.ASCII.GetBytes(name)).ToArray();
|
||||||
var maxFieldName = fieldNamesArray.Max(name => name.Length) + 1;
|
var maxFieldName = fieldNamesArray.Select(name => name.Length).Max() + 1;
|
||||||
WriteDataElement(writer, DataType.MiInt32, ConvertToByteArray([maxFieldName]));
|
WriteDataElement(writer, DataType.MiInt32, ConvertToByteArray(new[] { maxFieldName }));
|
||||||
var buffer = new byte[fieldNamesArray.Length * maxFieldName];
|
var buffer = new byte[fieldNamesArray.Length * maxFieldName];
|
||||||
var startPosition = 0;
|
var startPosition = 0;
|
||||||
foreach (var name in fieldNamesArray)
|
foreach (var name in fieldNamesArray)
|
||||||
@ -553,7 +575,6 @@ namespace MatFileHandler
|
|||||||
WriteWrappingContents(
|
WriteWrappingContents(
|
||||||
writer,
|
writer,
|
||||||
structureArray,
|
structureArray,
|
||||||
fakeWriter => fakeWriter.WriteStructureArrayContents(structureArray, name),
|
|
||||||
contentsWriter => { WriteStructureArrayContents(contentsWriter, structureArray, name, isGlobal); });
|
contentsWriter => { WriteStructureArrayContents(contentsWriter, structureArray, name, isGlobal); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +599,6 @@ namespace MatFileHandler
|
|||||||
WriteWrappingContents(
|
WriteWrappingContents(
|
||||||
writer,
|
writer,
|
||||||
cellArray,
|
cellArray,
|
||||||
fakeWriter => fakeWriter.WriteCellArrayContents(cellArray, name),
|
|
||||||
contentsWriter => { WriteCellArrayContents(contentsWriter, cellArray, name, isGlobal); });
|
contentsWriter => { WriteCellArrayContents(contentsWriter, cellArray, name, isGlobal); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,55 +635,33 @@ namespace MatFileHandler
|
|||||||
WriteArray(writer, variable.Value, variable.Name, variable.IsGlobal);
|
WriteArray(writer, variable.Value, variable.Name, variable.IsGlobal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteCompressedVariableToSeekableStream(BinaryWriter writer, IVariable variable)
|
private void WriteCompressedVariable(BinaryWriter writer, IVariable variable)
|
||||||
{
|
{
|
||||||
var position = writer.BaseStream.Position;
|
using (var compressedStream = new MemoryStream())
|
||||||
WriteTag(writer, new Tag(DataType.MiCompressed, 0));
|
|
||||||
writer.Write((byte)0x78);
|
|
||||||
writer.Write((byte)0x9c);
|
|
||||||
int compressedLength;
|
|
||||||
uint crc;
|
|
||||||
var before = writer.BaseStream.Position;
|
|
||||||
using (var compressionStream = new DeflateStream(writer.BaseStream, CompressionMode.Compress, leaveOpen: true))
|
|
||||||
{
|
{
|
||||||
using var checksumStream = new ChecksumCalculatingStream(compressionStream);
|
uint crc;
|
||||||
using var internalWriter = new BinaryWriter(checksumStream, Encoding.UTF8, leaveOpen: true);
|
using (var originalStream = new MemoryStream())
|
||||||
WriteVariable(internalWriter, variable);
|
{
|
||||||
crc = checksumStream.GetCrc();
|
using (var internalWriter = new BinaryWriter(originalStream))
|
||||||
|
{
|
||||||
|
WriteVariable(internalWriter, variable);
|
||||||
|
originalStream.Position = 0;
|
||||||
|
crc = CalculateAdler32Checksum(originalStream);
|
||||||
|
originalStream.Position = 0;
|
||||||
|
using (var compressionStream =
|
||||||
|
new DeflateStream(compressedStream, CompressionMode.Compress, leaveOpen: true))
|
||||||
|
{
|
||||||
|
originalStream.CopyTo(compressionStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compressedStream.Position = 0;
|
||||||
|
WriteTag(writer, new Tag(DataType.MiCompressed, (int)(compressedStream.Length + 6)));
|
||||||
|
writer.Write((byte)0x78);
|
||||||
|
writer.Write((byte)0x9c);
|
||||||
|
compressedStream.CopyTo(writer.BaseStream);
|
||||||
|
writer.Write(BitConverter.GetBytes(crc).Reverse().ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
var after = writer.BaseStream.Position;
|
|
||||||
compressedLength = (int)(after - before) + 6;
|
|
||||||
|
|
||||||
writer.Write(BitConverter.GetBytes(crc).Reverse().ToArray());
|
|
||||||
writer.BaseStream.Position = position;
|
|
||||||
WriteTag(writer, new Tag(DataType.MiCompressed, compressedLength));
|
|
||||||
writer.BaseStream.Seek(0, SeekOrigin.End);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteCompressedVariableToUnseekableStream(BinaryWriter writer, IVariable variable)
|
|
||||||
{
|
|
||||||
using var compressedStream = new MemoryStream();
|
|
||||||
uint crc;
|
|
||||||
using (var originalStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
using var internalWriter = new BinaryWriter(originalStream);
|
|
||||||
WriteVariable(internalWriter, variable);
|
|
||||||
originalStream.Position = 0;
|
|
||||||
crc = CalculateAdler32Checksum(originalStream);
|
|
||||||
originalStream.Position = 0;
|
|
||||||
using var compressionStream = new DeflateStream(
|
|
||||||
compressedStream,
|
|
||||||
CompressionMode.Compress,
|
|
||||||
leaveOpen: true);
|
|
||||||
originalStream.CopyTo(compressionStream);
|
|
||||||
}
|
|
||||||
compressedStream.Position = 0;
|
|
||||||
WriteTag(writer, new Tag(DataType.MiCompressed, (int)(compressedStream.Length + 6)));
|
|
||||||
writer.Write((byte)0x78);
|
|
||||||
writer.Write((byte)0x9c);
|
|
||||||
compressedStream.CopyTo(writer.BaseStream);
|
|
||||||
writer.Write(BitConverter.GetBytes(crc).Reverse().ToArray());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -8,7 +10,7 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets default options.
|
/// Gets default options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static MatFileWriterOptions Default => new()
|
public static MatFileWriterOptions Default => new MatFileWriterOptions
|
||||||
{
|
{
|
||||||
UseCompression = CompressionUsage.Always,
|
UseCompression = CompressionUsage.Always,
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -47,7 +49,7 @@ namespace MatFileHandler
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var rowAndColumn = GetRowAndColumn(list);
|
var rowAndColumn = GetRowAndColumn(list);
|
||||||
return DataDictionary.TryGetValue(rowAndColumn, out var result) ? result : default;
|
return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default(T);
|
||||||
}
|
}
|
||||||
set => DataDictionary[GetRowAndColumn(list)] = value;
|
set => DataDictionary[GetRowAndColumn(list)] = value;
|
||||||
}
|
}
|
||||||
@ -59,7 +61,7 @@ namespace MatFileHandler
|
|||||||
public override double[] ConvertToDoubleArray()
|
public override double[] ConvertToDoubleArray()
|
||||||
{
|
{
|
||||||
var data = ((IArrayOf<T>)this).Data;
|
var data = ((IArrayOf<T>)this).Data;
|
||||||
return data as double[] ?? data.Select(x => Convert.ToDouble(x, System.Globalization.CultureInfo.InvariantCulture)).ToArray();
|
return data as double[] ?? data.Select(x => Convert.ToDouble(x)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -73,7 +75,7 @@ namespace MatFileHandler
|
|||||||
var result = new double[Dimensions[0], Dimensions[1]];
|
var result = new double[Dimensions[0], Dimensions[1]];
|
||||||
foreach (var pair in Data)
|
foreach (var pair in Data)
|
||||||
{
|
{
|
||||||
result[pair.Key.row, pair.Key.column] = Convert.ToDouble(pair.Value, System.Globalization.CultureInfo.InvariantCulture);
|
result[pair.Key.row, pair.Key.column] = Convert.ToDouble(pair.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -91,12 +93,15 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
private (int row, int column) GetRowAndColumn(int[] indices)
|
private (int row, int column) GetRowAndColumn(int[] indices)
|
||||||
{
|
{
|
||||||
return indices.Length switch
|
switch (indices.Length)
|
||||||
{
|
{
|
||||||
1 => (indices[0] % Dimensions[0], indices[0] / Dimensions[0]),
|
case 1:
|
||||||
2 => (indices[0], indices[1]),
|
return (indices[0] % Dimensions[0], indices[0] / Dimensions[0]);
|
||||||
_ => throw new NotSupportedException("Invalid index for sparse array."),
|
case 2:
|
||||||
};
|
return (indices[0], indices[1]);
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException("Invalid index for sparse array.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -67,7 +69,7 @@ namespace MatFileHandler
|
|||||||
"Cannot set structure elements via this[params int[]] indexer. Use this[string, int[]] instead.");
|
"Cannot set structure elements via this[params int[]] indexer. Use this[string, int[]] instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatStructureArrayElement ExtractStructure(int i)
|
private IReadOnlyDictionary<string, IArray> ExtractStructure(int i)
|
||||||
{
|
{
|
||||||
return new MatStructureArrayElement(this, i);
|
return new MatStructureArrayElement(this, i);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
namespace MatFileHandler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parser for object data.
|
|
||||||
/// </summary>
|
|
||||||
internal static class ObjectParser
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Parse object data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uintArray">Opaque link array.</param>
|
|
||||||
/// <param name="subsystemData">Current subsystem data.</param>
|
|
||||||
/// <returns>Parsed object.</returns>
|
|
||||||
public static IArray ParseObject(MatNumericalArrayOf<uint> uintArray, SubsystemData subsystemData)
|
|
||||||
{
|
|
||||||
var (dimensions, indexToObjectId, classIndex) = DataElementReader.ParseOpaqueData(uintArray.Data);
|
|
||||||
return new OpaqueLink(
|
|
||||||
uintArray.Name,
|
|
||||||
string.Empty,
|
|
||||||
string.Empty,
|
|
||||||
dimensions,
|
|
||||||
uintArray,
|
|
||||||
indexToObjectId,
|
|
||||||
classIndex,
|
|
||||||
subsystemData);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
@ -24,14 +26,12 @@ namespace MatFileHandler
|
|||||||
/// <param name="className">Class name.</param>
|
/// <param name="className">Class name.</param>
|
||||||
/// <param name="dimensions">Dimensions of the object.</param>
|
/// <param name="dimensions">Dimensions of the object.</param>
|
||||||
/// <param name="rawData">Raw object's data.</param>
|
/// <param name="rawData">Raw object's data.</param>
|
||||||
/// <param name="subsystemData">Subsystem data.</param>
|
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData)
|
||||||
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData, SubsystemData subsystemData)
|
|
||||||
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
|
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
|
||||||
{
|
{
|
||||||
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
|
||||||
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
ClassName = className ?? throw new ArgumentNullException(nameof(className));
|
||||||
RawData = rawData ?? throw new ArgumentNullException(nameof(rawData));
|
RawData = rawData ?? throw new ArgumentNullException(nameof(rawData));
|
||||||
SubsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -49,11 +49,6 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string TypeDescription { get; }
|
public string TypeDescription { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets subsystem data.
|
|
||||||
/// </summary>
|
|
||||||
public SubsystemData SubsystemData { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Complex[]? ConvertToComplexArray() => null;
|
public override Complex[]? ConvertToComplexArray() => null;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -10,6 +12,8 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class OpaqueLink : Opaque, IMatObject
|
internal class OpaqueLink : Opaque, IMatObject
|
||||||
{
|
{
|
||||||
|
private readonly SubsystemData subsystemData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,10 +34,11 @@ namespace MatFileHandler
|
|||||||
int[] indexToObjectId,
|
int[] indexToObjectId,
|
||||||
int classIndex,
|
int classIndex,
|
||||||
SubsystemData subsystemData)
|
SubsystemData subsystemData)
|
||||||
: base(name, typeDescription, className, dimensions, data, subsystemData)
|
: base(name, typeDescription, className, dimensions, data)
|
||||||
{
|
{
|
||||||
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
|
||||||
ClassIndex = classIndex;
|
ClassIndex = classIndex;
|
||||||
|
this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -69,14 +74,22 @@ namespace MatFileHandler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets name of this object's class.
|
/// Gets name of this object's class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string ClassName => SubsystemData.ClassInformation[ClassIndex].Name;
|
public override string ClassName => subsystemData.ClassInformation[ClassIndex].Name;
|
||||||
|
|
||||||
private string[] FieldNamesArray => SubsystemData.ClassInformation[ClassIndex].FieldNames.ToArray();
|
private string[] FieldNamesArray => subsystemData.ClassInformation[ClassIndex].FieldNames.ToArray();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IArray this[string field, params int[] list]
|
public IArray this[string field, params int[] list]
|
||||||
{
|
{
|
||||||
get => TryGetValue(field, out var result, list) ? result! : throw new ArgumentOutOfRangeException(nameof(list));
|
get
|
||||||
|
{
|
||||||
|
if (TryGetValue(field, out var result, list))
|
||||||
|
{
|
||||||
|
return result!;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
set => throw new NotImplementedException();
|
set => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +100,7 @@ namespace MatFileHandler
|
|||||||
set => throw new NotImplementedException();
|
set => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private OpaqueObjectArrayElement ExtractObject(int i)
|
private IReadOnlyDictionary<string, IArray> ExtractObject(int i)
|
||||||
{
|
{
|
||||||
return new OpaqueObjectArrayElement(this, i);
|
return new OpaqueObjectArrayElement(this, i);
|
||||||
}
|
}
|
||||||
@ -95,8 +108,8 @@ namespace MatFileHandler
|
|||||||
private bool TryGetValue(string field, out IArray? output, params int[] list)
|
private bool TryGetValue(string field, out IArray? output, params int[] list)
|
||||||
{
|
{
|
||||||
var index = Dimensions.DimFlatten(list);
|
var index = Dimensions.DimFlatten(list);
|
||||||
var maybeFieldIndex = SubsystemData.ClassInformation[ClassIndex].FindField(field);
|
var maybeFieldIndex = subsystemData.ClassInformation[ClassIndex].FindField(field);
|
||||||
if (maybeFieldIndex is not int fieldIndex)
|
if (!(maybeFieldIndex is int fieldIndex))
|
||||||
{
|
{
|
||||||
output = default;
|
output = default;
|
||||||
return false;
|
return false;
|
||||||
@ -109,9 +122,9 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
var objectId = IndexToObjectId[index];
|
var objectId = IndexToObjectId[index];
|
||||||
var objectInfo = SubsystemData.ObjectInformation[objectId];
|
var objectInfo = subsystemData.ObjectInformation[objectId];
|
||||||
var fieldId = objectInfo.FieldLinks[fieldIndex];
|
var fieldId = objectInfo.FieldLinks[fieldIndex];
|
||||||
output = SubsystemData.Data[fieldId];
|
output = subsystemData.Data[fieldId];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +174,8 @@ namespace MatFileHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CS8767
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
#pragma warning disable CS8767
|
||||||
public bool TryGetValue(string key, out IArray? value)
|
public bool TryGetValue(string key, out IArray? value)
|
||||||
#pragma warning restore CS8767
|
#pragma warning restore CS8767
|
||||||
{
|
{
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A stream which wraps another stream and tracks the number of bytes read
|
|
||||||
/// for the purpose of adjusting for padding.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class PositionTrackingStream : Stream
|
|
||||||
{
|
|
||||||
private readonly Stream _baseStream;
|
|
||||||
private long _position;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="PositionTrackingStream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseStream">The stream to wrap.</param>
|
|
||||||
public PositionTrackingStream(Stream baseStream)
|
|
||||||
{
|
|
||||||
_baseStream = baseStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanRead => _baseStream.CanRead;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Length => _baseStream.Length;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => _position;
|
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Flush() => _baseStream.Flush();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
var bytesRead = _baseStream.Read(buffer, offset, count);
|
|
||||||
|
|
||||||
_position += bytesRead;
|
|
||||||
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void SetLength(long value) => throw new NotSupportedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_baseStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@ -8,6 +10,7 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class StringAdapter
|
public class StringAdapter
|
||||||
{
|
{
|
||||||
|
private readonly int[] dimensions;
|
||||||
private readonly string[] strings;
|
private readonly string[] strings;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -25,13 +28,13 @@ namespace MatFileHandler
|
|||||||
var binaryData = matObject["any", 0] as IArrayOf<ulong>
|
var binaryData = matObject["any", 0] as IArrayOf<ulong>
|
||||||
?? throw new HandlerException("Cannot extract string data.");
|
?? throw new HandlerException("Cannot extract string data.");
|
||||||
|
|
||||||
(Dimensions, strings) = ParseBinaryData(binaryData.Data);
|
(dimensions, strings) = ParseBinaryData(binaryData.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets string array dimensions.
|
/// Gets string array dimensions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int[] Dimensions { get; }
|
public int[] Dimensions => dimensions;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets string object at given position.
|
/// Gets string object at given position.
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace MatFileHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A stream which reads a finite section of another stream.
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class Substream : Stream
|
|
||||||
{
|
|
||||||
private readonly Stream _baseStream;
|
|
||||||
private long _bytesRead;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Substream"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="baseStream">The <see cref="Stream"/> to wrap.</param>
|
|
||||||
/// <param name="length">The number of bytes readable from this <see cref="Substream"/>.</param>
|
|
||||||
public Substream(Stream baseStream, long length)
|
|
||||||
{
|
|
||||||
_baseStream = baseStream;
|
|
||||||
Length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanRead => _baseStream.CanRead;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Length { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => _bytesRead;
|
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Flush() => _baseStream.Flush();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
var bytesRead = _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - _bytesRead));
|
|
||||||
|
|
||||||
_bytesRead += bytesRead;
|
|
||||||
|
|
||||||
return bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void SetLength(long value) => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@ -27,18 +29,15 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="classInformation">Information about the classes.</param>
|
/// <param name="classInformation">Information about the classes.</param>
|
||||||
/// <param name="objectInformation">Information about the objects.</param>
|
/// <param name="objectInformation">Information about the objects.</param>
|
||||||
/// <param name="fieldNames">Field names.</param>
|
|
||||||
/// <param name="data">Field values.</param>
|
/// <param name="data">Field values.</param>
|
||||||
public SubsystemData(
|
public SubsystemData(
|
||||||
Dictionary<int, ClassInfo> classInformation,
|
Dictionary<int, ClassInfo> classInformation,
|
||||||
Dictionary<int, ObjectInfo> objectInformation,
|
Dictionary<int, ObjectInfo> objectInformation,
|
||||||
string[] fieldNames,
|
|
||||||
Dictionary<int, IArray> data)
|
Dictionary<int, IArray> data)
|
||||||
{
|
{
|
||||||
_realData = new RealSubsystemData(
|
_realData = new RealSubsystemData(
|
||||||
classInformation,
|
classInformation,
|
||||||
objectInformation,
|
objectInformation,
|
||||||
fieldNames,
|
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +59,6 @@ namespace MatFileHandler
|
|||||||
public Dictionary<int, ObjectInfo> ObjectInformation =>
|
public Dictionary<int, ObjectInfo> ObjectInformation =>
|
||||||
_realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing.");
|
_realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing.");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets field names.
|
|
||||||
/// </summary>
|
|
||||||
public string[] FieldNames =>
|
|
||||||
_realData?.FieldNames ?? throw new HandlerException("Subsystem data missing.");
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize this object from another object.
|
/// Initialize this object from another object.
|
||||||
/// This ugly hack allows us to read the opaque objects and store references to
|
/// This ugly hack allows us to read the opaque objects and store references to
|
||||||
@ -78,7 +71,6 @@ namespace MatFileHandler
|
|||||||
_realData = new RealSubsystemData(
|
_realData = new RealSubsystemData(
|
||||||
data.ClassInformation,
|
data.ClassInformation,
|
||||||
data.ObjectInformation,
|
data.ObjectInformation,
|
||||||
data.FieldNames,
|
|
||||||
data.Data);
|
data.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +109,12 @@ namespace MatFileHandler
|
|||||||
/// <returns>Field index.</returns>
|
/// <returns>Field index.</returns>
|
||||||
public int? FindField(string fieldName)
|
public int? FindField(string fieldName)
|
||||||
{
|
{
|
||||||
return fieldToIndex.TryGetValue(fieldName, out var index) ? index : null;
|
if (fieldToIndex.TryGetValue(fieldName, out var index))
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,17 +147,14 @@ namespace MatFileHandler
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="classInformation">Class information.</param>
|
/// <param name="classInformation">Class information.</param>
|
||||||
/// <param name="objectInformation">Object information.</param>
|
/// <param name="objectInformation">Object information.</param>
|
||||||
/// <param name="fieldNames">Field names.</param>
|
|
||||||
/// <param name="data">Data.</param>
|
/// <param name="data">Data.</param>
|
||||||
public RealSubsystemData(
|
public RealSubsystemData(
|
||||||
Dictionary<int, ClassInfo> classInformation,
|
Dictionary<int, ClassInfo> classInformation,
|
||||||
Dictionary<int, ObjectInfo> objectInformation,
|
Dictionary<int, ObjectInfo> objectInformation,
|
||||||
string[] fieldNames,
|
|
||||||
IReadOnlyDictionary<int, IArray> data)
|
IReadOnlyDictionary<int, IArray> data)
|
||||||
{
|
{
|
||||||
ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation));
|
ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation));
|
||||||
ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation));
|
ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation));
|
||||||
FieldNames = fieldNames;
|
|
||||||
Data = data ?? throw new ArgumentNullException(nameof(data));
|
Data = data ?? throw new ArgumentNullException(nameof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,11 +172,6 @@ namespace MatFileHandler
|
|||||||
/// Gets information about all the objects occurring in the file.
|
/// Gets information about all the objects occurring in the file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<int, ObjectInfo> ObjectInformation { get; }
|
public Dictionary<int, ObjectInfo> ObjectInformation { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets field names.
|
|
||||||
/// </summary>
|
|
||||||
public string[] FieldNames { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -40,7 +42,7 @@ namespace MatFileHandler
|
|||||||
var embeddedObjectPositionsToValues = ReadEmbeddedObjectPositionsToValues(info, offsets, numberOfEmbeddedObjects);
|
var embeddedObjectPositionsToValues = ReadEmbeddedObjectPositionsToValues(info, offsets, numberOfEmbeddedObjects);
|
||||||
var numberOfObjects = ((offsets[5] - offsets[4]) / 24) - 1;
|
var numberOfObjects = ((offsets[5] - offsets[4]) / 24) - 1;
|
||||||
var objectClasses = ReadObjectClassInformations(info, offsets, numberOfObjects);
|
var objectClasses = ReadObjectClassInformations(info, offsets, numberOfObjects);
|
||||||
var numberOfObjectPositions = objectClasses.NumberOfObjectPositions;
|
var numberOfObjectPositions = objectClasses.Values.Count(x => x.ObjectPosition != 0);
|
||||||
var objectPositionsToValues = ReadObjectPositionsToValues(info, offsets, numberOfObjectPositions);
|
var objectPositionsToValues = ReadObjectPositionsToValues(info, offsets, numberOfObjectPositions);
|
||||||
var (classInformation, objectInformation) =
|
var (classInformation, objectInformation) =
|
||||||
GatherClassAndObjectInformation(
|
GatherClassAndObjectInformation(
|
||||||
@ -56,7 +58,7 @@ namespace MatFileHandler
|
|||||||
data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData);
|
data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SubsystemData(classInformation, objectInformation, fieldNames, data);
|
return new SubsystemData(classInformation, objectInformation, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions)
|
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions)
|
||||||
@ -66,7 +68,7 @@ namespace MatFileHandler
|
|||||||
return ReadObjectPositionsToValuesMapping(reader, numberOfObjectPositions);
|
return ReadObjectPositionsToValuesMapping(reader, numberOfObjectPositions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectClasses ReadObjectClassInformations(byte[] info, int[] offsets, int numberOfObjects)
|
private static Dictionary<int, ObjectClassInformation> ReadObjectClassInformations(byte[] info, int[] offsets, int numberOfObjects)
|
||||||
{
|
{
|
||||||
using var stream = new MemoryStream(info, offsets[4], offsets[5] - offsets[4]);
|
using var stream = new MemoryStream(info, offsets[4], offsets[5] - offsets[4]);
|
||||||
using var reader = new BinaryReader(stream);
|
using var reader = new BinaryReader(stream);
|
||||||
@ -100,7 +102,7 @@ namespace MatFileHandler
|
|||||||
GatherClassAndObjectInformation(
|
GatherClassAndObjectInformation(
|
||||||
Dictionary<int, string> classIdToName,
|
Dictionary<int, string> classIdToName,
|
||||||
string[] fieldNames,
|
string[] fieldNames,
|
||||||
ObjectClasses objectClasses,
|
Dictionary<int, ObjectClassInformation> objectClasses,
|
||||||
Dictionary<int, Dictionary<int, int>> objectPositionsToValues,
|
Dictionary<int, Dictionary<int, int>> objectPositionsToValues,
|
||||||
Dictionary<int, Dictionary<int, int>> embeddedObjectPositionsToValues)
|
Dictionary<int, Dictionary<int, int>> embeddedObjectPositionsToValues)
|
||||||
{
|
{
|
||||||
@ -111,8 +113,8 @@ namespace MatFileHandler
|
|||||||
var fieldIds = new SortedSet<int>();
|
var fieldIds = new SortedSet<int>();
|
||||||
foreach (var objectPosition in objectPositionsToValues.Keys)
|
foreach (var objectPosition in objectPositionsToValues.Keys)
|
||||||
{
|
{
|
||||||
var foundClassId = objectClasses.GetClassIdByObjectPosition(objectPosition);
|
var keyValuePair = objectClasses.First(pair => pair.Value.ObjectPosition == objectPosition);
|
||||||
if (foundClassId != classId)
|
if (keyValuePair.Value.ClassId != classId)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -125,8 +127,8 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
foreach (var objectPosition in embeddedObjectPositionsToValues.Keys)
|
foreach (var objectPosition in embeddedObjectPositionsToValues.Keys)
|
||||||
{
|
{
|
||||||
var foundClassId = objectClasses.GetClassIdByEmbeddedObjectPosition(objectPosition);
|
var keyValuePair = objectClasses.First(pair => pair.Value.EmbeddedObjectPosition == objectPosition);
|
||||||
if (foundClassId != classId)
|
if (keyValuePair.Value.ClassId != classId)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -149,14 +151,15 @@ namespace MatFileHandler
|
|||||||
var objectInfos = new Dictionary<int, SubsystemData.ObjectInfo>();
|
var objectInfos = new Dictionary<int, SubsystemData.ObjectInfo>();
|
||||||
foreach (var objectPosition in objectPositionsToValues.Keys)
|
foreach (var objectPosition in objectPositionsToValues.Keys)
|
||||||
{
|
{
|
||||||
var foundKey = objectClasses.GetKeyByObjectPosition(objectPosition);
|
var keyValuePair = objectClasses.First(pair => pair.Value.ObjectPosition == objectPosition);
|
||||||
objectInfos[foundKey] = new SubsystemData.ObjectInfo(objectPositionsToValues[objectPosition]);
|
objectInfos[keyValuePair.Key] = new SubsystemData.ObjectInfo(objectPositionsToValues[objectPosition]);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var embeddedObjectPosition in embeddedObjectPositionsToValues.Keys)
|
foreach (var objectPosition in embeddedObjectPositionsToValues.Keys)
|
||||||
{
|
{
|
||||||
var foundKey = objectClasses.GetKeyByEmbeddedObjectPosition(embeddedObjectPosition);
|
var keyValuePair = objectClasses.First(pair => pair.Value.EmbeddedObjectPosition == objectPosition);
|
||||||
objectInfos[foundKey] = new SubsystemData.ObjectInfo(embeddedObjectPositionsToValues[embeddedObjectPosition]);
|
objectInfos[keyValuePair.Key] =
|
||||||
|
new SubsystemData.ObjectInfo(embeddedObjectPositionsToValues[objectPosition]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (classInfos, objectInfos);
|
return (classInfos, objectInfos);
|
||||||
@ -238,40 +241,24 @@ namespace MatFileHandler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectClasses ReadObjectClasses(
|
private static Dictionary<int, ObjectClassInformation> ReadObjectClasses(
|
||||||
BinaryReader reader,
|
BinaryReader reader,
|
||||||
int numberOfObjects)
|
int numberOfObjects)
|
||||||
{
|
{
|
||||||
var result = new Dictionary<int, ObjectClassInformation>();
|
var result = new Dictionary<int, ObjectClassInformation>();
|
||||||
var classIdFromObjectPosition = new Dictionary<int, int>();
|
|
||||||
var classIdFromEmbeddedObjectPosition = new Dictionary<int, int>();
|
|
||||||
var keyFromObjectPosition = new Dictionary<int, int>();
|
|
||||||
var keyFromEmbeddedObjectPosition = new Dictionary<int, int>();
|
|
||||||
reader.ReadBytes(24);
|
reader.ReadBytes(24);
|
||||||
var numberOfObjectPositions = 0;
|
|
||||||
for (var i = 0; i < numberOfObjects; i++)
|
for (var i = 0; i < numberOfObjects; i++)
|
||||||
{
|
{
|
||||||
var classId = reader.ReadInt32();
|
var classId = reader.ReadInt32();
|
||||||
reader.ReadBytes(8);
|
reader.ReadBytes(8);
|
||||||
var embeddedObjectPosition = reader.ReadInt32();
|
var embeddedObjectPosition = reader.ReadInt32();
|
||||||
var objectPosition = reader.ReadInt32();
|
var objectPosition = reader.ReadInt32();
|
||||||
var loadingOrder = reader.ReadInt32(); // Not used.
|
var loadingOrder = reader.ReadInt32();
|
||||||
classIdFromObjectPosition[objectPosition] = classId;
|
result[i + 1] =
|
||||||
classIdFromEmbeddedObjectPosition[embeddedObjectPosition] = classId;
|
new ObjectClassInformation(embeddedObjectPosition, objectPosition, loadingOrder, classId);
|
||||||
keyFromObjectPosition[objectPosition] = i + 1;
|
|
||||||
keyFromEmbeddedObjectPosition[embeddedObjectPosition] = i + 1;
|
|
||||||
if (objectPosition != 0)
|
|
||||||
{
|
|
||||||
numberOfObjectPositions++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ObjectClasses(
|
return result;
|
||||||
classIdFromObjectPosition,
|
|
||||||
classIdFromEmbeddedObjectPosition,
|
|
||||||
keyFromObjectPosition,
|
|
||||||
keyFromEmbeddedObjectPosition,
|
|
||||||
numberOfObjectPositions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValuesMapping(
|
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValuesMapping(
|
||||||
@ -301,60 +288,45 @@ namespace MatFileHandler
|
|||||||
{
|
{
|
||||||
var next = BitConverter.ToInt32(bytes, position);
|
var next = BitConverter.ToInt32(bytes, position);
|
||||||
position += 4;
|
position += 4;
|
||||||
if (next == bytes.Length)
|
if (next == 0)
|
||||||
{
|
{
|
||||||
|
if (position % 8 != 0)
|
||||||
|
{
|
||||||
|
position += 4;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
offsets.Add(next);
|
offsets.Add(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (offsets.ToArray(), 40);
|
return (offsets.ToArray(), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)
|
private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)
|
||||||
{
|
{
|
||||||
if (array is MatNumericalArrayOf<uint> uintArray &&
|
if (array is MatNumericalArrayOf<uint> uintArray)
|
||||||
uintArray.Data.Length == 6 &&
|
|
||||||
uintArray.Data[0] == 3707764736u)
|
|
||||||
{
|
{
|
||||||
return ObjectParser.ParseObject(uintArray, subsystemData);
|
if (uintArray.Data[0] == 3707764736u)
|
||||||
}
|
|
||||||
|
|
||||||
if (array is MatCellArray cellArray)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < cellArray.Data.Length; i++)
|
|
||||||
{
|
{
|
||||||
var cell = cellArray.Data[i];
|
var (dimensions, indexToObjectId, classIndex) = DataElementReader.ParseOpaqueData(uintArray.Data);
|
||||||
var transformedCell = TransformOpaqueData(cell, subsystemData);
|
return new OpaqueLink(
|
||||||
cellArray.Data[i] = transformedCell;
|
uintArray.Name,
|
||||||
}
|
string.Empty,
|
||||||
}
|
string.Empty,
|
||||||
|
dimensions,
|
||||||
if (array is MatStructureArray structureArray)
|
uintArray,
|
||||||
{
|
indexToObjectId,
|
||||||
var newFields = new Dictionary<string, List<IArray>>();
|
classIndex,
|
||||||
foreach (var pair in structureArray.Fields)
|
subsystemData);
|
||||||
{
|
|
||||||
var values = pair.Value;
|
|
||||||
var transformedValues = new List<IArray>(values.Count);
|
|
||||||
foreach (var value in values)
|
|
||||||
{
|
|
||||||
var transformedValue = TransformOpaqueData(value, subsystemData);
|
|
||||||
transformedValues.Add(transformedValue);
|
|
||||||
}
|
|
||||||
newFields[pair.Key] = transformedValues;
|
|
||||||
}
|
|
||||||
foreach (var pair in newFields)
|
|
||||||
{
|
|
||||||
structureArray.Fields[pair.Key] = pair.Value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly struct ObjectClassInformation
|
private struct ObjectClassInformation
|
||||||
{
|
{
|
||||||
public ObjectClassInformation(int embeddedObjectPosition, int objectPosition, int loadingOrder, int classId)
|
public ObjectClassInformation(int embeddedObjectPosition, int objectPosition, int loadingOrder, int classId)
|
||||||
{
|
{
|
||||||
@ -372,41 +344,5 @@ namespace MatFileHandler
|
|||||||
|
|
||||||
public int ObjectPosition { get; }
|
public int ObjectPosition { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ObjectClasses
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, int> _classIdFromObjectPosition;
|
|
||||||
private readonly Dictionary<int, int> _classIdFromEmbeddedObjectPosition;
|
|
||||||
private readonly Dictionary<int, int> _keyFromObjectPosition;
|
|
||||||
private readonly Dictionary<int, int> _keyFromEmbeddedObjectPosition;
|
|
||||||
|
|
||||||
public ObjectClasses(
|
|
||||||
Dictionary<int, int> classIdFromObjectPosition,
|
|
||||||
Dictionary<int, int> classIdFromEmbeddedObjectPosition,
|
|
||||||
Dictionary<int, int> keyFromObjectPosition,
|
|
||||||
Dictionary<int, int> keyFromEmbeddedObjectPosition,
|
|
||||||
int numberOfObjectPositions)
|
|
||||||
{
|
|
||||||
_classIdFromObjectPosition = classIdFromObjectPosition;
|
|
||||||
_classIdFromEmbeddedObjectPosition = classIdFromEmbeddedObjectPosition;
|
|
||||||
_keyFromObjectPosition = keyFromObjectPosition;
|
|
||||||
_keyFromEmbeddedObjectPosition = keyFromEmbeddedObjectPosition;
|
|
||||||
NumberOfObjectPositions = numberOfObjectPositions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int NumberOfObjectPositions { get; }
|
|
||||||
|
|
||||||
public int GetClassIdByObjectPosition(int objectPosition)
|
|
||||||
=> _classIdFromObjectPosition[objectPosition];
|
|
||||||
|
|
||||||
public int GetClassIdByEmbeddedObjectPosition(int embeddedObjectPosition)
|
|
||||||
=> _classIdFromEmbeddedObjectPosition[embeddedObjectPosition];
|
|
||||||
|
|
||||||
public int GetKeyByObjectPosition(int objectPosition)
|
|
||||||
=> _keyFromObjectPosition[objectPosition];
|
|
||||||
|
|
||||||
public int GetKeyByEmbeddedObjectPosition(int embeddedObjectPosition)
|
|
||||||
=> _keyFromEmbeddedObjectPosition[embeddedObjectPosition];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@ -85,9 +87,9 @@ namespace MatFileHandler
|
|||||||
.Where(i => VariableNames[i] == variableName)
|
.Where(i => VariableNames[i] == variableName)
|
||||||
.Select(i => (int?)i)
|
.Select(i => (int?)i)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
if (maybeIndex is not int index)
|
if (!(maybeIndex is int index))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(variableName), $"Variable '{variableName}' not found.");
|
throw new IndexOutOfRangeException($"Variable '{variableName}' not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = matObject["data"] as ICellArray
|
var data = matObject["data"] as ICellArray
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Copyright 2017-2018 Alexander Luzgarev
|
||||||
|
|
||||||
namespace MatFileHandler
|
namespace MatFileHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# MatFileHandler
|
# MatFileHandler
|
||||||
|
|
||||||
[](https://www.nuget.org/packages/MatFileHandler/absoluteLatest)
|
|
||||||
|
|
||||||
MatFileHandler is a .NET library for reading and writing MATLAB .mat files
|
MatFileHandler is a .NET library for reading and writing MATLAB .mat files
|
||||||
(of so-called "Level 5"). MatFileHandler supports numerical arrays,
|
(of so-called "Level 5"). MatFileHandler supports numerical arrays,
|
||||||
logical arrays, sparse arrays, char arrays, cell arrays and structure arrays.
|
logical arrays, sparse arrays, char arrays, cell arrays and structure arrays.
|
||||||
@ -15,8 +13,9 @@ You can find (partial) technical description of MATLAB object data format
|
|||||||
This document briefly describes how to perform simple operations with .mat files
|
This document briefly describes how to perform simple operations with .mat files
|
||||||
using MatFileHandler.
|
using MatFileHandler.
|
||||||
|
|
||||||
If you have questions and/or ideas, you can [file a new issue](https://git.mahalex.net/mahalex/MatFileHandler/issues/new)
|
If you have questions and/or ideas, you can [file a new issue]
|
||||||
or contact me directly at <mahalex@gmail.com>.
|
(https://github.com/mahalex/MatFileHandler/issues/new) or contact me directly at
|
||||||
|
<mahalex@gmail.com>.
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
@ -204,7 +203,7 @@ classdef Point
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
We omit any methods (and constructors) such a class might have, because they are
|
We omit any methods (and constructos) such a class might have, because they are
|
||||||
not stored when you save an object of a class into a `.mat` file.
|
not stored when you save an object of a class into a `.mat` file.
|
||||||
|
|
||||||
Imagine that you have a `1x2 Point` object array `p` (an array of two points)
|
Imagine that you have a `1x2 Point` object array `p` (an array of two points)
|
||||||
|
@ -11,9 +11,9 @@ variables:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- task: UseDotNet@2
|
- task: UseDotNet@2
|
||||||
displayName: 'Use .NET Core SDK 9.x'
|
displayName: 'Use .NET Core SDK 5.x'
|
||||||
inputs:
|
inputs:
|
||||||
version: 9.x
|
version: 5.x
|
||||||
|
|
||||||
- script: dotnet build --configuration $(buildConfiguration)
|
- script: dotnet build --configuration $(buildConfiguration)
|
||||||
displayName: 'dotnet build $(buildConfiguration)'
|
displayName: 'dotnet build $(buildConfiguration)'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user