protected Type GetType(mxClass dataClass) { switch (dataClass) { case mxClass.DOUBLE: return(typeof(double)); case mxClass.SINGLE: return(typeof(Single)); case mxClass.INT8: return(typeof(byte)); case mxClass.INT32: return(typeof(int)); case mxClass.UINT32: return(typeof(uint)); case mxClass.INT64: return(typeof(long)); case mxClass.UINT64: return(typeof(ulong)); default: throw new ArgumentException("Cannot convert mxClass " + dataClass + " to Type"); } }
protected void WriteMatrixHeader(string name, int rows, int cols, mxClass dataClass, int elementSize, bool isComplex = false, bool isLogical = false) { // convert to a valid variable name name = MakeValidVariableName(name); int numNameBytes = ((name.Length + 7) / 8) * 8; // compute total size of buffer int numericBytes = 8 + elementSize * rows * cols; numericBytes = ((numericBytes + 7) / 8) * 8; int numBytes = 48 + numNameBytes + numericBytes; if (isComplex) { numBytes += numericBytes; } // write the data type field Write(MatType.MATRIX); Write(numBytes - 8); // number of bytes // write the array flags Write(MatType.UINT32); Write(8); // 8 bytes to follow int flags = (int)dataClass; if (isComplex) { flags |= 0x0800; } if (isLogical) { flags |= 0x0200; } Write(flags); Write(0); // write the dimension field Write(MatType.INT32); Write(8); // 8 bytes to follow Write(rows); // number of rows Write(cols); // number of columns // write the matrix name Write(MatType.INT8); Write(name.Length); // length of name in bytes Write(name, numNameBytes); }
protected Matrix ReadMatrix(mxClass dataClass, int rows, int cols) { Matrix result = new Matrix(rows, cols); MatType elementClass; int numDataBytes; bool isSmallFormat = ReadTypeAndSize(out elementClass, out numDataBytes); for (int j = 0; j < result.Cols; j++) { for (int i = 0; i < result.Rows; i++) { result[i, j] = (double)Convert.ChangeType(ReadElement(elementClass), typeof(double)); } } ReadPadding(numDataBytes, isSmallFormat); return(result); }
protected Array ReadArray(mxClass dataClass, int[] sizes) { Array result = Array.CreateInstance(GetType(dataClass), sizes); int numElts = result.Length; Reverse(sizes); int[] strides = StringUtil.ArrayStrides(sizes); Reverse(sizes); int[] index = new int[sizes.Length]; MatType elementClass; int numDataBytes; bool isSmallFormat = ReadTypeAndSize(out elementClass, out numDataBytes); for (int i = 0; i < numElts; i++) { StringUtil.LinearIndexToMultidimensionalIndex(i, strides, index); Reverse(index); object value = ReadElement(elementClass); result.SetValue(value, index); } ReadPadding(numDataBytes, isSmallFormat); return(result); }
/// <summary> /// Write a named array to the stream /// </summary> /// <param name="name"></param> /// <param name="array"></param> public void WriteArray(string name, Array array) { Type eltType = array.GetType().GetElementType(); mxClass dataClass = GetDataClass(eltType); // convert to a valid variable name name = MakeValidVariableName(name); // pad the name to an 8-byte boundary int numNameBytes = ((name.Length + 7) / 8) * 8; // precompute the cell bytes int numDataBytes = 0; int numDims = array.Rank; int numElts = array.Length; int[] sizes = new int[numDims]; for (int i = 0; i < numDims; i++) { sizes[i] = array.GetLength(i); } MatlabReader.Reverse(sizes); int[] strides = StringUtil.ArrayStrides(sizes); MatlabReader.Reverse(sizes); int[] index = new int[numDims]; List <byte[]> bytes = new List <byte[]>(); Stream oldWriter = writer; try { for (int i = 0; i < numElts; i++) { StringUtil.LinearIndexToMultidimensionalIndex(i, strides, index); MatlabReader.Reverse(index); object cell = array.GetValue(index); MemoryStream ms = new MemoryStream(128); writer = ms; if (dataClass == mxClass.CELL) { Write("", cell); } else if (dataClass == mxClass.DOUBLE) { Write((double)cell); } else if (dataClass == mxClass.SINGLE) { Write((Single)cell); } else if (dataClass == mxClass.INT8) { Write((byte)cell); } else if (dataClass == mxClass.INT16) { Write((short)cell); } else if (dataClass == mxClass.UINT16) { Write((ushort)cell); } else if (dataClass == mxClass.INT32) { Write((int)cell); } else if (dataClass == mxClass.UINT32) { Write((uint)cell); } else if (dataClass == mxClass.INT64) { Write((long)cell); } else if (dataClass == mxClass.UINT64) { Write((ulong)cell); } else { throw new NotImplementedException(dataClass.ToString()); } byte[] valueBytes = ms.ToArray(); bytes.Add(valueBytes); numDataBytes += valueBytes.Length; } } finally { writer = oldWriter; } // compute total size of buffer int sizeBytes = numDims * 4; if (numDims % 2 == 1) { sizeBytes += 4; } int numBytes = 32 + sizeBytes + numNameBytes + numDataBytes; if (dataClass != mxClass.CELL) { numBytes += 8; } // write the data type field Write(MatType.MATRIX); Write(numBytes); // number of bytes // write the array flags Write(MatType.UINT32); Write(8); // 8 bytes to follow Write((int)dataClass); Write(0); // reserved // write the dimension field Write(MatType.INT32); if (numDims == 1) { Write(8); // 8 bytes to follow Write(sizes[0]); Write(1); } else { Write(numDims * 4); for (int i = 0; i < numDims; i++) { Write(sizes[i]); } if (numDims % 2 == 1) { Write(0); } } // write the name Write(MatType.INT8); Write(name.Length); // length of name in bytes Write(name, numNameBytes); if (dataClass != mxClass.CELL) { MatType elementClass = GetElementClass(eltType); Write((int)elementClass); Write(numDataBytes); } // write the cell values for (int i = 0; i < bytes.Count; i++) { Write(bytes[i]); } }
/// <summary> /// Read a specific data type from the stream /// </summary> /// <param name="dataType">The type number as documented by the MAT format</param> /// <param name="name">On exit, the variable name</param> /// <returns>The data value, as a .NET object</returns> protected object Parse(MatType dataType, out string name) { if (dataType == MatType.COMPRESSED) { throw new NotImplementedException(); } if (dataType != MatType.MATRIX) { throw new NotImplementedException("dataType = " + dataType + " not implemented"); } // Flags MatType flagsType = (MatType)ReadInt(); if (flagsType != MatType.UINT32) { throw new NotImplementedException("flagsType = " + flagsType + " not recognized"); } int numFlagsBytes = ReadInt(); if (numFlagsBytes != 8) { throw new NotImplementedException("numFlagsBytes = " + numFlagsBytes + " not recognized"); } int flags = ReadInt(); bool isLogical = (flags & 0x0200) > 0; bool isComplex = (flags & 0x0800) > 0; mxClass dataClass = (mxClass)(flags & 0xff); if (dataClass > mxClass.UINT64) { throw new NotImplementedException("dataClass = " + dataClass + " not recognized"); } ReadInt(); // ignored // Size MatType sizeType = (MatType)ReadInt(); if (sizeType != MatType.INT32) { throw new NotImplementedException("sizeType = " + sizeType + " not recognized"); } int numSizeBytes = ReadInt(); int numDims = numSizeBytes / 4; int[] sizes = new int[numDims]; int numDimsGreaterThanOne = 0; for (int i = 0; i < numDims; i++) { sizes[i] = ReadInt(); if (sizes[i] > 1) { numDimsGreaterThanOne++; } } ReadPadding(numSizeBytes, false); bool isVector = (numDimsGreaterThanOne <= 1); int length = sizes[0] * sizes[1]; // Name name = ReadString(); if (dataClass == mxClass.CHAR) { return(ReadString()); } else if (dataClass == mxClass.CELL) { return(ReadCellArray(sizes)); } else if (dataClass == mxClass.STRUCT) { return(ReadStruct()); } else if (dataClass == mxClass.OBJECT || dataClass == mxClass.SPARSE) { throw new NotImplementedException("dataClass = " + dataClass + " not implemented"); } else if (isVector && dataClass == mxClass.INT32) { return(ReadIntArray(length)); } else if (isVector && dataClass == mxClass.UINT32) { return(ReadUIntArray(length)); } else if (isVector && dataClass == mxClass.INT64) { return(ReadLongArray(length)); } else if (isVector && dataClass == mxClass.UINT64) { return(ReadULongArray(length)); } else if (isVector && isLogical) { return(ReadBoolArray(length)); } else if (numDims == 2) { // Elements int rows = sizes[0]; int cols = sizes[1]; object real = ReadMatrix(dataClass, rows, cols); if (isComplex) { object imaginary = ReadMatrix(dataClass, rows, cols); ComplexMatrix cm = new ComplexMatrix(); cm.Real = (Matrix)real; cm.Imaginary = (Matrix)imaginary; return(cm); } else { return(real); } } else { if (isComplex) { throw new NotSupportedException("complex multi-dimensional arrays are not supported"); } // multi-dimensional array return(ReadArray(dataClass, sizes)); } }