Get rid of unnecessary ArrayFlags

This commit is contained in:
Alexander Luzgarev 2019-03-17 18:50:57 +01:00
parent ef73a380bb
commit 433dca8c69
18 changed files with 302 additions and 307 deletions

View File

@ -138,20 +138,4 @@ namespace MatFileHandler
Variable = variable; Variable = variable;
} }
} }
/// <summary>
/// Sparse array properties.
/// </summary>
internal struct SparseArrayFlags
{
/// <summary>
/// Usual array properties.
/// </summary>
public ArrayFlags ArrayFlags;
/// <summary>
/// Maximal number of non-zero elements.
/// </summary>
public uint NzMax;
}
} }

View File

@ -28,9 +28,7 @@ namespace MatFileHandler
where T : struct where T : struct
{ {
return new MatNumericalArrayOf<T>( return new MatNumericalArrayOf<T>(
GetStandardFlags<T>(),
dimensions, dimensions,
string.Empty,
new T[dimensions.NumberOfElements()]); new T[dimensions.NumberOfElements()]);
} }
@ -54,7 +52,7 @@ namespace MatFileHandler
{ {
throw new ArgumentException("Data size does not match the specified dimensions", "data"); throw new ArgumentException("Data size does not match the specified dimensions", "data");
} }
return new MatNumericalArrayOf<T>(GetStandardFlags<T>(), dimensions, string.Empty, data); return new MatNumericalArrayOf<T>(dimensions, data);
} }
/// <summary> /// <summary>
@ -84,7 +82,7 @@ namespace MatFileHandler
{ {
dictionary[field] = elements.ToList(); dictionary[field] = elements.ToList();
} }
return new MatStructureArray(flags, dimensions, string.Empty, dictionary); return new MatStructureArray(dimensions, dictionary);
} }
/// <summary> /// <summary>
@ -107,7 +105,7 @@ namespace MatFileHandler
{ {
var flags = ConstructArrayFlags(ArrayType.MxChar); var flags = ConstructArrayFlags(ArrayType.MxChar);
var ushortArray = contents.ToCharArray().Select(c => (ushort)c).ToArray(); var ushortArray = contents.ToCharArray().Select(c => (ushort)c).ToArray();
return new MatCharArrayOf<ushort>(flags, dimensions, string.Empty, ushortArray, contents); return new MatCharArrayOf<ushort>(dimensions, ushortArray, contents);
} }
/// <summary> /// <summary>
@ -129,9 +127,7 @@ namespace MatFileHandler
where T : struct where T : struct
{ {
return new MatSparseArrayOf<T>( return new MatSparseArrayOf<T>(
GetStandardSparseArrayFlags<T>(),
dimensions, dimensions,
string.Empty,
new Dictionary<(int, int), T>()); new Dictionary<(int, int), T>());
} }
@ -255,15 +251,5 @@ namespace MatFileHandler
} }
return ConstructArrayFlags(ArrayType.MxObject); return ConstructArrayFlags(ArrayType.MxObject);
} }
private SparseArrayFlags GetStandardSparseArrayFlags<T>()
{
var arrayFlags = GetStandardFlags<T>();
return new SparseArrayFlags
{
ArrayFlags = arrayFlags,
NzMax = 0,
};
}
} }
} }

View File

