From c03521701bc77fc959476a500e7b1cebc797f53e Mon Sep 17 00:00:00 2001 From: Hamzeh Javadi Date: Mon, 18 Dec 2017 01:29:09 +0330 Subject: [PATCH] Read complex variables. Add Imaginary and read complex variables. --- MatlabFileHelper.cs | 28 +++++++++++++++++++++ MatlabFileReader.cs | 59 ++++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/MatlabFileHelper.cs b/MatlabFileHelper.cs index 0bf60c1..c72ce2c 100644 --- a/MatlabFileHelper.cs +++ b/MatlabFileHelper.cs @@ -13,6 +13,7 @@ public class Variable public Type dataType; public String name; public object data; + public object Image; } internal enum MatfileVersion @@ -27,6 +28,14 @@ internal class Tag public object data; //In case of small data format, otherwise null } + internal class Flag + { + public Tag Tag; + public bool Complex = false; + public bool Global = false; + public bool Logical = false; + public Type dataClass; + } internal class Header { public String text; @@ -102,6 +111,25 @@ public static Tag ReadTag(this BinaryReader reader) return t; } + + public static Flag ReadFlag(this BinaryReader reader) + { + Flag f = new Flag() { Complex = false, Global = false, Logical = false }; + f.Tag = reader.ReadTag(); + UInt32 flagsClass = reader.ReadUInt32(); + byte flags = (byte)(flagsClass >> 8); + if ((flags & 0x08) == 0x08) + f.Complex = true; + if ((flags & 0x04) == 0x04) + f.Global = true; + if ((flags & 0x02) == 0x02) + f.Logical = true; + f.dataClass = MatfileHelper.parseArrayType((byte)flagsClass); + reader.ReadUInt32();//unused flags + //Flag f = matrixStream.ReadFlag(); + + return f; + } public static void AdvanceTo8ByteBoundary(this BinaryReader r) { long offset = (8 - (r.BaseStream.Position % 8)) % 8; diff --git a/MatlabFileReader.cs b/MatlabFileReader.cs index 94be7ac..4cc0b71 100644 --- a/MatlabFileReader.cs +++ b/MatlabFileReader.cs @@ -61,13 +61,15 @@ private static void ReadMatrix(ref Variable vi, UInt32 length, BinaryReader matr //Array flags //Will always be too large to be in small data format, so not checking t.data - t = MatfileHelper.ReadTag(matrixStream); - UInt32 flagsClass = matrixStream.ReadUInt32(); - byte flags = (byte)(flagsClass >> 8) ; - if ((flags & 0x80) == 0x80) - throw new IOException("Complex numbers not supported"); - vi.dataType = MatfileHelper.parseArrayType((byte)flagsClass); - matrixStream.ReadUInt32();//unused flags + //t = MatfileHelper.ReadTag(matrixStream); + //UInt32 flagsClass = matrixStream.ReadUInt32(); + //byte flags = (byte)(flagsClass >> 8) ; + //if ((flags & 0x80) == 0x08) + // throw new IOException("Complex numbers not supported"); + //vi.dataType = MatfileHelper.parseArrayType((byte)flagsClass); + //matrixStream.ReadUInt32();//unused flags + Flag Flag = matrixStream.ReadFlag(); + vi.dataType = Flag.dataClass; //Dimensions - There are always 2 dimensions, so this //tag will never be of small data format, i.e. not checking for t.data @@ -76,7 +78,7 @@ private static void ReadMatrix(ref Variable vi, UInt32 length, BinaryReader matr int elements = 1; for (int i = 0; i < arrayDimensions.Length; i++) { - int dimension = (int)matrixStream.ReadUInt32(); + int dimension = (int)matrixStream.ReadUInt32();// depends on sizeof(t.dataType) => MatfileHelper.MatlabBytesPerType(t.dataType) arrayDimensions[arrayDimensions.Length - i - 1] = dimension; elements *= dimension; } @@ -102,35 +104,48 @@ private static void ReadMatrix(ref Variable vi, UInt32 length, BinaryReader matr //Read and reshape data t = MatfileHelper.ReadTag(matrixStream); + reshape(ref vi.data, ref vi.dataType, matrixStream, t, arrayDimensions, elements); + + // Read Imaginary data + if (Flag.Complex) + { + t = matrixStream.ReadTag(); + reshape(ref vi.Image, ref vi.dataType, matrixStream, t, arrayDimensions, elements); + } + //Move on in case the data didn't end on a 64 byte boundary + matrixStream.BaseStream.Seek(offset + length, SeekOrigin.Begin); + } + + private static void reshape(ref object data, ref Type dataType, BinaryReader matrixStream, Tag t, int[] arrayDimensions, int elements) + { if (t.length / MatfileHelper.MatlabBytesPerType(t.dataType) != elements) throw new IOException("Read dimensions didn't correspond to header dimensions"); - + Array readBytes; if (t.data == null) - readBytes = MatfileHelper.CastToMatlabType(vi.dataType, matrixStream.ReadBytes((int)t.length)); + readBytes = MatfileHelper.CastToMatlabType(t.dataType, matrixStream.ReadBytes((int)t.length)); else readBytes = (Array)t.data; - Array reshapedData = Array.CreateInstance(vi.dataType, arrayDimensions); - if (t.dataType != vi.dataType) //This happens when matlab choses to store the data in a smaller datatype when the values permit it + Array reshapedData = Array.CreateInstance(dataType, elements);//elements variable replaced with arrayDimensions to sure Linear data + if (t.dataType != dataType) //This happens when matlab choses to store the data in a smaller datatype when the values permit it { - Array linearData = Array.CreateInstance(vi.dataType, readBytes.Length); + Array linearData = Array.CreateInstance(dataType, readBytes.Length); Array.Copy(readBytes, linearData, readBytes.Length); - Buffer.BlockCopy(linearData, 0, reshapedData, 0, linearData.Length * MatfileHelper.MatlabBytesPerType(vi.dataType)); - vi.dataType = t.dataType; + Buffer.BlockCopy(linearData, 0, reshapedData, 0, linearData.Length * MatfileHelper.MatlabBytesPerType(dataType)); + // dataType = t.dataType; } else //Readbytes is already in the correct type - Buffer.BlockCopy(readBytes, 0, reshapedData, 0, readBytes.Length * MatfileHelper.MatlabBytesPerType(vi.dataType)); + Buffer.BlockCopy(readBytes, 0, reshapedData, 0, readBytes.Length * MatfileHelper.MatlabBytesPerType(dataType)); - if(reshapedData.Length == 1) - vi.data = reshapedData.GetValue(0); + if (reshapedData.Length == 1) + data = reshapedData.GetValue(0); else - vi.data = reshapedData; + data = reshapedData; - //Move on in case the data didn't end on a 64 byte boundary - matrixStream.BaseStream.Seek(offset + length, SeekOrigin.Begin); + + } - public void Close() { readStream.Close();