/** @file mat.c * Matlab MAT version 5 file functions * @ingroup MAT */ /* * Copyright (C) 2005-2006 Christopher C. Hulbert * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* FIXME: Implement Unicode support */ #include #include #include #include #include #include "matio.h" #include "mat5.h" #include "mat4.h" #include "matio_private.h" static void ReadData(mat_t *mat, matvar_t *matvar) { if ( mat == NULL || matvar == NULL || mat->fp == NULL ) return; else if ( mat->version != MAT_FT_MAT4 ) Read5(mat,matvar); else if ( mat->version == MAT_FT_MAT4 ) Read4(mat,matvar); return; } /* *==================================================================== * Public Functions *==================================================================== */ /** @brief Creates a new Matlab MAT file * * Tries to create a new Matlab MAT file with the given name and optional * header string. If no header string is given, the default string * is used containing the software, version, and date in it. If a header * string is given, at most the first 116 characters is written to the file. * The given header string need not be the full 116 characters, but MUST be * NULL terminated. * @ingroup MAT * @param matname Name of MAT file to create * @param hdr_str Optional header string, NULL to use default * @return A pointer to the MAT file or NULL if it failed. This is not a * simple FILE * and should not be used as one. */ mat_t * Mat_Create(const char *matname,const char *hdr_str) { FILE *fp = NULL; mat_int16_t endian = 0, version; mat_t *mat = NULL; size_t err; time_t t; fp = fopen(matname,"wb"); if ( !fp ) return NULL; mat = malloc(sizeof(*mat)); if ( !mat ) { fclose(fp); return NULL; } mat->fp = NULL; mat->header = NULL; mat->subsys_offset = NULL; mat->filename = NULL; mat->version = 0; mat->byteswap = 0; mat->mode = 0; mat->bof = 0; t = time(NULL); mat->fp = fp; mat->filename = strdup_printf("%s",matname); mat->mode = MAT_ACC_RDWR; mat->byteswap = 0; mat->header = calloc(1,128); mat->subsys_offset = calloc(1,16); memset(mat->header,' ',128); if ( hdr_str == NULL ) { err = mat_snprintf(mat->header,116,"MATLAB 5.0 MAT-file, Platform: %s, " "Created By: libmatio v%d.%d.%d on %s", MATIO_PLATFORM, MATIO_MAJOR_VERSION, MATIO_MINOR_VERSION, MATIO_RELEASE_LEVEL, ctime(&t)); mat->header[115] = '\0'; /* Just to make sure it's NULL terminated */ } else { err = mat_snprintf(mat->header,116,"%s",hdr_str); } mat->header[err] = ' '; mat_snprintf(mat->subsys_offset,15," "); mat->version = (int)0x0100; endian = 0x4d49; version = 0x0100; err = fwrite(mat->header,1,116,mat->fp); err = fwrite(mat->subsys_offset,1,8,mat->fp); err = fwrite(&version,2,1,mat->fp); err = fwrite(&endian,2,1,mat->fp); return mat; } /** @brief Opens an existing Matlab MAT file * * Tries to open a Matlab MAT file with the given name * @ingroup MAT * @param matname Name of MAT file to open * @param mode File access mode (MAT_ACC_RDONLY,MAT_ACC_RDWR,etc). * @return A pointer to the MAT file or NULL if it failed. This is not a * simple FILE * and should not be used as one. */ mat_t * Mat_Open(const char *matname,int mode) { FILE *fp = NULL; mat_int16_t tmp, tmp2; int err; mat_t *mat = NULL; if ( (mode & 0x000000ff) == MAT_ACC_RDONLY ) { fp = fopen( matname, "rb" ); if ( !fp ) return NULL; } else if ( (mode & 0x000000ff) == MAT_ACC_RDWR ) { fp = fopen( matname, "r+b" ); if ( !fp ) { mat = Mat_Create(matname,NULL); return mat; } } else { mat = Mat_Create(matname,NULL); return mat; } mat = malloc(sizeof(mat_t)); if ( !mat ) { Mat_Critical("Couldn't allocate memory for the MAT file"); fclose(fp); return NULL; } mat->fp = fp; if ( mode & MAT_FT_MAT4 ) { mat->header = NULL; mat->subsys_offset = NULL; mat->version = MAT_FT_MAT4; mat->byteswap = 0; mat->mode = mode; mat->filename = strdup_printf("%s",matname); mat->bof = ftell(mat->fp); } else { mat->header = malloc(128); mat->subsys_offset = malloc(8); mat->filename = NULL; err = fread(mat->header,1,116,fp); mat->header[116] = '\0'; err = fread(mat->subsys_offset,1,8,fp); err = fread(&tmp2,2,1,fp); fread (&tmp,1,2,fp); mat->bof = ftell(mat->fp); mat->byteswap = -1; if (tmp == 0x4d49) mat->byteswap = 0; else if (tmp == 0x494d) { mat->byteswap = 1; Mat_int16Swap(&tmp2); } mat->version = (int)tmp2; if ( mat->byteswap < 0 ) { Mat_Critical("%s does not seem to be a valid MAT file",matname); Mat_Close(mat); mat=NULL; } else if ( mat->version != 0x0100 ) { Mat_Critical("%s is not a version 5 MAT file", matname); Mat_Close(mat); mat=NULL; } else { mat->filename = strdup_printf("%s",matname); mat->mode = mode; } } return mat; } /** @brief Closes an open Matlab MAT file * * Closes the given Matlab MAT file and frees any memory with it. * @ingroup MAT * @param mat Pointer to the MAT file * @retval 0 */ int Mat_Close( mat_t *mat ) { if ( NULL != mat ) { if ( mat->fp ) fclose(mat->fp); if ( mat->header ) free(mat->header); if ( mat->subsys_offset ) free(mat->subsys_offset); if ( mat->filename ) free(mat->filename); free(mat); } return 0; } /** @brief Rewinds a Matlab MAT file to the first variable * * Rewinds a Matlab MAT file to the first variable * @ingroup MAT * @param mat Pointer to the MAT file * @retval 0 on success */ int Mat_Rewind( mat_t *mat ) { if ( mat->version != MAT_FT_MAT4 ) fseek(mat->fp,128L,SEEK_SET); else fseek(mat->fp,0L,SEEK_SET); return 0; } /** @brief Returns the size of a Matlab Class * * Returns the size (in bytes) of the matlab class class_type * @ingroup MAT * @param class_type Matlab class type (MAT_C_*) * @returns Size of the class */ size_t Mat_SizeOfClass(int class_type) { switch (class_type) { case MAT_C_DOUBLE: return sizeof(double); case MAT_C_SINGLE: return sizeof(float); #ifdef HAVE_MAT_INT64_T case MAT_C_INT64: return sizeof(mat_int64_t); #endif #ifdef HAVE_MAT_UINT64_T case MAT_C_UINT64: return sizeof(mat_uint64_t); #endif case MAT_C_INT32: return sizeof(mat_int32_t); case MAT_C_UINT32: return sizeof(mat_uint32_t); case MAT_C_INT16: return sizeof(mat_int16_t); case MAT_C_UINT16: return sizeof(mat_uint16_t); case MAT_C_INT8: return sizeof(mat_int8_t); case MAT_C_UINT8: return sizeof(mat_uint8_t); case MAT_C_CHAR: return sizeof(mat_int16_t); default: return 0; } } /* *=================================================================== * MAT Variable Functions *=================================================================== */ /** @brief Allocates memory for a new matvar_t and initializes all the fields * * @ingroup MAT * @return A newly allocated matvar_t */ matvar_t * Mat_VarCalloc(void) { matvar_t *matvar; matvar = malloc(sizeof(*matvar)); if ( NULL != matvar ) { matvar->nbytes = 0; matvar->rank = 0; matvar->data_type = 0; matvar->data_size = 0; matvar->class_type = 0; matvar->isComplex = 0; matvar->isGlobal = 0; matvar->isLogical = 0; matvar->dims = NULL; matvar->name = NULL; matvar->data = NULL; matvar->mem_conserve = 0; matvar->compression = 0; matvar->fpos = 0; matvar->datapos = 0; matvar->fp = NULL; #if defined(HAVE_ZLIB) matvar->z = NULL; #endif } return matvar; } /** @brief Creates a MAT Variable with the given name and (optionally) data * * Creates a MAT variable that can be written to a Matlab MAT file with the * given name, data type, dimensions and data. Rank should always be 2 or more. * i.e. Scalar values would have rank=2 and dims[2] = {1,1}. Data type is * one of the MAT_T types. MAT adds MAT_T_STRUCT and MAT_T_CELL to create * Structures and Cell Arrays respectively. For MAT_T_STRUCT, data should be a * NULL terminated array of matvar_t * variables (i.e. for a 3x2 structure with * 10 fields, there should be 61 matvar_t * variables where the last one is * NULL). For cell arrays, the NULL termination isn't necessary. So to create * a cell array of size 3x2, data would be the address of an array of 6 * matvar_t * variables. * * EXAMPLE: * To create a struct of size 3x2 with 3 fields: * @code * int rank=2, dims[2] = {3,2}, nfields = 3; * matvar_t **vars; * * vars = malloc((3*2*nfields+1)*sizeof(matvar_t *)); * vars[0] = Mat_VarCreate(...); * : * vars[3*2*nfields-1] = Mat_VarCreate(...); * vars[3*2*nfields] = NULL; * @endcode * * EXAMPLE: * To create a cell array of size 3x2: * @code * int rank=2, dims[2] = {3,2}; * matvar_t **vars; * * vars = malloc(3*2*sizeof(matvar_t *)); * vars[0] = Mat_VarCreate(...); * : * vars[5] = Mat_VarCreate(...); * @endcode * * @ingroup MAT * @param name Name of the variable to create * @param class_type class type of the variable in Matlab(one of the mx Classes) * @param data_type data type of the variable (one of the MAT_T_ Types) * @param rank Rank of the variable * @param dims array of dimensions of the variable of size rank * @param data pointer to the data * @param opt 0, or bitwise or of the following options: * - MEM_CONSERVE to just use the pointer to the data and not copy the data * itself. Note that the pointer should not be freed until you are done * with the mat variable. The Mat_VarFree function will NOT free * data that was created with MEM_CONSERVE, so free it yourself. * - MAT_F_COMPLEX to specify that the data is complex. The data variable should * be a contigouse piece of memory with the real part written first and * the imaginary second * - MAT_F_GLOBAL to assign the variable as a global variable * - MAT_F_LOGICAL to specify that it is a logical variable * @return A MAT variable that can be written to a file or otherwise used */ matvar_t * Mat_VarCreate(const char *name,int class_type,int data_type,int rank,int *dims, void *data,int opt) { int i, nmemb = 1, nfields = 0; matvar_t *matvar = NULL; if (dims == NULL) return NULL; matvar = Mat_VarCalloc(); if ( NULL == matvar ) return NULL; matvar->compression = COMPRESSION_NONE; matvar->isComplex = opt & MAT_F_COMPLEX; matvar->isGlobal = opt & MAT_F_GLOBAL; matvar->isLogical = opt & MAT_F_LOGICAL; if ( name ) matvar->name = strdup_printf("%s",name); matvar->rank = rank; matvar->dims = malloc(matvar->rank*sizeof(int)); for ( i = 0; i < matvar->rank; i++ ) { matvar->dims[i] = dims[i]; nmemb *= dims[i]; } matvar->class_type = class_type; matvar->data_type = data_type; switch ( data_type ) { case MAT_T_INT8: matvar->data_size = 1; break; case MAT_T_UINT8: matvar->data_size = 1; break; case MAT_T_INT16: matvar->data_size = 2; break; case MAT_T_UINT16: matvar->data_size = 2; break; case MAT_T_INT64: matvar->data_size = 8; break; case MAT_T_UINT64: matvar->data_size = 8; break; case MAT_T_INT32: matvar->data_size = 4; break; case MAT_T_UINT32: matvar->data_size = 4; break; case MAT_T_SINGLE: matvar->data_size = sizeof(float); break; case MAT_T_DOUBLE: matvar->data_size = sizeof(double); break; case MAT_T_UTF8: matvar->data_size = 1; break; case MAT_T_UTF16: matvar->data_size = 2; break; case MAT_T_UTF32: matvar->data_size = 4; break; case MAT_T_CELL: matvar->data_size = sizeof(matvar_t **); break; case MAT_T_STRUCT: { matvar_t **fields; if ( data == NULL ) break; fields = data; nfields = 0; while ( fields[nfields] != NULL ) nfields++; matvar->data_size = sizeof(matvar_t **); nmemb = nfields; /* nfields is really nmemb*nfields */ break; } default: Mat_Error("Unrecognized data_type"); Mat_VarFree(matvar); return NULL; } if ( matvar->class_type == MAT_C_CHAR ) { #if 0 matvar->data_size = 1; nmemb++; #endif matvar->nbytes = nmemb*matvar->data_size; } else if ( matvar->class_type == MAT_C_SPARSE ) { matvar->data_size = sizeof(sparse_t); matvar->nbytes = nmemb*matvar->data_size; } else { matvar->nbytes = nmemb*matvar->data_size; } if ( data == NULL ) { matvar->data = NULL; } else if ( opt & MEM_CONSERVE ) { if ( matvar->isComplex ) { matvar->data = malloc(sizeof(struct ComplexSplit)); if ( NULL != data ) { struct ComplexSplit *complex_data = matvar->data; struct ComplexSplit *complex_data_in = data; *complex_data = *complex_data_in; } } else { matvar->data = (void*)data; } matvar->mem_conserve = 1; } else { if ( matvar->isComplex ) { matvar->data = malloc(sizeof(struct ComplexSplit)); if ( NULL != matvar->data ) { struct ComplexSplit *complex_data = matvar->data; struct ComplexSplit *complex_data_in = data; complex_data->Re = malloc(matvar->nbytes); complex_data->Im = malloc(matvar->nbytes); if ( NULL != complex_data->Re ) memcpy(complex_data->Re,complex_data_in->Re,matvar->nbytes); if ( NULL != complex_data->Im ) memcpy(complex_data->Im,complex_data_in->Im,matvar->nbytes); } } else { matvar->data = malloc(matvar->nbytes); if ( NULL != matvar->data ) memcpy(matvar->data,data,matvar->nbytes); } matvar->mem_conserve = 0; } return matvar; } /** @brief Deletes a variable from a file * * @ingroup MAT * @param mat Pointer to the mat_t file structure * @param name Name of the variable to delete * @returns 0 on success */ int Mat_VarDelete(mat_t *mat, char *name) { int err = 1; char *tmp_name, *new_name, *temp; mat_t *tmp; matvar_t *matvar; temp = strdup_printf("XXXXXX"); tmp_name = mktemp(temp); tmp = Mat_Create(tmp_name,mat->header); if ( tmp != NULL ) { while ( NULL != (matvar = Mat_VarReadNext(mat)) ) { if ( strcmp(matvar->name,name) ) Mat_VarWrite(tmp,matvar,0); else err = 0; Mat_VarFree(matvar); } /* FIXME: Memory leak */ new_name = strdup_printf("%s",mat->filename); fclose(mat->fp); if ( (err = remove(new_name)) == -1 ) { Mat_Critical("remove of %s failed",new_name); } else if ( !Mat_Close(tmp) && (err=rename(tmp_name,new_name))==-1) { Mat_Critical("rename failed oldname=%s,newname=%s",tmp_name, new_name); } else { tmp = Mat_Open(new_name,mat->mode); memcpy(mat,tmp,sizeof(mat_t)); } free(tmp); free(new_name); } free(temp); return err; } /** @brief Duplicates a matvar_t structure * * Provides a clean function for duplicating a matvar_t structure. * @ingroup MAT * @param in pointer to the matvar_t structure to be duplicated * @param opt 0 does a shallow duplicate and only assigns the data pointer to * the duplicated array. 1 will do a deep duplicate and actually * duplicate the contents of the data. Warning: If you do a shallow * copy and free both structures, the data will be freed twice and * memory will be corrupted. This may be fixed in a later release. * @returns Pointer to the duplicated matvar_t structure. */ matvar_t * Mat_VarDuplicate(const matvar_t *in, int opt) { matvar_t *out; int i; out = malloc(sizeof(matvar_t)); if ( out == NULL ) return NULL; out->nbytes = in->nbytes; out->rank = in->rank; out->data_type = in->data_type; out->data_size = in->data_size; out->class_type = in->class_type; out->isComplex = in->isComplex; out->isGlobal = in->isGlobal; out->isLogical = in->isLogical; out->mem_conserve = in->mem_conserve; out->compression = in->compression; out->fpos = in->fpos; out->datapos = in->datapos; out->name = NULL; out->dims = NULL; out->data = NULL; #if defined(HAVE_ZLIB) out->z = NULL; #endif if (in->name != NULL && (NULL != (out->name = malloc(strlen(in->name)+1)))) memcpy(out->name,in->name,strlen(in->name)+1); out->dims = malloc(in->rank*sizeof(int)); if ( out->dims != NULL ) memcpy(out->dims,in->dims,in->rank*sizeof(int)); #if defined(HAVE_ZLIB) if ( (in->z != NULL) && (NULL != (out->z = malloc(sizeof(z_stream)))) ) inflateCopy(out->z,in->z); #endif if ( !opt ) { out->data = in->data; } else if ( (in->data != NULL) && (in->class_type == MAT_C_STRUCT) ) { matvar_t **infields, **outfields; int nfields = 0; out->data = malloc(in->nbytes); if ( out->data != NULL && in->data_size > 0 ) { nfields = in->nbytes / in->data_size; infields = (matvar_t **)in->data; outfields = (matvar_t **)out->data; for ( i = 0; i < nfields; i++ ) { outfields[i] = Mat_VarDuplicate(infields[i],opt); } } } else if ( (in->data != NULL) && (in->class_type == MAT_C_CELL) ) { matvar_t **incells, **outcells; int ncells = 0; out->data = malloc(in->nbytes); if ( out->data != NULL && in->data_size > 0 ) { ncells = in->nbytes / in->data_size; incells = (matvar_t **)in->data; outcells = (matvar_t **)out->data; for ( i = 0; i < ncells; i++ ) { outcells[i] = Mat_VarDuplicate(incells[i],opt); } } } else if ( in->data != NULL ) { if ( out->isComplex ) { out->data = malloc(sizeof(struct ComplexSplit)); if ( out->data != NULL ) { struct ComplexSplit *out_data = out->data; struct ComplexSplit *in_data = in->data; out_data->Re = malloc(out->nbytes); if ( NULL != out_data->Re ) memcpy(out_data->Re,in_data->Re,out->nbytes); out_data->Im = malloc(out->nbytes); if ( NULL != out_data->Im ) memcpy(out_data->Im,in_data->Im,out->nbytes); } } else { out->data = malloc(in->nbytes); if ( out->data != NULL ) memcpy(out->data,in->data,in->nbytes); } } return out; } /** @brief Frees all the allocated memory associated with the structure * * Frees memory used by a MAT variable. Frees the data associated with a * MAT variable if it's non-NULL and MEM_CONSERVE was not used. * @ingroup MAT * @param matvar Pointer to the matvar_t structure */ void Mat_VarFree(matvar_t *matvar) { if ( !matvar ) return; if ( matvar->dims ) free(matvar->dims); if ( matvar->name ) free(matvar->name); if ( (matvar->data != NULL) && (matvar->class_type == MAT_C_STRUCT || matvar->class_type == MAT_C_CELL) && matvar->data_size > 0 ) { int i; matvar_t **fields = matvar->data; int nfields = matvar->nbytes / matvar->data_size; for ( i = 0; i < nfields; i++ ) Mat_VarFree(fields[i]); free(matvar->data); } else if ( (matvar->data != NULL) && (!matvar->mem_conserve) && (matvar->class_type == MAT_C_SPARSE) ) { sparse_t *sparse; sparse = matvar->data; if ( sparse->ir != NULL ) free(sparse->ir); if ( sparse->jc != NULL ) free(sparse->jc); if ( sparse->data != NULL ) free(sparse->data); free(sparse); } else { if ( matvar->isComplex && NULL != matvar->data ) { struct ComplexSplit *complex_data = matvar->data; if ( !matvar->mem_conserve ) { free(complex_data->Re); free(complex_data->Im); } free(complex_data); } else { if ( matvar->data && !matvar->mem_conserve ) free(matvar->data); } } #if defined(HAVE_ZLIB) if ( matvar->compression == COMPRESSION_ZLIB ) { inflateEnd(matvar->z); free(matvar->z); } #endif /* FIXME: Why does this cause a SEGV? */ #if 0 memset(matvar,0,sizeof(matvar_t)); #endif free(matvar); } void Mat_VarFree2(matvar_t *matvar) { if ( !matvar ) return; if ( matvar->dims ) free(matvar->dims); if ( matvar->name ) free(matvar->name); if ( (matvar->data != NULL) && (matvar->class_type == MAT_C_STRUCT || matvar->class_type == MAT_C_CELL) && matvar->data_size > 0 ) { int i; matvar_t **fields = (matvar_t **)matvar->data; int nfields = matvar->nbytes / matvar->data_size; for ( i = 0; i < nfields; i++ ) Mat_VarFree(fields[i]); free(matvar->data); } else if ( (matvar->data != NULL) && (!matvar->mem_conserve) && (matvar->class_type == MAT_C_SPARSE) ) { sparse_t *sparse; sparse = matvar->data; if ( sparse->ir != NULL ) free(sparse->ir); if ( sparse->jc != NULL ) free(sparse->jc); if ( sparse->data != NULL ) free(sparse->data); free(sparse); } else { if ( matvar->data && !matvar->mem_conserve ) free(matvar->data); } #if defined(HAVE_ZLIB) if ( matvar->compression == COMPRESSION_ZLIB ) inflateEnd(matvar->z); #endif /* FIXME: Why does this cause a SEGV? */ #if 0 memset(matvar,0,sizeof(matvar_t)); #endif } /** @brief Calculate a single subscript from a set of subscript values * * Calculates a single linear subscript (0-relative) given a 1-relative * subscript for each dimension. The calculation uses the formula below where * index is the linear index, s is an array of length RANK where each element * is the subscript for the correspondind dimension, D is an array whose * elements are the dimensions of the variable. * \f[ * index = \sum\limits_{k=0}^{RANK-1} [(s_k - 1) \prod\limits_{l=0}^{k} D_l ] * \f] * @ingroup MAT * @param rank Rank of the variable * @param dims dimensions of the variable * @param subs Dimension subscripts * @return Single (linear) subscript */ int Mat_CalcSingleSubscript(int rank,int *dims,int *subs) { int index = 0, i, j, k, err = 0; for ( i = 0; i < rank; i++ ) { k = subs[i]; if ( k > dims[i] ) { err = 1; Mat_Critical("Mat_CalcSingleSubscript: index out of bounds"); break; } else if ( k < 1 ) { err = 1; break; } k--; for ( j = i; j--; ) k *= dims[j]; index += k; } if ( err ) index = -1; return index; } /** @brief Calculate a set of subscript values from a single(linear) subscript * * Calculates 1-relative subscripts for each dimension given a 0-relative * linear index. Subscripts are calculated as follows where s is the array * of dimension subscripts, D is the array of dimensions, and index is the * linear index. * \f[ * s_k = \lfloor\frac{1}{L} \prod\limits_{l = 0}^{k} D_l\rfloor + 1 * \f] * \f[ * L = index - \sum\limits_{l = k}^{RANK - 1} s_k \prod\limits_{m = 0}^{k} D_m * \f] * @ingroup MAT * @param rank Rank of the variable * @param dims dimensions of the variable * @param index linear index * @return Array of dimension subscripts */ int * Mat_CalcSubscripts(int rank,int *dims,int index) { int i, j, k, *subs; double l; subs = malloc(rank*sizeof(int)); l = index; for ( i = rank; i--; ) { k = 1; for ( j = i; j--; ) k *= dims[j]; subs[i] = floor(l / (double)k); l -= subs[i]*k; subs[i]++; } return subs; } /** @brief Returns a pointer to the Cell array at a specific index * * Returns a pointer to the Cell Array Field at the given 1-relative index. * MAT file must be a version 5 matlab file. * @ingroup MAT * @param matvar Pointer to the Cell Array MAT variable * @param index linear index of cell to return * @return Pointer to the Cell Array Field on success, NULL on error */ matvar_t * Mat_VarGetCell(matvar_t *matvar,int index) { int nmemb = 1, i; matvar_t *cell = NULL; if ( matvar == NULL ) return NULL; for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; if ( index < nmemb ) cell = *((matvar_t **)matvar->data + index); return cell; } /** @brief Indexes a cell array * * Finds cells of a cell array given a start, stride, and edge for each. * dimension. The cells are placed in a pointer array. The cells should not * be freed, but the array of pointers should be. If copies are needed, * use Mat_VarDuplicate on each cell. * MAT File version must be 5. * @ingroup MAT * @param matvar Cell Array matlab variable * @param start vector of length rank with 0-relative starting coordinates for * each diemnsion. * @param stride vector of length rank with strides for each diemnsion. * @param edge vector of length rank with the number of elements to read in * each diemnsion. * @returns an array of pointers to the cells */ matvar_t ** Mat_VarGetCells(matvar_t *matvar,int *start, int *stride,int *edge) { int i, j, N, I = 0; int inc[10] = {0,}, cnt[10] = {0,}, dimp[10] = {0,}; matvar_t **cells; if ( (matvar == NULL) || (start == NULL) || (stride == NULL) || (edge == NULL) ) { return NULL; } else if ( matvar->rank > 10 ) { return NULL; } inc[0] = stride[0]-1; dimp[0] = matvar->dims[0]; N = edge[0]; I = start[0]; for ( i = 1; i < matvar->rank; i++ ) { inc[i] = stride[i]-1; dimp[i] = matvar->dims[i-1]; for ( j = i ; j--; ) { inc[i] *= matvar->dims[j]; dimp[i] *= matvar->dims[j+1]; } N *= edge[i]; if ( start[i] > 0 ) I += start[i]*dimp[i-1]; } cells = malloc(N*sizeof(matvar_t *)); for ( i = 0; i < N; i+=edge[0] ) { for ( j = 0; j < edge[0]; j++ ) { cells[i+j] = *((matvar_t **)matvar->data + I); I += stride[0]; } for ( j = 1; j < matvar->rank-1; j++ ) { cnt[j]++; if ( (cnt[j] % edge[j]) == 0 ) { cnt[j] = 0; if ( (I % dimp[j]) != 0 ) { I += dimp[j]-(I % dimp[j]); } } else { I += matvar->dims[0]-edge[0]*stride[0]-start[0]; I += inc[j]; break; } } } return cells; } /** @brief Indexes a cell array * * Finds cells of a cell array given a linear indexed start, stride, and edge. * The cells are placed in a pointer array. The cells themself should not * be freed as they are part of the original cell array, but the pointer array * should be. If copies are needed, use Mat_VarDuplicate on each of the cells. * MAT file version must be 5. * @ingroup MAT * @param matvar Cell Array matlab variable * @param start starting index * @param stride stride * @param edge Number of cells to get * @returns an array of pointers to the cells */ matvar_t ** Mat_VarGetCellsLinear(matvar_t *matvar,int start,int stride,int edge) { int i, I = 0; matvar_t **cells; if ( matvar == NULL || matvar->rank > 10 ) { cells = NULL; } else { cells = malloc(edge*sizeof(matvar_t *)); for ( i = 0; i < edge; i++ ) { cells[i] = *((matvar_t **)matvar->data + I); I += stride; } } return cells; } /** @brief Calculates the size of a matlab variable in bytes * * @ingroup MAT * @param matvar matlab variable * @returns size of the variable in bytes */ size_t Mat_VarGetSize(matvar_t *matvar) { int nmemb, i; size_t bytes = 0; if ( matvar->class_type == MAT_C_STRUCT ) { int nfields; matvar_t **fields; /* This is really nmemb*nfields, but we'll get a * more accurate count of the bytes by loopoing over all of them */ nfields = matvar->nbytes / matvar->data_size; fields = matvar->data; for ( i = 0; i < nfields; i++ ) bytes += Mat_VarGetSize(fields[i]); } else if ( matvar->class_type == MAT_C_CELL ) { int ncells; matvar_t **cells; ncells = matvar->nbytes / matvar->data_size; cells = matvar->data; for ( i = 0; i < ncells; i++ ) bytes += Mat_VarGetSize(cells[i]); } else { nmemb = 1; for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; bytes += nmemb*Mat_SizeOfClass(matvar->class_type); } return bytes; } /** @brief Adds a field to a structure * * Adds the given field to the structure. fields should be an array of matvar_t * pointers of the same size as the structure (i.e. 1 field per structure * element). * @ingroup MAT * @param matvar Pointer to the Structure MAT variable * @param fields Array of fields to be added * @retval 0 on success */ int Mat_VarAddStructField(matvar_t *matvar,matvar_t **fields) { int i, f, nfields, nmemb, cnt = 0; matvar_t **new_data,**old_data; if ( matvar == NULL || fields == NULL ) return -1; nmemb = 1; for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; nfields = matvar->nbytes / (nmemb*sizeof(matvar_t *)); new_data = malloc((nfields+1)*nmemb*sizeof(matvar_t *)); if ( new_data == NULL ) return -1; old_data = matvar->data; for ( i = 0; i < nmemb; i++ ) { for ( f = 0; f < nfields; f++ ) new_data[cnt++] = old_data[i*nfields+f]; new_data[cnt++] = fields[i]; } free(matvar->data); matvar->data = new_data; matvar->nbytes = (nfields+1)*nmemb*sizeof(matvar_t *); return 0; } /** @brief Returns the number of fields in a structure variable * * Returns the number of fields in the given structure. * MAT file version must be 5. * @ingroup MAT * @param matvar Structure matlab variable * @returns Number of fields, or a negative number on error */ int Mat_VarGetNumberOfFields(matvar_t *matvar) { int i, nfields, nmemb = 1; if ( matvar == NULL || matvar->class_type != MAT_C_STRUCT || matvar->data_size == 0 ) { nfields = -1; } else { for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; nfields = matvar->nbytes / (nmemb*matvar->data_size); } return nfields; } /** @brief Finds a field of a structure * * Returns a pointer to the structure field at the given 0-relative index. MAT * file version must be 5. * @ingroup MAT * @param matvar Pointer to the Structure MAT variable * @param name_or_index Name of the field, or the 1-relative index of the field. * If the index is used, it should be the address of an integer variable whose * value is the index number. * @param opt BY_NAME if the name_or_index is the name or BY_INDEX if the index * was passed. * @param index linear index of the structure to find the field of * @return Pointer to the Structure Field on success, NULL on error */ matvar_t * Mat_VarGetStructField(matvar_t *matvar,void *name_or_index,int opt,int index) { int i, err = 0, nfields, nmemb; matvar_t *field = NULL; nmemb = 1; for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; nfields = matvar->nbytes / (nmemb*sizeof(matvar_t *)); if ( index >= nmemb || index < 0) err = 1; if ( !err && (opt == BY_INDEX) ) { int field_index; field_index = *(int *)name_or_index; if ( field_index > nfields || field_index < 1 ) Mat_Critical("Mat_VarGetStructField: field index out of bounds"); else field = *((matvar_t **)matvar->data+index*nfields+field_index - 1); } else if ( !err && (opt == BY_NAME) ) { char *field_name; field_name = (char *)name_or_index; for ( i = 0; i < nfields; i++ ) { field = *((matvar_t **)matvar->data+index*nfields+i); if ( !strcmp(field->name,field_name) ) break; else field = NULL; } } return field; } /** @brief Indexes a structure * * Finds structures of a structure array given a start, stride, and edge for * each dimension. The structures are placed in a new structure array. If * copy_fields is non-zero, the indexed structures are copied and should be * freed, but if copy_fields is zero, the indexed structures are pointers to * the original, but should still be freed since the mem_conserve flag is set * so that the structures are not freed. * MAT File version must be 5. * @ingroup MAT * @param matvar Structure matlab variable * @param start vector of length rank with 0-relative starting coordinates for * each diemnsion. * @param stride vector of length rank with strides for each diemnsion. * @param edge vector of length rank with the number of elements to read in * each diemnsion. * @param copy_fields 1 to copy the fields, 0 to just set pointers to them. * If 0 is used, the fields should not be freed themselves. * @returns A new structure with fields indexed from matvar. */ matvar_t * Mat_VarGetStructs(matvar_t *matvar,int *start,int *stride,int *edge, int copy_fields) { int i, j, N, I = 0; int inc[10] = {0,}, cnt[10] = {0,}, dimp[10] = {0,}; int nfields, field; matvar_t **fields, *struct_slab; if ( (matvar == NULL) || (start == NULL) || (stride == NULL) || (edge == NULL) ) { return NULL; } else if ( matvar->rank > 10 ) { return NULL; } else if ( matvar->class_type != MAT_C_STRUCT ) { return NULL; } struct_slab = Mat_VarDuplicate(matvar,0); if ( !copy_fields ) struct_slab->mem_conserve = 1; nfields = matvar->nbytes / matvar->data_size; for ( i = 0; i < matvar->rank; i++ ) nfields = nfields / matvar->dims[i]; inc[0] = stride[0]-1; dimp[0] = matvar->dims[0]; N = edge[0]; I = start[0]*nfields; for ( i = 1; i < matvar->rank; i++ ) { inc[i] = stride[i]-1; dimp[i] = matvar->dims[i-1]; for ( j = i ; j--; ) { inc[i] *= matvar->dims[j]*nfields; dimp[i] *= matvar->dims[j+1]; } N *= edge[i]; if ( start[i] > 0 ) I += start[i]*dimp[i-1]*nfields; } struct_slab->nbytes = N*nfields*sizeof(matvar_t *); struct_slab->data = malloc(struct_slab->nbytes); if ( struct_slab->data == NULL ) { Mat_VarFree(struct_slab); return NULL; } fields = struct_slab->data; for ( i = 0; i < N; i+=edge[0] ) { for ( j = 0; j < edge[0]; j++ ) { for ( field = 0; field < nfields; field++ ) { if ( copy_fields ) fields[(i+j)*nfields+field] = Mat_VarDuplicate(*((matvar_t **)matvar->data + I),1); else fields[(i+j)*nfields+field] = *((matvar_t **)matvar->data + I); I++; } I += stride[0]*nfields; } for ( j = 1; j < matvar->rank-1; j++ ) { cnt[j]++; if ( (cnt[j] % edge[j]) == 0 ) { cnt[j] = 0; if ( (I % dimp[j]) != 0 ) { I += dimp[j]-(I % dimp[j]); } } else { I += matvar->dims[0]-edge[0]*stride[0]-start[0]; I += inc[j]; break; } } } return struct_slab; } /** @brief Indexes a structure * * Finds structures of a structure array given a single (linear)start, stride, * and edge. The structures are placed in a new structure array. If * copy_fields is non-zero, the indexed structures are copied and should be * freed, but if copy_fields is zero, the indexed structures are pointers to * the original, but should still be freed since the mem_conserve flag is set * so that the structures are not freed. * MAT File version must be 5. * @ingroup MAT * @param matvar Structure matlab variable * @param start starting index * @param stride stride * @param edge Number of structures to get * @param copy_fields 1 to copy the fields, 0 to just set pointers to them. * If 0 is used, the fields should not be freed themselves. * @returns A new structure with fields indexed from matvar */ matvar_t * Mat_VarGetStructsLinear(matvar_t *matvar,int start,int stride,int edge, int copy_fields) { int i, I = 0, field, nfields; matvar_t *struct_slab, **fields; /* FIXME: Check allocations */ if ( matvar == NULL || matvar->rank > 10 ) { struct_slab = NULL; } else { struct_slab = Mat_VarDuplicate(matvar,0); if ( !copy_fields ) struct_slab->mem_conserve = 1; nfields = matvar->nbytes / matvar->data_size; for ( i = 0; i < matvar->rank; i++ ) nfields = nfields / matvar->dims[i]; struct_slab->nbytes = edge*nfields*sizeof(matvar_t *); struct_slab->data = malloc(struct_slab->nbytes); fields = struct_slab->data; for ( i = 0; i < edge; i++ ) { if ( copy_fields ) { for ( field = 0; field < nfields; field++ ) { fields[i*nfields+field] = Mat_VarDuplicate(*((matvar_t **)matvar->data+I),1); I++; } } else { for ( field = 0; field < nfields; field++ ) { fields[i+field] = *((matvar_t **)matvar->data + I); I++; } } I += stride; } } return struct_slab; } /** @brief Prints the variable information * * Prints to stdout the values of the @ref matvar_t structure * @ingroup MAT * @param matvar Pointer to the matvar_t structure * @param printdata set to 1 if the Variables data should be printed, else 0 */ void Mat_VarPrint( matvar_t *matvar, int printdata ) { if ( matvar == NULL || matvar->fp == NULL ) return; else if ( matvar->fp->version != MAT_FT_MAT4 ) Mat_VarPrint5(matvar,printdata); else if ( matvar->fp->version == MAT_FT_MAT4 ) Mat_VarPrint4(matvar,printdata); return; } /** @brief Reads MAT variable data from a file * * Reads data from a MAT variable. The variable must have been read by * Mat_VarReadInfo. * @ingroup MAT * @param mat MAT file to read data from * @param matvar MAT variable information * @param data pointer to store data in (must be pre-allocated) * @param start array of starting indeces * @param stride stride of data * @param edge array specifying the number to read in each direction * @retval 0 on success */ int Mat_VarReadData(mat_t *mat,matvar_t *matvar,void *data, int *start,int *stride,int *edge) { int err = 0; if ( mat->version != MAT_FT_MAT4 ) err = ReadData5(mat,matvar,data,start,stride,edge); else err = ReadData4(mat,matvar,data,start,stride,edge); return err; } /** @brief Reads all the data for a matlab variable * * Allocates memory for an reads the data for a given matlab variable. * @ingroup MAT * @param mat Matlab MAT file structure pointer * @param matvar Variable whose data is to be read * @returns non-zero on error */ int Mat_VarReadDataAll(mat_t *mat,matvar_t *matvar) { int err = 0; if ( (mat == NULL) || (matvar == NULL) ) err = 1; else ReadData(mat,matvar); return err; } /** @brief Reads MAT variable data from a file * * Reads data from a MAT variable using a linear indexingmode. The variable * must have been read by Mat_VarReadInfo. * @ingroup MAT * @param mat MAT file to read data from * @param matvar MAT variable information * @param data pointer to store data in (must be pre-allocated) * @param start starting index * @param stride stride of data * @param edge number of elements to read * @retval 0 on success */ int Mat_VarReadDataLinear(mat_t *mat,matvar_t *matvar,void *data,int start, int stride,int edge) { int err = 0, nmemb = 1, i, data_type; mat_int32_t tag[2]; if ( mat->version == MAT_FT_MAT4 ) return -1; fseek(mat->fp,matvar->datapos,SEEK_SET); if ( matvar->compression == COMPRESSION_NONE ) { fread(tag,4,2,mat->fp); if ( mat->byteswap ) { Mat_int32Swap(tag); Mat_int32Swap(tag+1); } data_type = tag[0] & 0x000000ff; if ( tag[0] & 0xffff0000 ) { /* Data is packed in the tag */ fseek(mat->fp,-4,SEEK_CUR); } #if defined(HAVE_ZLIB) } else if ( matvar->compression == COMPRESSION_ZLIB ) { matvar->z->avail_in = 0; InflateDataType(mat,matvar,tag); if ( mat->byteswap ) { Mat_int32Swap(tag); Mat_int32Swap(tag+1); } data_type = tag[0] & 0x000000ff; if ( !(tag[0] & 0xffff0000) ) {/* Data is NOT packed in the tag */ InflateSkip(mat,matvar->z,4); } #endif } for ( i = 0; i < matvar->rank; i++ ) nmemb *= matvar->dims[i]; if ( stride*(edge-1)+start+1 > nmemb ) { err = 1; } else { stride--; switch(matvar->class_type) { case MAT_C_DOUBLE: matvar->data_type = MAT_T_DOUBLE; matvar->data_size = sizeof(double); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); fseek(mat->fp,start,SEEK_CUR); for ( i = 0; i < edge; i++ ) { ReadDoubleData(mat,(double*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedDoubleData(mat,&z_copy,(double*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_SINGLE: matvar->data_type = MAT_T_SINGLE; matvar->data_size = sizeof(float); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadSingleData(mat,(float*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedSingleData(mat,&z_copy,(float*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; #ifdef HAVE_MAT_INT64_T case MAT_C_INT64: matvar->data_type = MAT_T_INT64; matvar->data_size = sizeof(mat_int64_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt64Data(mat,(mat_int64_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt64Data(mat,&z_copy,(mat_int64_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; #endif /* HAVE_MAT_INT64_T */ #ifdef HAVE_MAT_UINT64_T case MAT_C_UINT64: matvar->data_type = MAT_T_UINT64; matvar->data_size = sizeof(mat_uint64_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt64Data(mat,(mat_int64_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt64Data(mat,&z_copy,(mat_int64_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; #endif /* HAVE_MAT_UINT64_T */ case MAT_C_INT32: matvar->data_type = MAT_T_INT32; matvar->data_size = sizeof(mat_int32_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt32Data(mat,(mat_int32_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt32Data(mat,&z_copy,(mat_int32_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_UINT32: matvar->data_type = MAT_T_UINT32; matvar->data_size = sizeof(mat_uint32_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt32Data(mat,(mat_int32_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt32Data(mat,&z_copy,(mat_int32_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_INT16: matvar->data_type = MAT_T_INT16; matvar->data_size = sizeof(mat_int16_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt16Data(mat,(mat_int16_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt16Data(mat,&z_copy,(mat_int16_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_UINT16: matvar->data_type = MAT_T_UINT16; matvar->data_size = sizeof(mat_uint16_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt16Data(mat,(mat_int16_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt16Data(mat,&z_copy,(mat_int16_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_INT8: matvar->data_type = MAT_T_INT8; matvar->data_size = sizeof(mat_int8_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt8Data(mat,(mat_int8_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt8Data(mat,&z_copy,(mat_int8_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; case MAT_C_UINT8: matvar->data_type = MAT_T_UINT8; matvar->data_size = sizeof(mat_uint8_t); if ( matvar->compression == COMPRESSION_NONE ) { stride *= Mat_SizeOf(data_type); for ( i = 0; i < edge; i++ ) { ReadInt8Data(mat,(mat_int8_t*)data+i,data_type,1); fseek(mat->fp,stride,SEEK_CUR); } #if defined(HAVE_ZLIB) } else { z_stream z_copy; err = inflateCopy(&z_copy,matvar->z); InflateSkipData(mat,&z_copy,data_type,start); for ( i = 0; i < edge; i++ ) { ReadCompressedInt8Data(mat,&z_copy,(mat_int8_t*)data+i, data_type,1); InflateSkipData(mat,&z_copy,data_type,stride); } inflateEnd(&z_copy); #endif } break; } } return err; } /** @brief Reads the information of the next variable in a MAT file * * Reads the next variable's information (class,flags-complex/global/logical, * rank,dimensions, name, etc) from the Matlab MAT file. After reading, the MAT * file is positioned past the current variable. * @ingroup MAT * @param mat Pointer to the MAT file * @return Pointer to the @ref matvar_t structure containing the MAT * variable information */ matvar_t * Mat_VarReadNextInfo( mat_t *mat ) { if( mat == NULL ) return NULL; else if ( mat->version == 0x0100 ) return Mat_VarReadNextInfo5(mat); else return Mat_VarReadNextInfo4(mat); return NULL; } /** @brief Reads the information of a variable with the given name from a MAT file * * Reads the named variable (or the next variable if name is NULL) information * (class,flags-complex/global/logical,rank,dimensions,and name) from the * Matlab MAT file * @ingroup MAT * @param mat Pointer to the MAT file * @param name Name of the variable to read * @return Pointer to the @ref matvar_t structure containing the MAT * variable information */ matvar_t * Mat_VarReadInfo( mat_t *mat, char *name ) { long fpos; matvar_t *matvar = NULL; if ( (mat == NULL) || (name == NULL) ) return NULL; fpos = ftell(mat->fp); fseek(mat->fp,mat->bof,SEEK_SET); do { #if 0 err = fread(&data_type,4,1,mat->fp); if ( !err ) return NULL; err = fread(&nBytes,4,1,mat->fp); if ( mat->byteswap ) { Mat_int32Swap(&data_type); Mat_int32Swap(&nBytes); } curpos = ftell(mat->fp); fseek(mat->fp,-8,SEEK_CUR); #endif matvar = Mat_VarReadNextInfo(mat); if ( matvar != NULL ) { if ( !matvar->name ) { Mat_VarFree(matvar); matvar = NULL; } else if ( strcmp(matvar->name,name) ) { Mat_VarFree(matvar); matvar = NULL; } } else { Mat_Critical("An error occurred in reading the MAT file"); break; } #if 0 fseek(mat->fp,curpos+nBytes,SEEK_SET); #endif } while ( !matvar && !feof(mat->fp) ); fseek(mat->fp,fpos,SEEK_SET); return matvar; } /** @brief Reads the variable with the given name from a MAT file * * Reads the next variable in the Matlab MAT file * @ingroup MAT * @param mat Pointer to the MAT file * @param name Name of the variable to read * @return Pointer to the @ref matvar_t structure containing the MAT * variable information */ matvar_t * Mat_VarRead( mat_t *mat, char *name ) { long fpos; matvar_t *matvar = NULL;; if ( (mat == NULL) || (name == NULL) ) return NULL; fpos = ftell(mat->fp); matvar = Mat_VarReadInfo(mat,name); if ( matvar ) ReadData(mat,matvar); fseek(mat->fp,fpos,SEEK_SET); return matvar; } /** @brief Reads the next variable in a MAT file * * Reads the next variable in the Matlab MAT file * @ingroup MAT * @param mat Pointer to the MAT file * @return Pointer to the @ref matvar_t structure containing the MAT * variable information */ matvar_t * Mat_VarReadNext( mat_t *mat ) { long fpos; matvar_t *matvar = NULL; if ( feof(mat->fp) ) return NULL; /* Read position so we can reset the file position if an error occurs */ fpos = ftell(mat->fp); matvar = Mat_VarReadNextInfo(mat); if ( matvar != NULL) ReadData(mat,matvar); else fseek(mat->fp,fpos,SEEK_SET); return matvar; } /** @brief Writes the given MAT variable to a MAT file * * Writes the MAT variable information stored in matvar to the given MAT file. * The variable will be written to the end of the file. * @ingroup MAT * @param mat MAT file to write to * @param matvar MAT variable information to write * @retval 0 on success */ int Mat_VarWriteInfo(mat_t *mat, matvar_t *matvar ) { if ( mat == NULL || matvar == NULL || mat->fp == NULL ) return -1; else if ( mat->version != MAT_FT_MAT4 ) WriteInfo5(mat,matvar); #if 0 else if ( mat->version == MAT_FT_MAT4 ) WriteInfo4(mat,matvar); #endif return 0; } /** @brief Writes the given data to the MAT variable * * Writes data to a MAT variable. The variable must have previously been * written with Mat_VarWriteInfo. * @ingroup MAT * @param mat MAT file to write to * @param matvar MAT variable information to write * @param data pointer to the data to write * @param start array of starting indeces * @param stride stride of data * @param edge array specifying the number to read in each direction * @retval 0 on success */ int Mat_VarWriteData(mat_t *mat,matvar_t *matvar,void *data, int *start,int *stride,int *edge) { int err = 0, k, N = 1; fseek(mat->fp,matvar->datapos+8,SEEK_SET); if ( mat == NULL || matvar == NULL || data == NULL ) { err = -1; } else if ( start == NULL && stride == NULL && edge == NULL ) { for ( k = 0; k < matvar->rank; k++ ) N *= matvar->dims[k]; if ( matvar->compression == COMPRESSION_NONE ) WriteData(mat,data,N,matvar->data_type); #if 0 else if ( matvar->compression == COMPRESSION_ZLIB ) { WriteCompressedData(mat,matvar->z,data,N,matvar->data_type); (void)deflateEnd(matvar->z); free(matvar->z); matvar->z = NULL; } #endif } else if ( matvar->rank == 2 ) { if ( stride[0]*(edge[0]-1)+start[0]+1 > matvar->dims[0] ) { err = 1; } else if ( stride[1]*(edge[1]-1)+start[1]+1 > matvar->dims[1] ) { err = 1; } else { switch ( matvar->class_type ) { case MAT_C_DOUBLE: case MAT_C_SINGLE: case MAT_C_INT64: case MAT_C_UINT64: case MAT_C_INT32: case MAT_C_UINT32: case MAT_C_INT16: case MAT_C_UINT16: case MAT_C_INT8: case MAT_C_UINT8: WriteDataSlab2(mat,data,matvar->data_type,matvar->dims, start,stride,edge); break; case MAT_C_CHAR: WriteCharDataSlab2(mat,data,matvar->data_type,matvar->dims, start,stride,edge); break; } } } return err; } /** @brief Writes the given MAT variable to a MAT file * * Writes the MAT variable information stored in matvar to the given MAT file. * The variable will be written to the end of the file. * @ingroup MAT * @param mat MAT file to write to * @param matvar MAT variable information to write * @param compress Whether or not to compress the data * (Only valid for version 5 MAT files and variables with numeric data) * @retval 0 on success */ int Mat_VarWrite( mat_t *mat, matvar_t *matvar, int compress ) { if ( mat == NULL || matvar == NULL ) return -1; else if ( mat->version != MAT_FT_MAT4 ) Write5(mat,matvar,compress); return 0; }