@ -16,18 +16,14 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Construct a complex sparse array. /// Construct a complex sparse array.
/// </summary> /// </summary>
/// <param name="flags">Array flags.</param>
/// <param name="dimensions">Array dimensions.</param> /// <param name="dimensions">Array dimensions.</param>
/// <param name="name">Array name.</param>
/// <param name="rowIndex">Row indices.</param> /// <param name="rowIndex">Row indices.</param>
/// <param name="columnIndex">Denotes index ranges for each column.</param> /// <param name="columnIndex">Denotes index ranges for each column.</param>
/// <param name="data">Real parts of the values.</param> /// <param name="data">Real parts of the values.</param>
/// <param name="imaginaryData">Imaginary parts of the values.</param> /// <param name="imaginaryData">Imaginary parts of the values.</param>
/// <returns>A constructed array.</returns> /// <returns>A constructed array.</returns>
public static MatArray ConvertToMatSparseArrayOfComplex( public static MatArray ConvertToMatSparseArrayOfComplex(
SparseArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
int[] rowIndex, int[] rowIndex,
int[] columnIndex, int[] columnIndex,
DataElement data, DataElement data,
@ -44,7 +40,7 @@ namespace MatFileHandler
rowIndex, rowIndex,
columnIndex, columnIndex,
j => new Complex(realParts[j], imaginaryParts[j])); j => new Complex(realParts[j], imaginaryParts[j]));
return new MatSparseArrayOf<Complex>(flags, dimensions, name, dataDictionary); return new MatSparseArrayOf<Complex>(dimensions, dataDictionary);
} }
/// <summary> /// <summary>
@ -53,15 +49,13 @@ namespace MatFileHandler
/// <typeparam name="T">Element type (Double or Boolean).</typeparam> /// <typeparam name="T">Element type (Double or Boolean).</typeparam>
/// <param name="flags">Array flags.</param> /// <param name="flags">Array flags.</param>
/// <param name="dimensions">Array dimensions.</param> /// <param name="dimensions">Array dimensions.</param>
/// <param name="name">Array name.</param>
/// <param name="rowIndex">Row indices.</param> /// <param name="rowIndex">Row indices.</param>
/// <param name="columnIndex">Denotes index ranges for each column.</param> /// <param name="columnIndex">Denotes index ranges for each column.</param>
/// <param name="data">The values.</param> /// <param name="data">The values.</param>
/// <returns>A constructed array.</returns> /// <returns>A constructed array.</returns>
public static MatArray ConvertToMatSparseArrayOf<T>( public static MatArray ConvertToMatSparseArrayOf<T>(
SparseArrayFlags flags, ArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
int[] rowIndex, int[] rowIndex,
int[] columnIndex, int[] columnIndex,
DataElement data) DataElement data)
@ -76,14 +70,14 @@ namespace MatFileHandler
throw new ArgumentException("Null data found.", "data"); throw new ArgumentException("Null data found.", "data");
} }
var elements = var elements =
ConvertDataToSparseProperType<T>(data, flags.ArrayFlags.Variable.HasFlag(Variable.IsLogical)); ConvertDataToSparseProperType<T>(data, flags.Variable.HasFlag(Variable.IsLogical));
if (elements == null) if (elements == null)
{ {
throw new HandlerException("Couldn't read sparse array."); throw new HandlerException("Couldn't read sparse array.");
} }
var dataDictionary = var dataDictionary =
DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]); DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
return new MatSparseArrayOf<T>(flags, dimensions, name, dataDictionary); return new MatSparseArrayOf<T>(dimensions, dataDictionary);
} }
/// <summary> /// <summary>
@ -92,7 +86,6 @@ namespace MatFileHandler
/// <typeparam name="T">Element type.</typeparam> /// <typeparam name="T">Element type.</typeparam>
/// <param name="flags">Array flags.</param> /// <param name="flags">Array flags.</param>
/// <param name="dimensions">Array dimensions.</param> /// <param name="dimensions">Array dimensions.</param>
/// <param name="name">Array name.</param>
/// <param name="realData">Real parts of the values.</param> /// <param name="realData">Real parts of the values.</param>
/// <param name="imaginaryData">Imaginary parts of the values.</param> /// <param name="imaginaryData">Imaginary parts of the values.</param>
/// <returns>A constructed array.</returns> /// <returns>A constructed array.</returns>
@ -104,7 +97,6 @@ namespace MatFileHandler
public static MatArray ConvertToMatNumericalArrayOf<T>( public static MatArray ConvertToMatNumericalArrayOf<T>(
ArrayFlags flags, ArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
DataElement realData, DataElement realData,
DataElement imaginaryData) DataElement imaginaryData)
where T : struct where T : struct
@ -112,7 +104,7 @@ namespace MatFileHandler
if (flags.Variable.HasFlag(Variable.IsLogical)) if (flags.Variable.HasFlag(Variable.IsLogical))
{ {
var data = DataExtraction.GetDataAsUInt8(realData).ToArrayLazily().Select(x => x != 0).ToArray(); var data = DataExtraction.GetDataAsUInt8(realData).ToArrayLazily().Select(x => x != 0).ToArray();
return new MatNumericalArrayOf<bool>(flags, dimensions, name, data); return new MatNumericalArrayOf<bool>(dimensions, data);
} }
switch (flags.Class) switch (flags.Class)
{ {
@ -120,9 +112,9 @@ namespace MatFileHandler
switch (realData) switch (realData)
{ {
case MiNum<byte> dataByte: case MiNum<byte> dataByte:
return ConvertToMatCharArray(flags, dimensions, name, dataByte); return ConvertToMatCharArray(dimensions, dataByte);
case MiNum<ushort> dataUshort: case MiNum<ushort> dataUshort:
return ConvertToMatCharArray(flags, dimensions, name, dataUshort); return ConvertToMatCharArray(dimensions, dataUshort);
default: default:
throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported."); throw new NotSupportedException("Only utf8, utf16 or ushort char arrays are supported.");
} }
@ -146,25 +138,23 @@ namespace MatFileHandler
(dataArray as double[]) (dataArray as double[])
.Zip(dataArray2 as double[], (x, y) => new Complex(x, y)) .Zip(dataArray2 as double[], (x, y) => new Complex(x, y))
.ToArray(); .ToArray();
return new MatNumericalArrayOf<Complex>(flags, dimensions, name, complexArray); return new MatNumericalArrayOf<Complex>(dimensions, complexArray);
} }
var complexDataArray = dataArray.Zip(dataArray2, (x, y) => new ComplexOf<T>(x, y)).ToArray(); var complexDataArray = dataArray.Zip(dataArray2, (x, y) => new ComplexOf<T>(x, y)).ToArray();
return new MatNumericalArrayOf<ComplexOf<T>>(flags, dimensions, name, complexDataArray); return new MatNumericalArrayOf<ComplexOf<T>>(dimensions, complexDataArray);
} }
return new MatNumericalArrayOf<T>(flags, dimensions, name, dataArray); return new MatNumericalArrayOf<T>(dimensions, dataArray);
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
} }
private static MatCharArrayOf<byte> ConvertToMatCharArray( private static MatCharArrayOf<byte> ConvertToMatCharArray(
ArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
MiNum<byte> dataElement) MiNum<byte> dataElement)
{ {
var data = dataElement?.Data; var data = dataElement?.Data;
return new MatCharArrayOf<byte>(flags, dimensions, name, data, Encoding.UTF8.GetString(data)); return new MatCharArrayOf<byte>(dimensions, data, Encoding.UTF8.GetString(data));
} }
private static T[] ConvertDataToProperType<T>(DataElement data, ArrayType arrayType) private static T[] ConvertDataToProperType<T>(DataElement data, ArrayType arrayType)
@ -212,16 +202,12 @@ namespace MatFileHandler
} }
private static MatCharArrayOf<ushort> ConvertToMatCharArray( private static MatCharArrayOf<ushort> ConvertToMatCharArray(
ArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
MiNum<ushort> dataElement) MiNum<ushort> dataElement)
{ {
var data = dataElement?.Data; var data = dataElement?.Data;
return new MatCharArrayOf<ushort>( return new MatCharArrayOf<ushort>(
flags,
dimensions, dimensions,
name,
data, data,
new string(data.Select(x => (char)x).ToArray())); new string(data.Select(x => (char)x).ToArray()));
} }

