Fix all the warnings

This commit is contained in:
Alexander Luzgarev 2025-04-10 20:12:29 +02:00
parent 306992f969
commit d87cc2c99c
36 changed files with 724 additions and 748 deletions

246
.editorconfig Normal file
View File

@ -0,0 +1,246 @@
# 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
#### 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

View File

@ -7,7 +7,7 @@ namespace MatFileHandler.Tests
/// <summary> /// <summary>
/// A filename convention based on file extensions. /// A filename convention based on file extensions.
/// </summary> /// </summary>
internal class ExtensionTestFilenameConvention : ITestFilenameConvention internal sealed class ExtensionTestFilenameConvention : ITestFilenameConvention
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExtensionTestFilenameConvention"/> class. /// Initializes a new instance of the <see cref="ExtensionTestFilenameConvention"/> class.

View File

@ -2,10 +2,9 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461;net472;net8.0</TargetFrameworks> <TargetFrameworks>net461;net472;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<LangVersion>10.0</LangVersion> <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> <ItemGroup>

View File

@ -590,7 +590,7 @@ namespace MatFileHandler.Tests
/// Test four-dimensional arrays. /// Test four-dimensional arrays.
/// </summary> /// </summary>
[Theory, MemberData(nameof(TestDataFactories))] [Theory, MemberData(nameof(TestDataFactories))]
public void Test_4DArrays(AbstractTestDataFactory<IMatFile> testFactory) public void Test4DArrays(AbstractTestDataFactory<IMatFile> testFactory)
{ {
var matFile = testFactory["issue20.mat"]; var matFile = testFactory["issue20.mat"];
var obj = matFile["a4d"].Value; var obj = matFile["a4d"].Value;

View File

@ -0,0 +1,9 @@
namespace MatFileHandler.Tests;
public enum MatFileWriterOptionsForTests
{
Undefined = 0,
None,
Always,
Never,
}

View File

@ -17,8 +17,8 @@ namespace MatFileHandler.Tests
/// <summary> /// <summary>
/// Test writing a simple Double array. /// Test writing a simple Double array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestWrite(MatFileWritingMethod method) public void TestWrite(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
var builder = new DataBuilder(); var builder = new DataBuilder();
var array = builder.NewArray<double>(1, 2); var array = builder.NewArray<double>(1, 2);
@ -26,7 +26,7 @@ namespace MatFileHandler.Tests
array[1] = 17.0; array[1] = 17.0;
var variable = builder.NewVariable("test", array); var variable = builder.NewVariable("test", array);
var actual = builder.NewFile(new[] { variable }); var actual = builder.NewFile(new[] { variable });
MatCompareWithTestData("good", "double-array", actual, method); MatCompareWithTestData("good", "double-array", actual, method, options);
} }
/// <summary> /// <summary>
@ -51,8 +51,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(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestLimits(MatFileWritingMethod method) public void TestLimits(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
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));
@ -64,14 +64,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); MatCompareWithTestData("good", "limits", actual, method, options);
} }
/// <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(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestLimitsComplex(MatFileWritingMethod method) public void TestLimitsComplex(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
var builder = new DataBuilder(); var builder = new DataBuilder();
var int8Complex = builder.NewVariable( var int8Complex = builder.NewVariable(
@ -103,26 +103,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); MatCompareWithTestData("good", "limits_complex", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a wide-Unicode symbol. /// Test writing a wide-Unicode symbol.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestUnicodeWide(MatFileWritingMethod method) public void TestUnicodeWide(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
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); MatCompareWithTestData("good", "unicode-wide", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a sparse array. /// Test writing a sparse array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestSparseArray(MatFileWritingMethod method) public void TestSparseArray(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
var builder = new DataBuilder(); var builder = new DataBuilder();
var sparseArray = builder.NewSparseArray<double>(4, 5); var sparseArray = builder.NewSparseArray<double>(4, 5);
@ -132,14 +132,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); MatCompareWithTestData("good", "sparse", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a structure array. /// Test writing a structure array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestStructure(MatFileWritingMethod method) public void TestStructure(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
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);
@ -160,27 +160,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); MatCompareWithTestData("good", "struct", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a logical array. /// Test writing a logical array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestLogical(MatFileWritingMethod method) public void TestLogical(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
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); MatCompareWithTestData("good", "logical", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a sparse logical array. /// Test writing a sparse logical array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestSparseLogical(MatFileWritingMethod method) public void TestSparseLogical(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
var builder = new DataBuilder(); var builder = new DataBuilder();
var array = builder.NewSparseArray<bool>(2, 3); var array = builder.NewSparseArray<bool>(2, 3);
@ -190,14 +190,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); MatCompareWithTestData("good", "sparse_logical", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a sparse complex array. /// Test writing a sparse complex array.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestSparseComplex(MatFileWritingMethod method) public void TestSparseComplex(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
var builder = new DataBuilder(); var builder = new DataBuilder();
var array = builder.NewSparseArray<Complex>(2, 2); var array = builder.NewSparseArray<Complex>(2, 2);
@ -206,41 +206,44 @@ 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); MatCompareWithTestData("good", "sparse_complex", actual, method, options);
} }
/// <summary> /// <summary>
/// Test writing a global variable. /// Test writing a global variable.
/// </summary> /// </summary>
[Theory, MemberData(nameof(MatFileWritingMethods))] [Theory, MemberData(nameof(MatFileWritingTestData))]
public void TestGlobal(MatFileWritingMethod method) public void TestGlobal(MatFileWritingMethod method, MatFileWriterOptionsForTests options)
{ {
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); MatCompareWithTestData("good", "global", actual, method, options);
} }
/// <summary> /// <summary>
/// Various writing methods for testing writing of .mat files. /// Various writing methods for testing writing of .mat files.
/// </summary> /// </summary>
public static TheoryData<MatFileWritingMethod> MatFileWritingMethods public static TheoryData<MatFileWritingMethod, MatFileWriterOptionsForTests> MatFileWritingTestData
{ {
get get
{ {
return new TheoryData<MatFileWritingMethod> var always = new MatFileWriterOptions { UseCompression = CompressionUsage.Always};
var never = new MatFileWriterOptions { UseCompression = CompressionUsage.Never };
var data = new TheoryData<MatFileWritingMethod, MatFileWriterOptionsForTests>
{ {
new MatFileWritingToMemoryStream(null), { MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.None },
new MatFileWritingToMemoryStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Always }), { MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.Always },
new MatFileWritingToMemoryStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Never }), { MatFileWritingMethod.NormalStream, MatFileWriterOptionsForTests.Never },
new MatFileWritingToUnseekableStream(null), { MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.None },
new MatFileWritingToUnseekableStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Always }), { MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.Always },
new MatFileWritingToUnseekableStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Never }), { MatFileWritingMethod.UnseekableStream, MatFileWriterOptionsForTests.Never },
new MatFileWritingToUnalignedMemoryStream(null), { MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.None },
new MatFileWritingToUnalignedMemoryStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Always }), { MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.Always },
new MatFileWritingToUnalignedMemoryStream(new MatFileWriterOptions { UseCompression = CompressionUsage.Never }), { MatFileWritingMethod.UnalignedStream, MatFileWriterOptionsForTests.Never },
}; };
return data;
} }
} }
@ -401,10 +404,11 @@ namespace MatFileHandler.Tests
string factoryName, string factoryName,
string testName, string testName,
IMatFile actual, IMatFile actual,
MatFileWritingMethod method) MatFileWritingMethod method,
MatFileWriterOptionsForTests options)
{ {
var expected = GetMatTestData(factoryName)[testName]; var expected = GetMatTestData(factoryName)[testName];
var buffer = method.WriteMatFile(actual); var buffer = MatFileWritingMethods.WriteMatFile(method, options, actual);
using var stream = new MemoryStream(buffer); using var stream = new MemoryStream(buffer);
var reader = new MatFileReader(stream); var reader = new MatFileReader(stream);
var actualRead = reader.Read(); var actualRead = reader.Read();

View File

@ -2,16 +2,11 @@
namespace MatFileHandler.Tests namespace MatFileHandler.Tests
{ {
/// <summary> public enum MatFileWritingMethod
/// A method of writing IMatFile into a byte buffer.
/// </summary>
public abstract class MatFileWritingMethod
{ {
/// <summary> Undefined,
/// Write an IMatFile into a byte buffer. NormalStream,
/// </summary> UnseekableStream,
/// <param name="matFile"></param> UnalignedStream,
/// <returns></returns>
public abstract byte[] WriteMatFile(IMatFile matFile);
} }
} }

View File

@ -0,0 +1,58 @@
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(),
};
}
}

