#include "MatIO.hpp" #include "Sparse.hpp" #include "Exception.hpp" #include "Print.hpp" #include "Malloc.hpp" #include "MemPtr.hpp" #include "Array.hpp" #include "Interpreter.hpp" #include "Utils.hpp" #include // Things to still look at: // Logical/Global flags - done // Compressed mode write - done // Sparse matrices - done // Matrix size calculation - done // Load/Save interfacing - done const int CHUNK = 32768; extern void SwapBuffer(char* cp, int count, int elsize); // A class to read/write Matlab MAT files. Implemented based on the Matlab 7.1 // version of the file matfile_format.pdf from the Mathworks web site. void ComplexSplit(const Array &x, Array &real, Array &imag) { if (x.dataClass() == FM_COMPLEX) { real = Array(FM_FLOAT,x.dimensions()); imag = Array(FM_FLOAT,x.dimensions()); const float *dp = (const float *) x.getDataPointer(); float *rp = (float *) real.getReadWriteDataPointer(); float *ip = (float *) imag.getReadWriteDataPointer(); for (unsigned i=0;i= MatIO::mxDOUBLE_CLASS) && (type < MatIO::mxFUNCTION_CLASS)) || (type == MatIO::mxCHAR_CLASS)); } const uint8 bcomplexFlag = 8; const uint8 bglobalFlag = 4; const uint8 blogicalFlag = 2; uint32 UpperWord(uint32 x) { return x >> 16; } uint32 LowerWord(uint32 x) { return x & 0xffff; } uint8 ByteOne(uint32 x) { return (x & 0xff); } uint8 ByteTwo(uint32 x) { return ((x & 0xff00) >> 8); } uint8 ByteThree(int32 x) { return ((x & 0xff0000) >> 16); } uint8 ByteFour(uint32 x) { return ((x & 0xff000000) >> 24); } Array FromDimensions(Dimensions dims) { Array x(FM_INT32,Dimensions(1,dims.getLength())); for (int i=0;i maxDims) throw Exception(string("MAT Variable has more dimensions ") + string("than maxDims (currently set to ") + maxDims + ")."); // FIXME - more graceful ways to do this Dimensions dm; for (int i=0;i jrBlock(nnz); uint32 *jr = &jrBlock; int outptr = 0; for (int i=0;izalloc = NULL; zstream->zfree = NULL; zstream->opaque = NULL; zstream->next_in = NULL; zstream->next_out = m_compression_buffer; zstream->avail_in = 0; zstream->avail_out = CHUNK; int retval; retval = deflateInit(zstream,9); if (retval) throw Exception("defaultinit didn't work"); m_compressed_data = true; } void MatIO::WriteCompressedBytes(const void *dest, uint32 towrite) { zstream->next_in = (Bytef*) dest; zstream->avail_in = towrite; do { int ret = deflate(zstream,Z_NO_FLUSH); if (ret == Z_STREAM_ERROR) throw Exception("Compression engine failed on write!"); if (zstream->avail_out == 0) { WriteFileBytes(m_compression_buffer,CHUNK); zstream->avail_out = CHUNK; zstream->next_out = m_compression_buffer; } } while (zstream->avail_in); } void MatIO::CloseCompressor() { int ret; do { ret = deflate(zstream,Z_FINISH); if (zstream->avail_out == 0) { WriteFileBytes(m_compression_buffer,CHUNK); zstream->avail_out = CHUNK; zstream->next_out = m_compression_buffer; } } while (ret != Z_STREAM_END); WriteFileBytes(m_compression_buffer,CHUNK-zstream->avail_out); deflateEnd(zstream); free(zstream); m_compressed_data = false; Free(m_compression_buffer); } void MatIO::InitializeDecompressor(uint32 bcount) { // Allocate an array to hold the compressed bytes m_compression_buffer = (uint8*) Malloc(bcount); ReadFileBytes(m_compression_buffer,bcount); // Set up the zstream... zstream = (z_streamp) calloc(1,sizeof(z_stream)); zstream->zalloc = NULL; zstream->zfree = NULL; zstream->opaque = NULL; zstream->next_in = m_compression_buffer; zstream->next_out = NULL; zstream->avail_in = bcount; zstream->avail_out = 0; int retval; retval = inflateInit(zstream); if (retval) throw Exception("inflateInit didn't work"); m_compressed_data = true; } void MatIO::ReadCompressedBytes(void *dest, uint32 toread) { zstream->next_out = (Bytef*) dest; zstream->avail_out = toread; while (zstream->avail_out) { int ret = inflate(zstream,Z_SYNC_FLUSH); if (ret < 0) throw Exception(string("inflate failed with code: ") + ret); } } void MatIO::CloseDecompressor() { inflateEnd(zstream); free(zstream); m_compressed_data = false; Free(m_compression_buffer); } void MatIO::ReadFileBytes(void *dest, uint32 toread) { fread(dest,1,toread,m_fp); } void MatIO::WriteFileBytes(const void *dest, uint32 towrite) { fwrite(dest,1,towrite,m_fp); } void MatIO::WriteData(const void *dest, uint32 towrite) { m_writecount += towrite; if (m_phantomWriteMode) return; if (!m_compressed_data) WriteFileBytes(dest,towrite); else WriteCompressedBytes(dest,towrite); } void MatIO::ReadData(void *dest, uint32 toread) { if (!m_compressed_data) ReadFileBytes(dest,toread); else ReadCompressedBytes(dest,toread); } uint16 MatIO::getUint16() { uint16 x; ReadData(&x,sizeof(uint16)); if (m_endianSwap) SwapBuffer((char*)&x,1,sizeof(uint16)); return x; } uint32 MatIO::getUint32() { uint32 x; ReadData(&x,sizeof(uint32)); if (m_endianSwap) SwapBuffer((char*)&x,1,sizeof(uint32)); return x; } void MatIO::putUint16(uint16 x) { WriteData(&x,sizeof(uint16)); } void MatIO::putUint32(uint32 x) { WriteData(&x,sizeof(uint32)); } void MatIO::Align64Bit() { if (m_mode == readMode) { uint32 adjustBytes; if (!m_compressed_data) { adjustBytes = ((8-(ftell(m_fp)&0x7)) % 8); fseek(m_fp,adjustBytes,SEEK_CUR); } else { uint8 dummy[8]; adjustBytes = (8-(zstream->total_out) & 0x7); ReadCompressedBytes(dummy,adjustBytes); } } else { char buffer[8]; uint32 adjustBytes; adjustBytes = ((8-(m_writecount&0x7)) % 8); WriteData(buffer,adjustBytes); } } void MatIO::putStructArray(const Array &x) { // Calculate the maximum field name length rvstring fnames(x.fieldNames()); // FIXME - should we truncate to 32 byte fieldnames? int fieldNameCount = fnames.size(); size_t maxlen = 0; for (int i=0;iIJV // Replace the col_ptr array by a new one // [1,4,8,10,13,17,20] --> // [1 1 1, 2 2 2 2, 3 3, 4, 4, 4, 5...] void MatIO::putCellArray(const Array &x) { // Count how many elements we expect int num = x.getLength(); const Array *dp = (const Array *) x.getDataPointer(); for (int i=0;igetContext()->addGlobalVariable(name); eval->getContext()->insertVariable(name,a); } else { fieldnames << name; fieldvalues << a; } } } } if (nargout == 0) return ArrayVector(); else return ArrayVector() << Array::structConstructor(fieldnames,fieldvalues); } ArrayVector MatSaveFunction(string filename, rvstring names, Interpreter *eval) { MatIO m(filename,MatIO::writeMode); Context *cntxt = eval->getContext(); char header[116]; time_t t = time(NULL); snprintf(header, 116, "MATLAB 5.0 MAT-file, Created on: %s by %s", ctime(&t), Interpreter::getVersionString().c_str()); m.putHeader(header); for (int i=0;ilookupVariable(names[i]); if (toWrite.valid()) m.putArray(*toWrite,names[i],cntxt->isVariableGlobal(names[i])); else eval->warningMessage(string("variable ") + names[i] + " does not exist to save"); } return ArrayVector(); }