View File

@ -25,59 +25,60 @@ namespace MatFileHandler
this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData)); this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
} }
private DataElement ReadElementWithoutFlags(Tag tag, BinaryReader reader)
{
switch (tag.Type)
{
case DataType.MiInt8:
return ReadNum<sbyte>(tag, reader);
case DataType.MiUInt8:
case DataType.MiUtf8:
return ReadNum<byte>(tag, reader);
case DataType.MiInt16:
return ReadNum<short>(tag, reader);
case DataType.MiUInt16:
case DataType.MiUtf16:
return ReadNum<ushort>(tag, reader);
case DataType.MiInt32:
return ReadNum<int>(tag, reader);
case DataType.MiUInt32:
return ReadNum<uint>(tag, reader);
case DataType.MiSingle:
return ReadNum<float>(tag, reader);
case DataType.MiDouble:
return ReadNum<double>(tag, reader);
case DataType.MiInt64:
return ReadNum<long>(tag, reader);
case DataType.MiUInt64:
return ReadNum<ulong>(tag, reader);
default:
throw new NotSupportedException("Unknown element.");
}
}
private DataElementWithArrayFlags ReadElementWithFlags(Tag tag, BinaryReader reader)
{
switch (tag.Type)
{
case DataType.MiMatrix:
return ReadMatrix(tag, reader);
case DataType.MiCompressed:
return ReadCompressed(tag, reader);
default:
var element = ReadElementWithoutFlags(tag, reader);
return new DataElementWithArrayFlags(element);
}
}
/// <summary> /// <summary>
/// Read a data element. /// Read a data element.
/// </summary> /// </summary>
/// <param name="reader">Input reader.</param> /// <param name="reader">Input reader.</param>
/// <returns>Data element.</returns> /// <returns>Data element.</returns>
public DataElement Read(BinaryReader reader) public DataElementWithArrayFlags Read(BinaryReader reader)
{ {
var (dataReader, tag) = ReadTag(reader); var (dataReader, tag) = ReadTag(reader);
DataElement result; DataElementWithArrayFlags result = ReadElementWithFlags(tag, dataReader);
switch (tag.Type)
{
case DataType.MiInt8:
result = ReadNum<sbyte>(tag, dataReader);
break;
case DataType.MiUInt8:
case DataType.MiUtf8:
result = ReadNum<byte>(tag, dataReader);
break;
case DataType.MiInt16:
result = ReadNum<short>(tag, dataReader);
break;
case DataType.MiUInt16:
case DataType.MiUtf16:
result = ReadNum<ushort>(tag, dataReader);
break;
case DataType.MiInt32:
result = ReadNum<int>(tag, dataReader);
break;
case DataType.MiUInt32:
result = ReadNum<uint>(tag, dataReader);
break;
case DataType.MiSingle:
result = ReadNum<float>(tag, dataReader);
break;
case DataType.MiDouble:
result = ReadNum<double>(tag, dataReader);
break;
case DataType.MiInt64:
result = ReadNum<long>(tag, dataReader);
break;
case DataType.MiUInt64:
result = ReadNum<ulong>(tag, dataReader);
break;
case DataType.MiMatrix:
result = ReadMatrix(tag, dataReader);
break;
case DataType.MiCompressed:
result = ReadCompressed(tag, dataReader);
break;
default:
throw new NotSupportedException("Unknown element.");
}
if (tag.Type != DataType.MiCompressed) if (tag.Type != DataType.MiCompressed)
{ {
var position = reader.BaseStream.Position; var position = reader.BaseStream.Position;
@ -181,17 +182,13 @@ namespace MatFileHandler
return new MiNum<T>(result); return new MiNum<T>(result);
} }
private static SparseArrayFlags ReadSparseArrayFlags(DataElement element) private static (ArrayFlags flags, uint nzMax) ReadSparseArrayFlags(DataElement element)
{ {
var arrayFlags = ReadArrayFlags(element); var arrayFlags = ReadArrayFlags(element);
var flagData = (element as MiNum<uint>)?.Data ?? var flagData = (element as MiNum<uint>)?.Data ??
throw new HandlerException("Unexpected type in sparse array flags."); throw new HandlerException("Unexpected type in sparse array flags.");
var nzMax = flagData[1]; var nzMax = flagData[1];
return new SparseArrayFlags return (arrayFlags, nzMax);
{
ArrayFlags = arrayFlags,
NzMax = nzMax,
};
} }
private static (BinaryReader, Tag) ReadTag(BinaryReader reader) private static (BinaryReader, Tag) ReadTag(BinaryReader reader)
@ -222,91 +219,108 @@ namespace MatFileHandler
var elements = new List<IArray>(); var elements = new List<IArray>();
for (var i = 0; i < numberOfElements; i++) for (var i = 0; i < numberOfElements; i++)
{ {
var element = Read(reader) as IArray; var element = Read(reader).Element as IArray;
elements.Add(element); elements.Add(element);
} }
return new MatCellArray(flags, dimensions, name, elements); return new MatCellArray(flags, dimensions, name, elements);
} }
private DataElement ContinueReadingOpaque(BinaryReader reader) private DataElementWithArrayFlags ContinueReadingOpaque(BinaryReader reader)
{ {
var nameElement = Read(reader) as MiNum<sbyte> ?? var nameElement = Read(reader).Element as MiNum<sbyte> ??
throw new HandlerException("Unexpected type in object name."); throw new HandlerException("Unexpected type in object name.");
var name = ReadName(nameElement); var name = ReadName(nameElement);
var anotherElement = Read(reader) as MiNum<sbyte> ?? var anotherElement = Read(reader).Element as MiNum<sbyte> ??
throw new HandlerException("Unexpected type in object type description."); throw new HandlerException("Unexpected type in object type description.");
var typeDescription = ReadName(anotherElement); var typeDescription = ReadName(anotherElement);
var classNameElement = Read(reader) as MiNum<sbyte> ?? var classNameElement = Read(reader).Element as MiNum<sbyte> ??
throw new HandlerException("Unexpected type in class name."); throw new HandlerException("Unexpected type in class name.");
var className = ReadName(classNameElement); var className = ReadName(classNameElement);
var dataElement = Read(reader); var dataElement = Read(reader).Element;
var data = ReadData(dataElement); var data = ReadData(dataElement);
if (data is MatNumericalArrayOf<uint> linkElement) if (data is MatNumericalArrayOf<uint> linkElement)
{ {
var (dimensions, indexToObjectId, classIndex) = ParseOpaqueData(linkElement.Data); var (dimensions, indexToObjectId, classIndex) = ParseOpaqueData(linkElement.Data);
return new OpaqueLink( return new DataElementWithArrayFlags(
name, new OpaqueLink(
typeDescription, typeDescription,
className, className,
dimensions, dimensions,
data, data,
indexToObjectId, indexToObjectId,
classIndex, classIndex,
subsystemData); subsystemData),
default,
name);
} }
else else
{ {
return new Opaque(name, typeDescription, className, new int[] { }, data); return new DataElementWithArrayFlags(
new Opaque(
typeDescription,
className,
new int[] { },
data),
default,
name);
} }
} }
private DataElement ContinueReadingSparseArray( private DataElementWithArrayFlags ContinueReadingSparseArray(
BinaryReader reader, BinaryReader reader,
DataElement firstElement, DataElement firstElement,
int[] dimensions, int[] dimensions,
string name) string name)
{ {
var sparseArrayFlags = ReadSparseArrayFlags(firstElement); var (arrayFlags, nzMax) = ReadSparseArrayFlags(firstElement);
var rowIndex = Read(reader) as MiNum<int> ?? var rowIndex = Read(reader).Element as MiNum<int> ??
throw new HandlerException("Unexpected type in row indices of a sparse array."); throw new HandlerException("Unexpected type in row indices of a sparse array.");
var columnIndex = Read(reader) as MiNum<int> ?? var columnIndex = Read(reader).Element as MiNum<int> ??
throw new HandlerException("Unexpected type in column indices of a sparse array."); throw new HandlerException("Unexpected type in column indices of a sparse array.");
var data = Read(reader); var data = Read(reader).Element;
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsLogical)) if (arrayFlags.Variable.HasFlag(Variable.IsLogical))
{ {
return DataElementConverter.ConvertToMatSparseArrayOf<bool>( return new DataElementWithArrayFlags(
sparseArrayFlags, DataElementConverter.ConvertToMatSparseArrayOf<bool>(
arrayFlags,
dimensions, dimensions,
name,
rowIndex.Data, rowIndex.Data,
columnIndex.Data, columnIndex.Data,
data); data),
arrayFlags,
name,
nzMax);
} }
if (sparseArrayFlags.ArrayFlags.Variable.HasFlag(Variable.IsComplex)) if (arrayFlags.Variable.HasFlag(Variable.IsComplex))
{ {
var imaginaryData = Read(reader); var imaginaryData = Read(reader).Element;
return DataElementConverter.ConvertToMatSparseArrayOfComplex( return new DataElementWithArrayFlags(
sparseArrayFlags, DataElementConverter.ConvertToMatSparseArrayOfComplex(
dimensions, dimensions,
name,
rowIndex.Data, rowIndex.Data,
columnIndex.Data, columnIndex.Data,
data, data,
imaginaryData); imaginaryData),
arrayFlags,
name,
nzMax);
} }
switch (data) switch (data)
{ {
case MiNum<double> _: case MiNum<double> _:
return DataElementConverter.ConvertToMatSparseArrayOf<double>( return new DataElementWithArrayFlags(
sparseArrayFlags, DataElementConverter.ConvertToMatSparseArrayOf<double>(
arrayFlags,
dimensions, dimensions,
name,
rowIndex.Data, rowIndex.Data,
columnIndex.Data, columnIndex.Data,
data); data),
arrayFlags,
name,
nzMax);
default: default:
throw new NotSupportedException("Only double and logical sparse arrays are supported."); throw new NotSupportedException("Only double and logical sparse arrays are supported.");
} }
@ -314,12 +328,10 @@ namespace MatFileHandler
private DataElement ContinueReadingStructure( private DataElement ContinueReadingStructure(
BinaryReader reader, BinaryReader reader,
ArrayFlags flags,
int[] dimensions, int[] dimensions,
string name,
int fieldNameLength) int fieldNameLength)
{ {
var element = Read(reader); var element = Read(reader).Element;
var fieldNames = ReadFieldNames(element as MiNum<sbyte>, fieldNameLength); var fieldNames = ReadFieldNames(element as MiNum<sbyte>, fieldNameLength);
var fields = new Dictionary<string, List<IArray>>(); var fields = new Dictionary<string, List<IArray>>();
foreach (var fieldName in fieldNames) foreach (var fieldName in fieldNames)
@ -332,15 +344,15 @@ namespace MatFileHandler
{ {
foreach (var fieldName in fieldNames) foreach (var fieldName in fieldNames)
{ {
var field = Read(reader) as IArray; var field = Read(reader).Element as IArray;
fields[fieldName].Add(field); fields[fieldName].Add(field);
} }
} }
return new MatStructureArray(flags, dimensions, name, fields); return new MatStructureArray(dimensions, fields);
} }
private DataElement Read(Stream stream) private DataElementWithArrayFlags Read(Stream stream)
{ {
using (var reader = new BinaryReader(stream)) using (var reader = new BinaryReader(stream))
{ {
@ -348,7 +360,7 @@ namespace MatFileHandler
} }
} }
private DataElement ReadCompressed(Tag tag, BinaryReader reader) private DataElementWithArrayFlags ReadCompressed(Tag tag, BinaryReader reader)
{ {
reader.ReadBytes(2); reader.ReadBytes(2);
var compressedData = new byte[tag.Length - 6]; var compressedData = new byte[tag.Length - 6];
@ -367,28 +379,31 @@ namespace MatFileHandler
return Read(resultStream); return Read(resultStream);
} }
private DataElement ReadMatrix(Tag tag, BinaryReader reader) private DataElementWithArrayFlags ReadMatrix(Tag tag, BinaryReader reader)
{ {
if (tag.Length == 0) if (tag.Length == 0)
{ {
return MatArray.Empty(); return new DataElementWithArrayFlags(MatArray.Empty());
} }
var element1 = Read(reader); var element1 = Read(reader).Element;
var flags = ReadArrayFlags(element1); var flags = ReadArrayFlags(element1);
if (flags.Class == ArrayType.MxOpaque) if (flags.Class == ArrayType.MxOpaque)
{ {
return ContinueReadingOpaque(reader); return ContinueReadingOpaque(reader);
} }
var element2 = Read(reader) as MiNum<int> ?? var element2 =
throw new HandlerException("Unexpected type in array dimensions data."); Read(reader).Element as MiNum<int>
?? throw new HandlerException("Unexpected type in array dimensions data.");
var dimensions = ReadDimensionsArray(element2); var dimensions = ReadDimensionsArray(element2);
var element3 = Read(reader) as MiNum<sbyte> ?? throw new HandlerException("Unexpected type in array name."); var element3 =
Read(reader).Element as MiNum<sbyte>
?? throw new HandlerException("Unexpected type in array name.");
var name = ReadName(element3); var name = ReadName(element3);
if (flags.Class == ArrayType.MxCell) if (flags.Class == ArrayType.MxCell)
{ {
return ContinueReadingCellArray(reader, flags, dimensions, name); return new DataElementWithArrayFlags(ContinueReadingCellArray(reader, flags, dimensions, name));
} }
if (flags.Class == ArrayType.MxSparse) if (flags.Class == ArrayType.MxSparse)
@ -396,12 +411,12 @@ namespace MatFileHandler
return ContinueReadingSparseArray(reader, element1, dimensions, name); return ContinueReadingSparseArray(reader, element1, dimensions, name);
} }
var element4 = Read(reader); var element4 = Read(reader).Element;
var data = ReadData(element4); var data = ReadData(element4);
DataElement imaginaryData = null; DataElement imaginaryData = null;
if (flags.Variable.HasFlag(Variable.IsComplex)) if (flags.Variable.HasFlag(Variable.IsComplex))
{ {
var element5 = Read(reader); var element5 = Read(reader).Element;
imaginaryData = ReadData(element5); imaginaryData = ReadData(element5);
} }
@ -410,7 +425,10 @@ namespace MatFileHandler
var fieldNameLengthElement = data as MiNum<int> ?? var fieldNameLengthElement = data as MiNum<int> ??
throw new HandlerException( throw new HandlerException(
"Unexpected type in structure field name length."); "Unexpected type in structure field name length.");
return ContinueReadingStructure(reader, flags, dimensions, name, fieldNameLengthElement.Data[0]); return new DataElementWithArrayFlags(
ContinueReadingStructure(reader, dimensions, fieldNameLengthElement.Data[0]),
flags,
name);
} }
switch (flags.Class) switch (flags.Class)
@ -419,103 +437,129 @@ namespace MatFileHandler
switch (data) switch (data)
{ {
case MiNum<byte> _: case MiNum<byte> _:
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case MiNum<ushort> _: case MiNum<ushort> _:
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
default: default:
throw new NotSupportedException( throw new NotSupportedException(
$"This type of char array ({data.GetType()}) is not supported."); $"This type of char array ({data.GetType()}) is not supported.");
} }
case ArrayType.MxInt8: case ArrayType.MxInt8:
return DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<sbyte>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxUInt8: case ArrayType.MxUInt8:
if (flags.Variable.HasFlag(Variable.IsLogical)) if (flags.Variable.HasFlag(Variable.IsLogical))
{ {
return DataElementConverter.ConvertToMatNumericalArrayOf<bool>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<bool>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
} }
return DataElementConverter.ConvertToMatNumericalArrayOf<byte>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<byte>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxInt16: case ArrayType.MxInt16:
return DataElementConverter.ConvertToMatNumericalArrayOf<short>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<short>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxUInt16: case ArrayType.MxUInt16:
return DataElementConverter.ConvertToMatNumericalArrayOf<ushort>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<ushort>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxInt32: case ArrayType.MxInt32:
return DataElementConverter.ConvertToMatNumericalArrayOf<int>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<int>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxUInt32: case ArrayType.MxUInt32:
return DataElementConverter.ConvertToMatNumericalArrayOf<uint>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<uint>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxInt64: case ArrayType.MxInt64:
return DataElementConverter.ConvertToMatNumericalArrayOf<long>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<long>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxUInt64: case ArrayType.MxUInt64:
return DataElementConverter.ConvertToMatNumericalArrayOf<ulong>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<ulong>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxSingle: case ArrayType.MxSingle:
return DataElementConverter.ConvertToMatNumericalArrayOf<float>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<float>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
case ArrayType.MxDouble: case ArrayType.MxDouble:
return DataElementConverter.ConvertToMatNumericalArrayOf<double>( return new DataElementWithArrayFlags(
DataElementConverter.ConvertToMatNumericalArrayOf<double>(
flags, flags,
dimensions, dimensions,
name,
data, data,
imaginaryData); imaginaryData),
flags,
name);
default: default:
throw new HandlerException("Unknown data type."); throw new HandlerException("Unknown data type.");
} }

