private static void ReadMatrix(ref Variable vi, UInt32 length, BinaryReader matrixStream) { Tag t; long offset = matrixStream.BaseStream.Position; //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 //Dimensions - There are always 2 dimensions, so this //tag will never be of small data format, i.e. not checking for t.data t = MatfileHelper.ReadTag(matrixStream); int[] arrayDimensions = new int[t.length / MatfileHelper.MatlabBytesPerType(t.dataType)]; int elements = 1; for (int i = 0; i < arrayDimensions.Length; i++) { int dimension = (int)matrixStream.ReadUInt32(); arrayDimensions[arrayDimensions.Length - i - 1] = dimension; elements *= dimension; } //Don't keep single dimensions arrayDimensions = arrayDimensions.Where(x => x > 1).ToArray(); //If by doing this, we end up without dimensions, it means we had a 1x...x1 array. //We need at least 1 dimension to instantiate the final array, so... if (arrayDimensions.Length == 0) arrayDimensions = new int[1] { 1 }; //Array name t = MatfileHelper.ReadTag(matrixStream); if (t.data != null) { sbyte[] varname = t.data as sbyte[]; vi.name = Encoding.UTF8.GetString(Array.ConvertAll(varname, x => (byte)x)); } else { byte[] varname = matrixStream.ReadBytes((int)t.length); vi.name = Encoding.UTF8.GetString(varname); MatfileHelper.AdvanceTo8ByteBoundary(matrixStream); } //Read and reshape data t = MatfileHelper.ReadTag(matrixStream); 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)); 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 linearData = Array.CreateInstance(vi.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; } else //Readbytes is already in the correct type Buffer.BlockCopy(readBytes, 0, reshapedData, 0, readBytes.Length * MatfileHelper.MatlabBytesPerType(vi.dataType)); if(reshapedData.Length == 1) vi.data = reshapedData.GetValue(0); else vi.data = reshapedData; //Move on in case the data didn't end on a 64 byte boundary matrixStream.BaseStream.Seek(offset + length, SeekOrigin.Begin); }
private void ReadVariables() { Variables = new Dictionary<string, Variable>(); while(readStream.BaseStream.Position < readStream.BaseStream.Length) { Variable v = new Variable(); Tag t = MatfileHelper.ReadTag(readStream); if(t.dataType == null) throw new Exception("Not an array, don't know what to do with this stuff"); else if (t.dataType.Equals(typeof(Array))) //We use Array to indicate MiMatrix { ReadMatrix(ref v, t.length, readStream); } else if (t.dataType.Equals(typeof(ZlibStream))) { byte[] compressed = readStream.ReadBytes((int)t.length); byte[] decompressed = ZlibStream.UncompressBuffer(compressed); MemoryStream m = new MemoryStream(decompressed); BinaryReader br = new BinaryReader(m); Tag ct = MatfileHelper.ReadTag(br); ReadMatrix(ref v, ct.length, br); } else throw new Exception("Not an array, don't know what to do with this stuff"); Variables.Add(v.name, v); } }