View File

@ -1,37 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// A method of writing an IMatFile into a MemoryStream.
/// </summary>
public class MatFileWritingToMemoryStream : MatFileWritingMethod
{
private readonly MatFileWriterOptions? _maybeOptions;
/// <summary>
/// Initializes a new instance of the <see cref="MatFileWritingToMemoryStream"/> class.
/// </summary>
/// <param name="maybeOptions">Options for the <see cref="MatFileWriter"/>.</param>
public MatFileWritingToMemoryStream(MatFileWriterOptions? maybeOptions)
{
_maybeOptions = maybeOptions;
}
/// <inheritdoc />
public override byte[] WriteMatFile(IMatFile matFile)
{
using var memoryStream = new MemoryStream();
var matFileWriter = _maybeOptions switch
{
{ } options => new MatFileWriter(memoryStream, options),
_ => new MatFileWriter(memoryStream),
};
matFileWriter.Write(matFile);
return memoryStream.ToArray();
}
}
}

View File

@ -1,43 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System;
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// A method of writing an IMatFile into a stream that is "unaligned".
/// </summary>
public class MatFileWritingToUnalignedMemoryStream : MatFileWritingMethod
{
private readonly MatFileWriterOptions? _maybeOptions;
/// <summary>
/// Initializes a new instance of the <see cref="MatFileWritingToUnalignedMemoryStream"/> class.
/// </summary>
/// <param name="maybeOptions">Options for the <see cref="MatFileWriter"/>.</param>
public MatFileWritingToUnalignedMemoryStream(MatFileWriterOptions? maybeOptions)
{
_maybeOptions = maybeOptions;
}
/// <inheritdoc />
public override byte[] WriteMatFile(IMatFile matFile)
{
using var memoryStream = new MemoryStream();
memoryStream.Seek(3, SeekOrigin.Begin);
var matFileWriter = _maybeOptions switch
{
{ } options => new MatFileWriter(memoryStream, options),
_ => new MatFileWriter(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;
}
}
}

View File

@ -1,38 +0,0 @@
// Copyright 2017-2018 Alexander Luzgarev
using System.IO;
namespace MatFileHandler.Tests
{
/// <summary>
/// A method of writing an IMatFile into a stream that is not seekable.
/// </summary>
public class MatFileWritingToUnseekableStream : MatFileWritingMethod
{
private readonly MatFileWriterOptions? _maybeOptions;
/// <summary>
/// Initializes a new instance of the <see cref="MatFileWritingToUnseekableStream"/> class.
/// </summary>
/// <param name="maybeOptions">Options for the <see cref="MatFileWriter"/>.</param>
public MatFileWritingToUnseekableStream(MatFileWriterOptions? maybeOptions)
{
_maybeOptions = maybeOptions;
}
/// <inheritdoc />
public override byte[] WriteMatFile(IMatFile matFile)
{
using var memoryStream = new MemoryStream();
using var unseekableStream = new UnseekableWriteStream(memoryStream);
var matFileWriter = _maybeOptions switch
{
{ } options => new MatFileWriter(unseekableStream, options),
_ => new MatFileWriter(unseekableStream),
};
matFileWriter.Write(matFile);
return memoryStream.ToArray();
}
}
}

View File

@ -9,7 +9,7 @@ namespace MatFileHandler.Tests
/// A stream which wraps another stream and only reads one byte at a time, /// A stream which wraps another stream and only reads one byte at a time,
/// while forbidding seeking in it. /// while forbidding seeking in it.
/// </summary> /// </summary>
internal class PartialUnseekableReadStream : Stream internal sealed class PartialUnseekableReadStream : Stream
{ {
private readonly Stream _baseStream; private readonly Stream _baseStream;

View File

@ -8,7 +8,7 @@ namespace MatFileHandler.Tests
/// <summary> /// <summary>
/// A stream which wraps another stream and forbids seeking in it. /// A stream which wraps another stream and forbids seeking in it.
/// </summary> /// </summary>
internal class UnseekableWriteStream : Stream internal sealed class UnseekableWriteStream : Stream
{ {
public UnseekableWriteStream(Stream baseStream) public UnseekableWriteStream(Stream baseStream)
{ {

View File

@ -8,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 struct ComplexOf<T> : IEquatable<ComplexOf<T>> public readonly struct ComplexOf<T> : IEquatable<ComplexOf<T>>
where T : struct where T : struct
{ {
/// <summary> /// <summary>
@ -71,10 +71,11 @@ 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 (ReferenceEquals(null, obj)) if (obj is null)
{ {
return false; return false;
} }
return obj is ComplexOf<T> other && Equals(other); return obj is ComplexOf<T> other && Equals(other);
} }

View File

@ -75,12 +75,17 @@ namespace MatFileHandler
{ {
throw new ArgumentException("Null data found.", nameof(data)); throw new ArgumentException("Null data found.", nameof(data));
} }
var elements =
var maybeElements =
ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical)); ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical));
if (elements == null) if (maybeElements is not { } elements)
{ {
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);
@ -117,15 +122,12 @@ namespace MatFileHandler
switch (flags.Class) switch (flags.Class)
{ {
case ArrayType.MxChar: case ArrayType.MxChar:
switch (realData) return realData switch
{ {
case MiNum<byte> dataByte: MiNum<byte> dataByte => ConvertToMatCharArray(flags, dimensions, name, dataByte),
return ConvertToMatCharArray(flags, dimensions, name, dataByte); MiNum<ushort> dataUshort => ConvertToMatCharArray(flags, dimensions, name, dataUshort),
case MiNum<ushort> dataUshort: _ => throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported."),
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,13 +186,12 @@ 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
{ {
case MiNum<double> _: MiNum<double> => DataExtraction.GetDataAsDouble(data) as T[],
return DataExtraction.GetDataAsDouble(data) as T[]; _ => throw new NotSupportedException(),
default: };
throw new NotSupportedException();
}
} }
private static MatCharArrayOf<ushort> ConvertToMatCharArray( private static MatCharArrayOf<ushort> ConvertToMatCharArray(

View File

@ -33,50 +33,23 @@ namespace MatFileHandler
public DataElement Read(BinaryReader reader) public DataElement Read(BinaryReader reader)
{ {
var (dataReader, tag) = ReadTag(reader); var (dataReader, tag) = ReadTag(reader);
DataElement result;
switch (tag.Type) var result = tag.Type switch
{ {
case DataType.MiInt8: DataType.MiInt8 => ReadNum<sbyte>(tag, dataReader),
result = ReadNum<sbyte>(tag, dataReader); DataType.MiUInt8 or DataType.MiUtf8 => ReadNum<byte>(tag, dataReader),
break; DataType.MiInt16 => ReadNum<short>(tag, dataReader),
case DataType.MiUInt8: DataType.MiUInt16 or DataType.MiUtf16 => ReadNum<ushort>(tag, dataReader),
case DataType.MiUtf8: DataType.MiInt32 => ReadNum<int>(tag, dataReader),
result = ReadNum<byte>(tag, dataReader); DataType.MiUInt32 => ReadNum<uint>(tag, dataReader),
break; DataType.MiSingle => ReadNum<float>(tag, dataReader),
case DataType.MiInt16: DataType.MiDouble => ReadNum<double>(tag, dataReader),
result = ReadNum<short>(tag, dataReader); DataType.MiInt64 => ReadNum<long>(tag, dataReader),
break; DataType.MiUInt64 => ReadNum<ulong>(tag, dataReader),
case DataType.MiUInt16: DataType.MiMatrix => ReadMatrix(tag, dataReader),
case DataType.MiUtf16: DataType.MiCompressed => ReadCompressed(tag, dataReader),
result = ReadNum<ushort>(tag, dataReader); _ => throw new NotSupportedException("Unknown element."),
break; };
case DataType.MiInt32:
result = ReadNum<int>(tag, dataReader);
break;
case DataType.MiUInt32:
result = ReadNum<uint>(tag, dataReader);
break;
case DataType.MiSingle:
result = ReadNum<float>(tag, dataReader);
break;
case DataType.MiDouble:
result = ReadNum<double>(tag, dataReader);
break;
case DataType.MiInt64:
result = ReadNum<long>(tag, dataReader);
break;
case DataType.MiUInt64:
result = ReadNum<ulong>(tag, dataReader);
break;
case DataType.MiMatrix:
result = ReadMatrix(tag, dataReader);
break;
case DataType.MiCompressed:
result = ReadCompressed(tag, dataReader);
break;
default:
throw new NotSupportedException("Unknown element.");
}
if (tag.Type != DataType.MiCompressed) if (tag.Type != DataType.MiCompressed)
{ {
@ -206,7 +179,7 @@ namespace MatFileHandler
else else
{ {
var length = typeHi; var length = typeHi;
type = type & 0xffff; 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));
} }
@ -298,19 +271,17 @@ namespace MatFileHandler
imaginaryData); imaginaryData);
} }
switch (data) return data switch
{ {
case MiNum<double> _: MiNum<double> => DataElementConverter.ConvertToMatSparseArrayOf<double>(
return DataElementConverter.ConvertToMatSparseArrayOf<double>(
sparseArrayFlags, sparseArrayFlags,
dimensions, dimensions,
name, name,
rowIndex.Data, rowIndex.Data,
columnIndex.Data, columnIndex.Data,
data); data),
default: _ => throw new NotSupportedException("Only double and logical sparse arrays are supported."),
throw new NotSupportedException("Only double and logical sparse arrays are supported."); };
}
} }
private MatStructureArray ContinueReadingStructure( private MatStructureArray ContinueReadingStructure(
@ -421,26 +392,23 @@ namespace MatFileHandler
switch (flags.Class) switch (flags.Class)
{ {
case ArrayType.MxChar: case ArrayType.MxChar:
switch (data) return data switch
{ {
case MiNum<byte> _: MiNum<byte> => DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
flags, flags,
dimensions, dimensions,
name, name,
data, data,
imaginaryData); imaginaryData),
case MiNum<ushort> _: MiNum<ushort> => DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
flags, flags,
dimensions, dimensions,
name, name,
data, data,
imaginaryData); imaginaryData),
default: _ => throw new NotSupportedException(
throw new NotSupportedException( $"This type of char array ({data.GetType()}) is not supported."),
$"This type of char array ({data.GetType()}) is not supported."); };
}
case ArrayType.MxInt8: case ArrayType.MxInt8:
return DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>( return DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
flags, flags,

View File

@ -16,31 +16,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToDouble(sbyteElement.Data),
return SbyteToDouble(sbyteElement.Data); MiNum<byte> byteElement => ByteToDouble(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToDouble(intElement.Data),
return ByteToDouble(byteElement.Data); MiNum<uint> uintElement => UintToDouble(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToDouble(shortElement.Data),
return IntToDouble(intElement.Data); MiNum<ushort> ushortElement => UshortToDouble(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToDouble(longElement.Data),
return UintToDouble(uintElement.Data); MiNum<ulong> ulongElement => UlongToDouble(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => FloatToDouble(floatElement.Data),
return ShortToDouble(shortElement.Data); MiNum<double> doubleElement => doubleElement.Data,
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToDouble(ushortElement.Data); $"Expected data element that would be convertible to double, found {element.GetType()}."),
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>
@ -50,31 +40,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToSingle(sbyteElement.Data),
return SbyteToSingle(sbyteElement.Data); MiNum<byte> byteElement => ByteToSingle(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToSingle(intElement.Data),
return ByteToSingle(byteElement.Data); MiNum<uint> uintElement => UintToSingle(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToSingle(shortElement.Data),
return IntToSingle(intElement.Data); MiNum<ushort> ushortElement => UshortToSingle(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToSingle(longElement.Data),
return UintToSingle(uintElement.Data); MiNum<ulong> ulongElement => UlongToSingle(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => floatElement.Data,
return ShortToSingle(shortElement.Data); MiNum<double> doubleElement => DoubleToSingle(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToSingle(ushortElement.Data); $"Expected data element that would be convertible to float, found {element.GetType()}."),
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>
@ -84,31 +64,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => sbyteElement.Data,
return sbyteElement.Data; MiNum<byte> byteElement => ByteToSByte(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToSByte(intElement.Data),
return ByteToSByte(byteElement.Data); MiNum<uint> uintElement => UintToSByte(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToSByte(shortElement.Data),
return IntToSByte(intElement.Data); MiNum<ushort> ushortElement => UshortToSByte(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToSByte(longElement.Data),
return UintToSByte(uintElement.Data); MiNum<ulong> ulongElement => UlongToSByte(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToSByte(floatElement.Data),
return ShortToSByte(shortElement.Data); MiNum<double> doubleElement => DoubleToSByte(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToSByte(ushortElement.Data); $"Expected data element that would be convertible to int8, found {element.GetType()}."),
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>
@ -118,31 +88,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToByte(sbyteElement.Data),
return SbyteToByte(sbyteElement.Data); MiNum<byte> byteElement => byteElement.Data,
case MiNum<byte> byteElement: MiNum<int> intElement => IntToByte(intElement.Data),
return byteElement.Data; MiNum<uint> uintElement => UintToByte(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToByte(shortElement.Data),
return IntToByte(intElement.Data); MiNum<ushort> ushortElement => UshortToByte(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToByte(longElement.Data),
return UintToByte(uintElement.Data); MiNum<ulong> ulongElement => UlongToByte(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToByte(floatElement.Data),
return ShortToByte(shortElement.Data); MiNum<double> doubleElement => DoubleToByte(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToByte(ushortElement.Data); $"Expected data element that would be convertible to uint8, found {element.GetType()}."),
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>
@ -152,31 +112,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToInt16(sbyteElement.Data),
return SbyteToInt16(sbyteElement.Data); MiNum<byte> byteElement => ByteToInt16(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToInt16(intElement.Data),
return ByteToInt16(byteElement.Data); MiNum<uint> uintElement => UintToInt16(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => shortElement.Data,
return IntToInt16(intElement.Data); MiNum<ushort> ushortElement => UshortToInt16(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToInt16(longElement.Data),
return UintToInt16(uintElement.Data); MiNum<ulong> ulongElement => UlongToInt16(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToInt16(floatElement.Data),
return shortElement.Data; MiNum<double> doubleElement => DoubleToInt16(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToInt16(ushortElement.Data); $"Expected data element that would be convertible to int16, found {element.GetType()}."),
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>
@ -186,31 +136,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToUInt16(sbyteElement.Data),
return SbyteToUInt16(sbyteElement.Data); MiNum<byte> byteElement => ByteToUInt16(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToUInt16(intElement.Data),
return ByteToUInt16(byteElement.Data); MiNum<uint> uintElement => UintToUInt16(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToUInt16(shortElement.Data),
return IntToUInt16(intElement.Data); MiNum<ushort> ushortElement => ushortElement.Data,
case MiNum<uint> uintElement: MiNum<long> longElement => LongToUInt16(longElement.Data),
return UintToUInt16(uintElement.Data); MiNum<ulong> ulongElement => UlongToUInt16(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToUInt16(floatElement.Data),
return ShortToUInt16(shortElement.Data); MiNum<double> doubleElement => DoubleToUInt16(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return ushortElement.Data; $"Expected data element that would be convertible to uint16, found {element.GetType()}."),
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>
@ -220,31 +160,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToInt32(sbyteElement.Data),
return SbyteToInt32(sbyteElement.Data); MiNum<byte> byteElement => ByteToInt32(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => intElement.Data,
return ByteToInt32(byteElement.Data); MiNum<uint> uintElement => UintToInt32(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToInt32(shortElement.Data),
return intElement.Data; MiNum<ushort> ushortElement => UshortToInt32(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToInt32(longElement.Data),
return UintToInt32(uintElement.Data); MiNum<ulong> ulongElement => UlongToInt32(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToInt32(floatElement.Data),
return ShortToInt32(shortElement.Data); MiNum<double> doubleElement => DoubleToInt32(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToInt32(ushortElement.Data); $"Expected data element that would be convertible to int32, found {element.GetType()}."),
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>
@ -254,31 +184,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToUInt32(sbyteElement.Data),
return SbyteToUInt32(sbyteElement.Data); MiNum<byte> byteElement => ByteToUInt32(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToUInt32(intElement.Data),
return ByteToUInt32(byteElement.Data); MiNum<uint> uintElement => uintElement.Data,
case MiNum<int> intElement: MiNum<short> shortElement => ShortToUInt32(shortElement.Data),
return IntToUInt32(intElement.Data); MiNum<ushort> ushortElement => UshortToUInt32(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToUInt32(longElement.Data),
return uintElement.Data; MiNum<ulong> ulongElement => UlongToUInt32(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToUInt32(floatElement.Data),
return ShortToUInt32(shortElement.Data); MiNum<double> doubleElement => DoubleToUInt32(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToUInt32(ushortElement.Data); $"Expected data element that would be convertible to uint32, found {element.GetType()}."),
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>
@ -288,31 +208,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToInt64(sbyteElement.Data),
return SbyteToInt64(sbyteElement.Data); MiNum<byte> byteElement => ByteToInt64(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToInt64(intElement.Data),
return ByteToInt64(byteElement.Data); MiNum<uint> uintElement => UintToInt64(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToInt64(shortElement.Data),
return IntToInt64(intElement.Data); MiNum<ushort> ushortElement => UshortToInt64(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => longElement.Data,
return UintToInt64(uintElement.Data); MiNum<ulong> ulongElement => UlongToInt64(ulongElement.Data),
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToInt64(floatElement.Data),
return ShortToInt64(shortElement.Data); MiNum<double> doubleElement => DoubleToInt64(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToInt64(ushortElement.Data); $"Expected data element that would be convertible to int64, found {element.GetType()}."),
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>
@ -322,31 +232,21 @@ 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)
{ {
switch (element) return element switch
{ {
case MiNum<sbyte> sbyteElement: MiNum<sbyte> sbyteElement => SbyteToUInt64(sbyteElement.Data),
return SbyteToUInt64(sbyteElement.Data); MiNum<byte> byteElement => ByteToUInt64(byteElement.Data),
case MiNum<byte> byteElement: MiNum<int> intElement => IntToUInt64(intElement.Data),
return ByteToUInt64(byteElement.Data); MiNum<uint> uintElement => UintToUInt64(uintElement.Data),
case MiNum<int> intElement: MiNum<short> shortElement => ShortToUInt64(shortElement.Data),
return IntToUInt64(intElement.Data); MiNum<ushort> ushortElement => UshortToUInt64(ushortElement.Data),
case MiNum<uint> uintElement: MiNum<long> longElement => LongToUInt64(longElement.Data),
return UintToUInt64(uintElement.Data); MiNum<ulong> ulongElement => ulongElement.Data,
case MiNum<short> shortElement: MiNum<float> floatElement => SingleToUInt64(floatElement.Data),
return ShortToUInt64(shortElement.Data); MiNum<double> doubleElement => DoubleToUInt64(doubleElement.Data),
case MiNum<ushort> ushortElement: _ => throw new HandlerException(
return UshortToUInt64(ushortElement.Data); $"Expected data element that would be convertible to uint64, found {element.GetType()}."),
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

View File

@ -16,41 +16,21 @@ 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)
{ {
switch (type) return type switch
{ {
case DataType.MiInt8: DataType.MiInt8 or DataType.MiUInt8 => 1,
return 1; DataType.MiInt16 or DataType.MiUInt16 => 2,
case DataType.MiUInt8: DataType.MiInt32 or DataType.MiUInt32 => 4,
return 1; DataType.MiSingle => 4,
case DataType.MiInt16: DataType.MiDouble => 8,
return 2; DataType.MiInt64 or DataType.MiUInt64 => 8,
case DataType.MiUInt16: DataType.MiMatrix => 0,
return 2; DataType.MiCompressed => 0,
case DataType.MiInt32: DataType.MiUtf8 => 1,
return 4; DataType.MiUtf16 => 2,
case DataType.MiUInt32: DataType.MiUtf32 => 4,
return 4; _ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
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);
}
} }
} }
} }

View File

@ -12,8 +12,6 @@ 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;
@ -36,15 +34,13 @@ 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.");
data2 = new double[data.Length]; Dimensions = dataArray.Dimensions;
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();
data2 = complexData.Select(c => c.Imaginary).ToArray(); Dimensions = dataComplex.Dimensions;
dimensions = dataComplex.Dimensions;
break; break;
default: default:
throw new HandlerException("Datetime data not found."); throw new HandlerException("Datetime data not found.");
@ -54,7 +50,7 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Gets datetime array dimensions. /// Gets datetime array dimensions.
/// </summary> /// </summary>
public int[] Dimensions => dimensions; public int[] Dimensions { get; }
/// <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"/>.
@ -66,11 +62,11 @@ namespace MatFileHandler
get get
{ {
var milliseconds = data[Dimensions.DimFlatten(list)]; var milliseconds = data[Dimensions.DimFlatten(list)];
if (milliseconds < -62_135_596_800_000.0 || milliseconds > 253_402_300_799_999.0) return milliseconds switch
{ {
return null; < -62_135_596_800_000.0 or > 253_402_300_799_999.0 => null,
} _ => epoch.AddMilliseconds(milliseconds),
return epoch.AddMilliseconds(milliseconds); };
} }
} }
} }

View File

@ -9,7 +9,6 @@ namespace MatFileHandler
/// </summary> /// </summary>
public class DurationAdapter public class DurationAdapter
{ {
private readonly int[] dimensions;
private readonly double[] data; private readonly double[] data;
/// <summary> /// <summary>
@ -27,13 +26,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 => dimensions; public int[] Dimensions { get; }
/// <summary> /// <summary>
/// Gets duration object at given position. /// Gets duration object at given position.

View File

@ -222,12 +222,7 @@ namespace MatFileHandler
private static int CalculatePadding(int length) private static int CalculatePadding(int length)
{ {
var rem = length % 8; var rem = length % 8;
if (rem == 0) return rem == 0 ? 0 : 8 - rem;
{
return 0;
}
return 8 - rem;
} }
private void WriteDataElement(int dataLength) private void WriteDataElement(int dataLength)
@ -293,7 +288,7 @@ namespace MatFileHandler
private void WriteFieldNames(IEnumerable<string> fieldNames) private void WriteFieldNames(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.Select(name => name.Length).Max() + 1; var maxFieldName = fieldNamesArray.Max(name => name.Length) + 1;
WriteDataElement(GetLengthOfByteArray<int>(1)); WriteDataElement(GetLengthOfByteArray<int>(1));
var buffer = new byte[fieldNamesArray.Length * maxFieldName]; var buffer = new byte[fieldNamesArray.Length * maxFieldName];
var startPosition = 0; var startPosition = 0;

View File

@ -4,7 +4,9 @@ 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,11 +74,9 @@ 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;
if (!isLittleEndian) return 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()

View File

@ -27,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>
public bool TryGetVariable(string name, out IVariable? variable); bool TryGetVariable(string name, out IVariable? variable);
} }
} }

View File

@ -18,11 +18,7 @@ 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 = new Dictionary<string, IVariable>(); _variables = variables.ToDictionary(v => v.Name, v => v);
foreach (var variable in variables)
{
_variables[variable.Name] = variable;
}
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -16,7 +16,8 @@
<OutputPath>bin\$(Configuration)\</OutputPath> <OutputPath>bin\$(Configuration)\</OutputPath>
<DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile> <DocumentationFile>$(OutputPath)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<LangVersion>10.0</LangVersion> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PublishRepositoryUrl>true</PublishRepositoryUrl> <PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>

View File

@ -1,6 +1,5 @@
// Copyright 2017-2018 Alexander Luzgarev // Copyright 2017-2018 Alexander Luzgarev
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -28,11 +27,9 @@ 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(new PositionTrackingStream(Stream));
{
return Read(reader); return Read(reader);
} }
}
/// <summary> /// <summary>
/// Read a sequence of raw variables from .mat file. /// Read a sequence of raw variables from .mat file.
@ -95,17 +92,15 @@ namespace MatFileHandler
var variables = new List<IVariable>(); var variables = new List<IVariable>();
foreach (var variable in rawVariables) foreach (var variable in rawVariables)
{ {
var array = variable.DataElement as MatArray; if (variable.DataElement is MatArray array)
if (array is null)
{ {
continue; variables.Add(
} new MatVariable(
variables.Add(new MatVariable(
array, array,
array.Name, array.Name,
array.Flags.Variable.HasFlag(Variable.IsGlobal))); array.Flags.Variable.HasFlag(Variable.IsGlobal)));
} }
}
return new MatFile(variables); return new MatFile(variables);
} }

View File

@ -47,8 +47,7 @@ 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); WriteHeader(writer, header);
foreach (var variable in file.Variables) foreach (var variable in file.Variables)
{ {
@ -73,7 +72,6 @@ namespace MatFileHandler
} }
} }
} }
}
private static uint CalculateAdler32Checksum(Stream stream) private static uint CalculateAdler32Checksum(Stream stream)
{ {
@ -193,6 +191,10 @@ 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();
@ -227,7 +229,7 @@ namespace MatFileHandler
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(new byte[] { 0, 0, 0, 0, 0, 0 }); writer.Write([0, 0, 0, 0, 0, 0]);
} }
private static void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags) private static void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags)
@ -236,7 +238,7 @@ namespace MatFileHandler
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(new byte[] { 0, 0 }); writer.Write([0, 0]);
writer.Write(flags.NzMax); writer.Write(flags.NzMax);
} }
@ -281,10 +283,7 @@ 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( WriteDataElement(writer, DataType.MiUInt8, ConvertToByteArray(boolArray.Data));
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));
@ -324,57 +323,33 @@ namespace MatFileHandler
private static ArrayFlags GetArrayFlags(IArray array, bool isGlobal) private static ArrayFlags GetArrayFlags(IArray array, bool isGlobal)
{ {
var variableFlags = isGlobal ? Variable.IsGlobal : 0; var variableFlags = isGlobal ? Variable.IsGlobal : 0;
switch (array) return array switch
{ {
case IArrayOf<sbyte> _: IArrayOf<sbyte> => new ArrayFlags(ArrayType.MxInt8, variableFlags),
return new ArrayFlags(ArrayType.MxInt8, variableFlags); IArrayOf<byte> => new ArrayFlags(ArrayType.MxUInt8, variableFlags),
case IArrayOf<byte> _: IArrayOf<short> => new ArrayFlags(ArrayType.MxInt16, variableFlags),
return new ArrayFlags(ArrayType.MxUInt8, variableFlags); IArrayOf<ushort> => new ArrayFlags(ArrayType.MxUInt16, variableFlags),
case IArrayOf<short> _: IArrayOf<int> => new ArrayFlags(ArrayType.MxInt32, variableFlags),
return new ArrayFlags(ArrayType.MxInt16, variableFlags); IArrayOf<uint> => new ArrayFlags(ArrayType.MxUInt32, variableFlags),
case IArrayOf<ushort> _: IArrayOf<long> => new ArrayFlags(ArrayType.MxInt64, variableFlags),
return new ArrayFlags(ArrayType.MxUInt16, variableFlags); IArrayOf<ulong> => new ArrayFlags(ArrayType.MxUInt64, variableFlags),
case IArrayOf<int> _: IArrayOf<float> => new ArrayFlags(ArrayType.MxSingle, variableFlags),
return new ArrayFlags(ArrayType.MxInt32, variableFlags); IArrayOf<double> => new ArrayFlags(ArrayType.MxDouble, variableFlags),
case IArrayOf<uint> _: IArrayOf<bool> => new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsLogical),
return new ArrayFlags(ArrayType.MxUInt32, variableFlags); IArrayOf<ComplexOf<sbyte>> => new ArrayFlags(ArrayType.MxInt8, variableFlags | Variable.IsComplex),
case IArrayOf<long> _: IArrayOf<ComplexOf<byte>> => new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsComplex),
return new ArrayFlags(ArrayType.MxInt64, variableFlags); IArrayOf<ComplexOf<short>> => new ArrayFlags(ArrayType.MxInt16, variableFlags | Variable.IsComplex),
case IArrayOf<ulong> _: IArrayOf<ComplexOf<ushort>> => new ArrayFlags(ArrayType.MxUInt16, variableFlags | Variable.IsComplex),
return new ArrayFlags(ArrayType.MxUInt64, variableFlags); IArrayOf<ComplexOf<int>> => new ArrayFlags(ArrayType.MxInt32, variableFlags | Variable.IsComplex),
case IArrayOf<float> _: IArrayOf<ComplexOf<uint>> => new ArrayFlags(ArrayType.MxUInt32, variableFlags | Variable.IsComplex),
return new ArrayFlags(ArrayType.MxSingle, variableFlags); IArrayOf<ComplexOf<long>> => new ArrayFlags(ArrayType.MxInt64, variableFlags | Variable.IsComplex),
case IArrayOf<double> _: IArrayOf<ComplexOf<ulong>> => new ArrayFlags(ArrayType.MxUInt64, variableFlags | Variable.IsComplex),
return new ArrayFlags(ArrayType.MxDouble, variableFlags); IArrayOf<ComplexOf<float>> => new ArrayFlags(ArrayType.MxSingle, variableFlags | Variable.IsComplex),
case IArrayOf<bool> _: IArrayOf<Complex> => new ArrayFlags(ArrayType.MxDouble, variableFlags | Variable.IsComplex),
return new ArrayFlags(ArrayType.MxUInt8, variableFlags | Variable.IsLogical); IStructureArray => new ArrayFlags(ArrayType.MxStruct, variableFlags),
case IArrayOf<ComplexOf<sbyte>> _: ICellArray => new ArrayFlags(ArrayType.MxCell, variableFlags),
return new ArrayFlags(ArrayType.MxInt8, variableFlags | Variable.IsComplex); _ => throw new NotSupportedException(),
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 static SparseArrayFlags GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero)
@ -466,9 +441,8 @@ namespace MatFileHandler
{ {
WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(data)); WriteDataElement(writer, DataType.MiDouble, ConvertToByteArray(data));
} }
else if (data is Complex[]) else if (data is Complex[] complexData)
{ {
var complexData = data as Complex[];
WriteDataElement( WriteDataElement(
writer, writer,
DataType.MiDouble, DataType.MiDouble,
@ -478,13 +452,12 @@ 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[]) else if (data is bool[] boolData)
{ {
var boolData = data as bool[];
WriteDataElement( WriteDataElement(
writer, writer,
DataType.MiUInt8, DataType.MiUInt8,
boolData.Select(element => element ? (byte)1 : (byte)0).ToArray()); ConvertToByteArray(boolData));
} }
} }
@ -538,8 +511,8 @@ namespace MatFileHandler
private static void WriteFieldNames(BinaryWriter writer, IEnumerable<string> fieldNames) private static 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.Select(name => name.Length).Max() + 1; var maxFieldName = fieldNamesArray.Max(name => name.Length) + 1;
WriteDataElement(writer, DataType.MiInt32, ConvertToByteArray(new[] { maxFieldName })); WriteDataElement(writer, DataType.MiInt32, ConvertToByteArray([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)
@ -672,24 +645,21 @@ namespace MatFileHandler
private void WriteCompressedVariableToUnseekableStream(BinaryWriter writer, IVariable variable) private void WriteCompressedVariableToUnseekableStream(BinaryWriter writer, IVariable variable)
{ {
using (var compressedStream = new MemoryStream()) using var compressedStream = new MemoryStream();
{
uint crc; uint crc;
using (var originalStream = new MemoryStream()) using (var originalStream = new MemoryStream())
{ {
using (var internalWriter = new BinaryWriter(originalStream)) using var internalWriter = new BinaryWriter(originalStream);
{
WriteVariable(internalWriter, variable); WriteVariable(internalWriter, variable);
originalStream.Position = 0; originalStream.Position = 0;
crc = CalculateAdler32Checksum(originalStream); crc = CalculateAdler32Checksum(originalStream);
originalStream.Position = 0; originalStream.Position = 0;
using (var compressionStream = using var compressionStream = new DeflateStream(
new DeflateStream(compressedStream, CompressionMode.Compress, leaveOpen: true)) compressedStream,
{ CompressionMode.Compress,
leaveOpen: true);
originalStream.CopyTo(compressionStream); originalStream.CopyTo(compressionStream);
} }
}
}
compressedStream.Position = 0; compressedStream.Position = 0;
WriteTag(writer, new Tag(DataType.MiCompressed, (int)(compressedStream.Length + 6))); WriteTag(writer, new Tag(DataType.MiCompressed, (int)(compressedStream.Length + 6)));
writer.Write((byte)0x78); writer.Write((byte)0x78);
@ -698,5 +668,4 @@ namespace MatFileHandler
writer.Write(BitConverter.GetBytes(crc).Reverse().ToArray()); writer.Write(BitConverter.GetBytes(crc).Reverse().ToArray());
} }
} }
}
} }

View File

@ -10,7 +10,7 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Gets default options. /// Gets default options.
/// </summary> /// </summary>
public static MatFileWriterOptions Default => new MatFileWriterOptions public static MatFileWriterOptions Default => new()
{ {
UseCompression = CompressionUsage.Always, UseCompression = CompressionUsage.Always,
}; };

View File

@ -93,15 +93,12 @@ namespace MatFileHandler
private (int row, int column) GetRowAndColumn(int[] indices) private (int row, int column) GetRowAndColumn(int[] indices)
{ {
switch (indices.Length) return indices.Length switch
{ {
case 1: 1 => (indices[0] % Dimensions[0], indices[0] / Dimensions[0]),
return (indices[0] % Dimensions[0], indices[0] / Dimensions[0]); 2 => (indices[0], indices[1]),
case 2: _ => throw new NotSupportedException("Invalid index for sparse array."),
return (indices[0], indices[1]); };
default:
throw new NotSupportedException("Invalid index for sparse array.");
}
} }
} }
} }

View File

@ -78,15 +78,7 @@ namespace MatFileHandler
/// <inheritdoc /> /// <inheritdoc />
public IArray this[string field, params int[] list] public IArray this[string field, params int[] list]
{ {
get get => TryGetValue(field, out var result, list) ? result! : throw new ArgumentOutOfRangeException(nameof(list));
{
if (TryGetValue(field, out var result, list))
{
return result!;
}
throw new ArgumentOutOfRangeException(nameof(list));
}
set => throw new NotImplementedException(); set => throw new NotImplementedException();
} }
@ -106,7 +98,7 @@ namespace MatFileHandler
{ {
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 int fieldIndex)) if (maybeFieldIndex is not int fieldIndex)
{ {
output = default; output = default;
return false; return false;
@ -171,8 +163,8 @@ namespace MatFileHandler
} }
} }
/// <inheritdoc />
#pragma warning disable CS8767 #pragma warning disable CS8767
/// <inheritdoc />
public bool TryGetValue(string key, out IArray? value) public bool TryGetValue(string key, out IArray? value)
#pragma warning restore CS8767 #pragma warning restore CS8767
{ {

View File

@ -48,7 +48,7 @@ internal sealed class PositionTrackingStream : Stream
/// <inheritdoc/> /// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
int bytesRead = _baseStream.Read(buffer, offset, count); var bytesRead = _baseStream.Read(buffer, offset, count);
_position += bytesRead; _position += bytesRead;

View File

@ -10,7 +10,6 @@ namespace MatFileHandler
/// </summary> /// </summary>
public class StringAdapter public class StringAdapter
{ {
private readonly int[] dimensions;
private readonly string[] strings; private readonly string[] strings;
/// <summary> /// <summary>
@ -28,13 +27,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 => dimensions; public int[] Dimensions { get; }
/// <summary> /// <summary>
/// Gets string object at given position. /// Gets string object at given position.

View File

@ -49,7 +49,7 @@ namespace MatFileHandler
/// <inheritdoc/> /// <inheritdoc/>
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)
{ {
int bytesRead = _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - _bytesRead)); var bytesRead = _baseStream.Read(buffer, offset, (int)Math.Min(count, Length - _bytesRead));
_bytesRead += bytesRead; _bytesRead += bytesRead;

View File

@ -119,12 +119,7 @@ namespace MatFileHandler
/// <returns>Field index.</returns> /// <returns>Field index.</returns>
public int? FindField(string fieldName) public int? FindField(string fieldName)
{ {
if (fieldToIndex.TryGetValue(fieldName, out var index)) return fieldToIndex.TryGetValue(fieldName, out var index) ? index : null;
{
return index;
}
return null;
} }
} }

View File

@ -2,7 +2,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -357,7 +356,7 @@ namespace MatFileHandler
return array; return array;
} }
private struct ObjectClassInformation private readonly struct ObjectClassInformation
{ {
public ObjectClassInformation(int embeddedObjectPosition, int objectPosition, int loadingOrder, int classId) public ObjectClassInformation(int embeddedObjectPosition, int objectPosition, int loadingOrder, int classId)
{ {

View File

@ -87,7 +87,7 @@ 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 int index)) if (maybeIndex is not int index)
{ {
throw new ArgumentOutOfRangeException(nameof(variableName), $"Variable '{variableName}' not found."); throw new ArgumentOutOfRangeException(nameof(variableName), $"Variable '{variableName}' not found.");
} }