View File

@ -0,0 +1,28 @@
namespace MatFileHandler
{
internal class DataElementWithArrayFlags
{
public DataElementWithArrayFlags(DataElement element, ArrayFlags flags, string name, uint nzMax = 0)
{
Element = element;
Flags = flags;
Name = name;
NzMax = nzMax;
}
public DataElementWithArrayFlags(DataElement element)
{
Element = element;
Flags = default;
Name = default;
}
public DataElement Element { get; }
public ArrayFlags Flags { get; }
public string Name { get; }
public uint NzMax { get; }
}
}

View File

@ -12,45 +12,28 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatArray"/> class. /// Initializes a new instance of the <see cref="MatArray"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array properties.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param> protected MatArray(int[] dimensions)
protected MatArray(
ArrayFlags flags,
int[] dimensions,
string name)
{ {
Flags = flags;
Dimensions = dimensions; Dimensions = dimensions;
Name = name;
} }
/// <inheritdoc /> /// <inheritdoc />
public int[] Dimensions { get; } public int[] Dimensions { get; }
/// <summary>
/// Gets the array name.
/// </summary>
public string Name { get; }
/// <inheritdoc /> /// <inheritdoc />
public int Count => Dimensions.NumberOfElements(); public int Count => Dimensions.NumberOfElements();
/// <inheritdoc /> /// <inheritdoc />
public bool IsEmpty => Dimensions.Length == 0; public bool IsEmpty => Dimensions.Length == 0;
/// <summary>
/// Gets properties of the array.
/// </summary>
internal ArrayFlags Flags { get; }
/// <summary> /// <summary>
/// Returns a new empty array. /// Returns a new empty array.
/// </summary> /// </summary>
/// <returns>Empty array.</returns> /// <returns>Empty array.</returns>
public static MatArray Empty() public static MatArray Empty()
{ {
return new MatArray(new ArrayFlags { Class = ArrayType.MxCell, Variable = 0 }, new int[] { }, string.Empty); return new MatArray(new int[] { });
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -18,7 +18,7 @@ namespace MatFileHandler
/// <param name="name">Array name.</param> /// <param name="name">Array name.</param>
/// <param name="elements">Array elements.</param> /// <param name="elements">Array elements.</param>
public MatCellArray(ArrayFlags flags, int[] dimensions, string name, IEnumerable<IArray> elements) public MatCellArray(ArrayFlags flags, int[] dimensions, string name, IEnumerable<IArray> elements)
: base(flags, dimensions, name) : base(dimensions)
{ {
Data = elements.ToArray(); Data = elements.ToArray();
} }

View File

@ -15,13 +15,11 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatCharArrayOf{T}"/> class. /// Initializes a new instance of the <see cref="MatCharArrayOf{T}"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array parameters.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="rawData">Raw data (UTF-8 or UTF-16).</param> /// <param name="rawData">Raw data (UTF-8 or UTF-16).</param>
/// <param name="stringData">Contents as a string.</param> /// <param name="stringData">Contents as a string.</param>
internal MatCharArrayOf(ArrayFlags flags, int[] dimensions, string name, T[] rawData, string stringData) internal MatCharArrayOf(int[] dimensions, T[] rawData, string stringData)
: base(flags, dimensions, name, rawData) : base(dimensions, rawData)
{ {
StringData = stringData; StringData = stringData;
} }

View File

@ -3,9 +3,11 @@ using System.IO;
namespace MatFileHandler namespace MatFileHandler
{ {
/// <summary>
/// Reader for MATLAB "Level 5" .mat files.
/// </summary>
internal static class MatFileLevel5Reader internal static class MatFileLevel5Reader
{ {
/// <summary> /// <summary>
/// Read a sequence of raw variables from .mat file. /// Read a sequence of raw variables from .mat file.
/// </summary> /// </summary>
@ -29,13 +31,13 @@ namespace MatFileHandler
var dataElement = dataElementReader.Read(reader); var dataElement = dataElementReader.Read(reader);
if (position == subsystemDataOffset) if (position == subsystemDataOffset)
{ {
var subsystemDataElement = dataElement as IArrayOf<byte>; var subsystemDataElement = dataElement.Element as IArrayOf<byte>;
var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData); var newSubsystemData = ReadSubsystemData(subsystemDataElement.Data, subsystemData);
subsystemData.Set(newSubsystemData); subsystemData.Set(newSubsystemData);
} }
else else
{ {
variables.Add(new RawVariable(position, dataElement)); variables.Add(new RawVariable(position, dataElement.Element, dataElement.Flags, dataElement.Name));
} }
} }
catch (EndOfStreamException) catch (EndOfStreamException)
@ -63,18 +65,17 @@ namespace MatFileHandler
{ {
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 rawVariable in rawVariables)
{ {
var array = variable.DataElement as MatArray; if (!(rawVariable.DataElement is MatArray array))
if (array is null)
{ {
continue; continue;
} }
variables.Add(new MatVariable( variables.Add(new MatVariable(
array, array,
array.Name, rawVariable.Name,
array.Flags.Variable.HasFlag(Variable.IsGlobal))); rawVariable.Flags.Variable.HasFlag(Variable.IsGlobal)));
} }
return new MatFile(variables); return new MatFile(variables);

View File

@ -1,7 +1,6 @@
// Copyright 2017-2018 Alexander Luzgarev // Copyright 2017-2018 Alexander Luzgarev
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
namespace MatFileHandler namespace MatFileHandler

View File

@ -226,14 +226,14 @@ namespace MatFileHandler
writer.Write(new byte[] { 0, 0, 0, 0, 0, 0 }); writer.Write(new byte[] { 0, 0, 0, 0, 0, 0 });
} }
private void WriteSparseArrayFlags(BinaryWriter writer, SparseArrayFlags flags) private void WriteSparseArrayFlags(BinaryWriter writer, ArrayFlags flags, uint nzMax)
{ {
var flag = (byte)flags.ArrayFlags.Variable; var flag = (byte)flags.Variable;
WriteTag(writer, new Tag(DataType.MiUInt32, 8)); WriteTag(writer, new Tag(DataType.MiUInt32, 8));
writer.Write((byte)flags.ArrayFlags.Class); writer.Write((byte)flags.Class);
writer.Write(flag); writer.Write(flag);
writer.Write(new byte[] { 0, 0 }); writer.Write(new byte[] { 0, 0 });
writer.Write(flags.NzMax); writer.Write(nzMax);
} }
private void WriteName(BinaryWriter writer, string name) private void WriteName(BinaryWriter writer, string name)
@ -373,19 +373,16 @@ namespace MatFileHandler
} }
} }
private SparseArrayFlags GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero) private (ArrayFlags flags, uint nzMax) GetSparseArrayFlags<T>(ISparseArrayOf<T> array, bool isGlobal, uint nonZero)
where T : struct where T : struct
{ {
var flags = GetArrayFlags(array, isGlobal); var flags = GetArrayFlags(array, isGlobal);
return new SparseArrayFlags return (new ArrayFlags
{
ArrayFlags = new ArrayFlags
{ {
Class = ArrayType.MxSparse, Class = ArrayType.MxSparse,
Variable = flags.Variable, Variable = flags.Variable,
}, },
NzMax = nonZero, nonZero);
};
} }
private ArrayFlags GetCharArrayFlags(bool isGlobal) private ArrayFlags GetCharArrayFlags(bool isGlobal)
@ -513,7 +510,8 @@ namespace MatFileHandler
where T : struct, IEquatable<T> where T : struct, IEquatable<T>
{ {
(var rows, var columns, var data, var nonZero) = PrepareSparseArrayData(array); (var rows, var columns, var data, var nonZero) = PrepareSparseArrayData(array);
WriteSparseArrayFlags(writer, GetSparseArrayFlags(array, isGlobal, nonZero)); var (flags, nzMax) = GetSparseArrayFlags(array, isGlobal, nonZero);
WriteSparseArrayFlags(writer, flags, nzMax);
WriteDimensions(writer, array.Dimensions); WriteDimensions(writer, array.Dimensions);
WriteName(writer, name); WriteName(writer, name);
WriteSparseArrayValues(writer, rows, columns, data); WriteSparseArrayValues(writer, rows, columns, data);

View File

@ -17,12 +17,10 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatNumericalArrayOf{T}"/> class. /// Initializes a new instance of the <see cref="MatNumericalArrayOf{T}"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array parameters.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="data">Array contents.</param> /// <param name="data">Array contents.</param>
public MatNumericalArrayOf(ArrayFlags flags, int[] dimensions, string name, T[] data) public MatNumericalArrayOf(int[] dimensions, T[] data)
: base(flags, dimensions, name) : base(dimensions)
{ {
Data = data; Data = data;
} }

View File

@ -18,16 +18,10 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatSparseArrayOf{T}"/> class. /// Initializes a new instance of the <see cref="MatSparseArrayOf{T}"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array properties.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="data">Array contents.</param> /// <param name="data">Array contents.</param>
public MatSparseArrayOf( public MatSparseArrayOf(int[] dimensions, Dictionary<(int, int), T> data)
SparseArrayFlags flags, : base(dimensions)
int[] dimensions,
string name,
Dictionary<(int, int), T> data)
: base(flags.ArrayFlags, dimensions, name)
{ {
DataDictionary = data; DataDictionary = data;
} }

View File

@ -15,16 +15,10 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatStructureArray"/> class. /// Initializes a new instance of the <see cref="MatStructureArray"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array properties.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="fields">Array contents.</param> /// <param name="fields">Array contents.</param>
public MatStructureArray( public MatStructureArray(int[] dimensions, Dictionary<string, List<IArray>> fields)
ArrayFlags flags, : base(dimensions)
int[] dimensions,
string name,
Dictionary<string, List<IArray>> fields)
: base(flags, dimensions, name)
{ {
Fields = fields; Fields = fields;
} }

View File

@ -21,13 +21,12 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Opaque"/> class. /// Initializes a new instance of the <see cref="Opaque"/> class.
/// </summary> /// </summary>
/// <param name="name">Name of the object.</param>
/// <param name="typeDescription">Type description.</param> /// <param name="typeDescription">Type description.</param>
/// <param name="className">Class name.</param> /// <param name="className">Class name.</param>
/// <param name="dimensions">Dimensions of the object.</param> /// <param name="dimensions">Dimensions of the object.</param>
/// <param name="rawData">Raw object's data.</param> /// <param name="rawData">Raw object's data.</param>
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData) public Opaque(string typeDescription, string className, int[] dimensions, DataElement rawData)
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name) : base(dimensions)
{ {
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription)); TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
ClassName = className ?? throw new ArgumentNullException(nameof(className)); ClassName = className ?? throw new ArgumentNullException(nameof(className));

View File

@ -17,7 +17,6 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="OpaqueLink"/> class. /// Initializes a new instance of the <see cref="OpaqueLink"/> class.
/// </summary> /// </summary>
/// <param name="name">Name of the object.</param>
/// <param name="typeDescription">Description of object's class.</param> /// <param name="typeDescription">Description of object's class.</param>
/// <param name="className">Name of the object's class.</param> /// <param name="className">Name of the object's class.</param>
/// <param name="dimensions">Dimensions of the object.</param> /// <param name="dimensions">Dimensions of the object.</param>
@ -26,7 +25,6 @@ namespace MatFileHandler
/// <param name="classIndex">Index of object's class.</param> /// <param name="classIndex">Index of object's class.</param>
/// <param name="subsystemData">Reference to global subsystem data.</param> /// <param name="subsystemData">Reference to global subsystem data.</param>
public OpaqueLink( public OpaqueLink(
string name,
string typeDescription, string typeDescription,
string className, string className,
int[] dimensions, int[] dimensions,
@ -34,7 +32,7 @@ namespace MatFileHandler
int[] indexToObjectId, int[] indexToObjectId,
int classIndex, int classIndex,
SubsystemData subsystemData) SubsystemData subsystemData)
: base(name, typeDescription, className, dimensions, data) : base(typeDescription, className, dimensions, data)
{ {
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId)); IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
ClassIndex = classIndex; ClassIndex = classIndex;

View File

@ -17,10 +17,12 @@ namespace MatFileHandler
/// </summary> /// </summary>
/// <param name="offset">Offset of the variable in the source file.</param> /// <param name="offset">Offset of the variable in the source file.</param>
/// <param name="dataElement">Data element parsed from the file.</param> /// <param name="dataElement">Data element parsed from the file.</param>
internal RawVariable(long offset, DataElement dataElement) internal RawVariable(long offset, DataElement dataElement, ArrayFlags flags, string name)
{ {
Offset = offset; Offset = offset;
DataElement = dataElement ?? throw new ArgumentNullException(nameof(dataElement)); DataElement = dataElement ?? throw new ArgumentNullException(nameof(dataElement));
Flags = flags;
Name = name;
} }
/// <summary> /// <summary>
@ -28,6 +30,10 @@ namespace MatFileHandler
/// </summary> /// </summary>
public DataElement DataElement { get; } public DataElement DataElement { get; }
public ArrayFlags Flags { get; }
public string Name { get; }
/// <summary> /// <summary>
/// Gets offset of the variable in the .mat file. /// Gets offset of the variable in the .mat file.
/// </summary> /// </summary>

View File

@ -314,7 +314,6 @@ namespace MatFileHandler
{ {
var (dimensions, indexToObjectId, classIndex) = DataElementReader.ParseOpaqueData(uintArray.Data); var (dimensions, indexToObjectId, classIndex) = DataElementReader.ParseOpaqueData(uintArray.Data);
return new OpaqueLink( return new OpaqueLink(
uintArray.Name,
string.Empty, string.Empty,
string.Empty, string.Empty,
dimensions, dimensions,