Commit message: Fix memory leak

As reported by https://github.com/tbeu/matio/issues/131
CVE: CVE-2019-20052
CWE: CWE-401
Vulnerability description: A memory leak was discovered in Mat_VarCalloc in mat.c in matio 1.5.17 because SafeMulDims does not consider the rank==0 case.

Project: matio
File: mat.c

Mat_VarCalloc(void)
{
    matvar_t *matvar;

    matvar = (matvar_t*)malloc(sizeof(*matvar));

    if ( NULL != matvar ) {
        matvar->nbytes       = 0;
        matvar->rank         = 0;
        matvar->data_type    = MAT_T_UNKNOWN;
        matvar->data_size    = 0;
        matvar->class_type   = MAT_C_EMPTY;
        matvar->isComplex    = 0;
        matvar->isGlobal     = 0;
        matvar->isLogical    = 0;
        matvar->dims         = NULL;
        matvar->name         = NULL;
        matvar->data         = NULL;
        matvar->mem_conserve = 0;
        matvar->compression  = MAT_COMPRESSION_NONE;
        matvar->internal     = (struct matvar_internal*)malloc(sizeof(*matvar->internal));
        if ( NULL == matvar->internal ) {
            free(matvar);
            matvar = NULL;
        } else {
#if defined(MAT73) && MAT73
            matvar->internal->hdf5_name  = NULL;
            matvar->internal->hdf5_ref   =  0;
            matvar->internal->id         = -1;
#endif
            matvar->internal->datapos    = 0;
            matvar->internal->num_fields = 0;
            matvar->internal->fieldnames = NULL;
#if HAVE_ZLIB
            matvar->internal->z          = NULL;
            matvar->internal->data       = NULL;
#endif
        }
    }

    return matvar;
}

Project: matio
File: mat.c

int SafeMul(size_t* res, size_t a, size_t b)
{
    if ( !psnip_safe_size_mul(res, a, b) ) {
        *res = 0;
        return 1;
    }

    return 0;
}

Project: matio
File: mat.c

Mat_VarFree(matvar_t *matvar)
{
    size_t nelems = 0;

    if ( NULL == matvar )
        return;
    if ( NULL != matvar->dims ) {
        nelems = 1;
        SafeMulDims(matvar, &nelems);
        free(matvar->dims);
    }
    if ( NULL != matvar->data ) {
        switch (matvar->class_type ) {
            case MAT_C_STRUCT:
                if ( !matvar->mem_conserve ) {
                    matvar_t **fields = (matvar_t**)matvar->data;
                    size_t nelems_x_nfields, i;
                    SafeMul(&nelems_x_nfields, nelems, matvar->internal->num_fields);
                    for ( i = 0; i < nelems_x_nfields; i++ )
                        Mat_VarFree(fields[i]);

                    free(matvar->data);
                }
                break;
            case MAT_C_CELL:
                if ( !matvar->mem_conserve ) {
                    matvar_t **cells = (matvar_t**)matvar->data;
                    size_t i;
                    for ( i = 0; i < nelems; i++ )
                        Mat_VarFree(cells[i]);

                    free(matvar->data);
                }
                break;
            case MAT_C_SPARSE:
                if ( !matvar->mem_conserve ) {
                    mat_sparse_t *sparse;
                    sparse = (mat_sparse_t*)matvar->data;
                    if ( sparse->ir != NULL )
                        free(sparse->ir);
                    if ( sparse->jc != NULL )
                        free(sparse->jc);
                    if ( matvar->isComplex && NULL != sparse->data ) {
                        ComplexFree((mat_complex_split_t*)sparse->data);
                    } else if ( sparse->data != NULL ) {
                        free(sparse->data);
                    }
                    free(sparse);
                }
                break;
            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:
            case MAT_C_CHAR:
                if ( !matvar->mem_conserve ) {
                    if ( matvar->isComplex ) {
                        ComplexFree((mat_complex_split_t*)matvar->data);
                    } else {
                        free(matvar->data);
                    }
                }
                break;
            case MAT_C_FUNCTION:
                if ( !matvar->mem_conserve ) {
                    free(matvar->data);
                }
                break;
            case MAT_C_EMPTY:
            case MAT_C_OBJECT:
            case MAT_C_OPAQUE:
                break;
        }
    }

    if ( NULL != matvar->internal ) {
#if HAVE_ZLIB
        if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
            inflateEnd(matvar->internal->z);
            free(matvar->internal->z);
            if ( matvar->class_type == MAT_C_SPARSE && NULL != matvar->internal->data ) {
                mat_sparse_t *sparse;
                sparse = (mat_sparse_t*)matvar->internal->data;
                if ( sparse->ir != NULL )
                    free(sparse->ir);
                if ( sparse->jc != NULL )
                    free(sparse->jc);
                if ( matvar->isComplex && NULL != sparse->data ) {
                    ComplexFree((mat_complex_split_t*)sparse->data);
                } else if ( sparse->data != NULL ) {
                    free(sparse->data);
                }
                free(sparse);
            }
            else if ( matvar->isComplex && NULL != matvar->internal->data ) {
                ComplexFree((mat_complex_split_t*)matvar->internal->data);
            } else if ( NULL != matvar->internal->data ) {
                free(matvar->internal->data);
            }
        }
#endif
#if defined(MAT73) && MAT73
        if ( -1 < matvar->internal->id ) {
            switch ( H5Iget_type(matvar->internal->id) ) {
                case H5I_GROUP:
                    H5Gclose(matvar->internal->id);
                    matvar->internal->id = -1;
                    break;
                case H5I_DATASET:
                    H5Dclose(matvar->internal->id);
                    matvar->internal->id = -1;
                    break;
                default:
                    break;
            }
        }
        if ( 0 < matvar->internal->hdf5_ref ) {
            switch ( H5Iget_type(matvar->internal->id) ) {
                case H5I_GROUP:
                    H5Gclose(matvar->internal->id);
                    matvar->internal->hdf5_ref = -1;
                    break;
                case H5I_DATASET:
                    H5Dclose(matvar->internal->id);
                    matvar->internal->hdf5_ref = -1;
                    break;
                default:
                    break;
            }
        }
        if ( NULL != matvar->internal->hdf5_name ) {
            free(matvar->internal->hdf5_name);
            matvar->internal->hdf5_name = NULL;
        }
#endif
        if ( NULL != matvar->internal->fieldnames &&
            matvar->internal->num_fields > 0 ) {
            size_t i;
            for ( i = 0; i < matvar->internal->num_fields; i++ ) {
                if ( NULL != matvar->internal->fieldnames[i] )
                    free(matvar->internal->fieldnames[i]);
            }
            free(matvar->internal->fieldnames);
        }
        free(matvar->internal);
        matvar->internal = NULL;
    }
    if ( NULL != matvar->name )
        free(matvar->name);
    free(matvar);
}

Project: matio
File: mat.c

ClassType2DataType(enum matio_classes class_type)
{
    switch ( class_type ) {
        case MAT_C_DOUBLE:
            return MAT_T_DOUBLE;
        case MAT_C_SINGLE:
            return MAT_T_SINGLE;
#ifdef HAVE_MAT_INT64_T
        case MAT_C_INT64:
            return MAT_T_INT64;
#endif
#ifdef HAVE_MAT_UINT64_T
        case MAT_C_UINT64:
            return MAT_T_UINT64;
#endif
        case MAT_C_INT32:
            return MAT_T_INT32;
        case MAT_C_UINT32:
            return MAT_T_UINT32;
        case MAT_C_INT16:
            return MAT_T_INT16;
        case MAT_C_UINT16:
            return MAT_T_UINT16;
        case MAT_C_INT8:
            return MAT_T_INT8;
        case MAT_C_CHAR:
            return MAT_T_UINT8;
        case MAT_C_UINT8:
            return MAT_T_UINT8;
        case MAT_C_CELL:
            return MAT_T_CELL;
        case MAT_C_STRUCT:
            return MAT_T_STRUCT;
        default:
            return MAT_T_UNKNOWN;
    }
}

Project: matio
File: mat.c

mat_copy(const char* src, const char* dst)
{
    size_t len;
    char buf[BUFSIZ] = {'\0'};
    FILE* in = NULL;
    FILE* out = NULL;

#if defined(_WIN32) && defined(_MSC_VER)
    {
        wchar_t* wname = utf82u(src);
        if ( NULL != wname ) {
            in = _wfopen(wname, L"rb");
            free(wname);
        }
    }
#else
    in = fopen(src, "rb");
#endif
    if ( in == NULL ) {
        Mat_Critical("Cannot open file \"%s\" for reading.", src);
        return -1;
    }

#if defined(_WIN32) && defined(_MSC_VER)
    {
        wchar_t* wname = utf82u(dst);
        if ( NULL != wname ) {
            out = _wfopen(wname, L"wb");
            free(wname);
        }
    }
#else
    out = fopen(dst, "wb");
#endif
    if ( out == NULL ) {
        fclose(in);
        Mat_Critical("Cannot open file \"%s\" for writing.", dst);
        return -1;
    }

    while ( (len = fread(buf, sizeof(char), BUFSIZ, in)) > 0 ) {
        if ( len != fwrite(buf, sizeof(char), len, out) ) {
            fclose(in);
            fclose(out);
            Mat_Critical("Error writing to file \"%s\".", dst);
            return -1;
        }
    }
    fclose(in);
    fclose(out);
    return 0;
}

Project: matio
File: mat.c

Mat_CalcSingleSubscript(int rank,int *dims,int *subs)
{
    int index = 0, i, j, err = 0;

    for ( i = 0; i < rank; i++ ) {
        int 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;
}

Project: matio
File: mat.c

ComplexFree(mat_complex_split_t* complex_data)
{
    free(complex_data->Re);
    free(complex_data->Im);
    free(complex_data);
}

Project: matio
File: mat.c

Mat_VarReadData(mat_t *mat,matvar_t *matvar,void *data,
      int *start,int *stride,int *edge)
{
    int err = 0;

    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:
            break;
        default:
            return -1;
    }

    switch ( mat->version ) {
        case MAT_FT_MAT5:
            err = Mat_VarReadData5(mat,matvar,data,start,stride,edge);
            break;
        case MAT_FT_MAT73:
#if defined(MAT73) && MAT73
            err = Mat_VarReadData73(mat,matvar,data,start,stride,edge);
#else
            err = 1;
#endif
            break;
        case MAT_FT_MAT4:
            err = Mat_VarReadData4(mat,matvar,data,start,stride,edge);
            break;
        default:
            err = 2;
            break;
    }

    return err;
}

Project: matio
File: mat.c

Mat_VarRead( mat_t *mat, const char *name )
{
    matvar_t *matvar = NULL;

    if ( (mat == NULL) || (name == NULL) )
        return NULL;

    if ( MAT_FT_MAT73 != mat->version ) {
        long fpos = ftell((FILE*)mat->fp);
        if ( fpos == -1L ) {
            Mat_Critical("Couldn't determine file position");
            return NULL;
        }
        matvar = Mat_VarReadInfo(mat,name);
        if ( matvar ) {
            const int err = ReadData(mat,matvar);
            if ( err ) {
                Mat_VarFree(matvar);
                matvar = NULL;
            }
        }
        (void)fseek((FILE*)mat->fp,fpos,SEEK_SET);
    } else {
        size_t fpos = mat->next_index;
        mat->next_index = 0;
        matvar = Mat_VarReadInfo(mat,name);
        if ( matvar ) {
            const int err = ReadData(mat,matvar);
            if ( err ) {
                Mat_VarFree(matvar);
                matvar = NULL;
            }
        }
        mat->next_index = fpos;
    }

    return matvar;
}

Project: matio
File: mat.c

Mat_GetVersion(mat_t *mat)
{
    enum mat_ft file_type = MAT_FT_UNDEFINED;
    if ( NULL != mat )
        file_type = (enum mat_ft)mat->version;
    return file_type;
}

Project: matio
File: mat.c

Mat_VarDuplicate(const matvar_t *in, int opt)
{
    matvar_t *out;
    size_t i;

    out = Mat_VarCalloc();
    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;

    if ( NULL != in->name ) {
        size_t len = strlen(in->name) + 1;
        out->name = (char*)malloc(len);
        if ( NULL != out->name )
            memcpy(out->name,in->name,len);
    }

    out->dims = (size_t*)malloc(in->rank*sizeof(*out->dims));
    if ( out->dims != NULL )
        memcpy(out->dims,in->dims,in->rank*sizeof(*out->dims));

    if ( NULL != in->internal ) {
#if defined(MAT73) && MAT73
        if ( NULL != in->internal->hdf5_name )
            out->internal->hdf5_name = strdup(in->internal->hdf5_name);

        out->internal->hdf5_ref = in->internal->hdf5_ref;
        out->internal->id       = in->internal->id;
#endif
        out->internal->datapos  = in->internal->datapos;
#if HAVE_ZLIB
        out->internal->z        = NULL;
        out->internal->data     = NULL;
#endif
        out->internal->num_fields = in->internal->num_fields;
        if ( NULL != in->internal->fieldnames && in->internal->num_fields > 0 ) {
            out->internal->fieldnames = (char**)calloc(in->internal->num_fields,
                                               sizeof(*in->internal->fieldnames));
            for ( i = 0; i < in->internal->num_fields; i++ ) {
                if ( NULL != in->internal->fieldnames[i] )
                    out->internal->fieldnames[i] =
                        strdup(in->internal->fieldnames[i]);
            }
        }

#if HAVE_ZLIB
        if ( (in->internal->z != NULL) && (NULL != (out->internal->z = (z_streamp)malloc(sizeof(z_stream)))) )
            inflateCopy(out->internal->z,in->internal->z);
        if ( in->internal->data != NULL ) {
            if ( in->class_type == MAT_C_SPARSE ) {
                out->internal->data = malloc(sizeof(mat_sparse_t));
                if ( out->internal->data != NULL ) {
                    mat_sparse_t *out_sparse = (mat_sparse_t*)out->internal->data;
                    mat_sparse_t *in_sparse  = (mat_sparse_t*)in->internal->data;
                    out_sparse->nzmax = in_sparse->nzmax;
                    out_sparse->nir = in_sparse->nir;
                    out_sparse->ir = (mat_uint32_t*)malloc(in_sparse->nir*sizeof(*out_sparse->ir));
                    if ( out_sparse->ir != NULL )
                        memcpy(out_sparse->ir, in_sparse->ir, in_sparse->nir*sizeof(*out_sparse->ir));
                    out_sparse->njc = in_sparse->njc;
                    out_sparse->jc = (mat_uint32_t*)malloc(in_sparse->njc*sizeof(*out_sparse->jc));
                    if ( out_sparse->jc != NULL )
                        memcpy(out_sparse->jc, in_sparse->jc, in_sparse->njc*sizeof(*out_sparse->jc));
                    out_sparse->ndata = in_sparse->ndata;
                    if ( out->isComplex && NULL != in_sparse->data ) {
                        out_sparse->data = malloc(sizeof(mat_complex_split_t));
                        if ( out_sparse->data != NULL ) {
                            mat_complex_split_t *out_data = (mat_complex_split_t*)out_sparse->data;
                            mat_complex_split_t *in_data  = (mat_complex_split_t*)in_sparse->data;
                            out_data->Re = malloc(
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                            if ( NULL != out_data->Re )
                                memcpy(out_data->Re,in_data->Re,
                                    in_sparse->ndata*Mat_SizeOf(in->data_type));
                            out_data->Im = malloc(
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                            if ( NULL != out_data->Im )
                                memcpy(out_data->Im,in_data->Im,
                                    in_sparse->ndata*Mat_SizeOf(in->data_type));
                        }
                    } else if ( in_sparse->data != NULL ) {
                        out_sparse->data = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                        if ( NULL != out_sparse->data )
                            memcpy(out_sparse->data, in_sparse->data,
                                in_sparse->ndata*Mat_SizeOf(in->data_type));
                    }
                }
            } else if ( out->isComplex ) {
                out->internal->data = malloc(sizeof(mat_complex_split_t));
                if ( out->internal->data != NULL ) {
                    mat_complex_split_t *out_data = (mat_complex_split_t*)out->internal->data;
                    mat_complex_split_t *in_data  = (mat_complex_split_t*)in->internal->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 if ( NULL != (out->internal->data = malloc(in->nbytes)) ) {
                memcpy(out->internal->data, in->internal->data, in->nbytes);
            }
        }
#endif
    } else {
        free(out->internal);
        out->internal = NULL;
    }

    if ( !opt ) {
        out->data = in->data;
    } else if ( (in->data != NULL) && (in->class_type == MAT_C_STRUCT) ) {
        out->data = malloc(in->nbytes);
        if ( out->data != NULL && in->data_size > 0 ) {
            size_t nfields = in->nbytes / in->data_size;
            matvar_t **infields  = (matvar_t **)in->data;
            matvar_t **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) ) {
        out->data = malloc(in->nbytes);
        if ( out->data != NULL && in->data_size > 0 ) {
            size_t nelems = in->nbytes / in->data_size;
            matvar_t **incells  = (matvar_t **)in->data;
            matvar_t **outcells = (matvar_t **)out->data;
            for ( i = 0; i < nelems; i++ ) {
                outcells[i] = Mat_VarDuplicate(incells[i],opt);
            }
        }
    } else if ( (in->data != NULL) && (in->class_type == MAT_C_SPARSE) ) {
        out->data = malloc(sizeof(mat_sparse_t));
        if ( out->data != NULL ) {
            mat_sparse_t *out_sparse = (mat_sparse_t*)out->data;
            mat_sparse_t *in_sparse  = (mat_sparse_t*)in->data;
            out_sparse->nzmax = in_sparse->nzmax;
            out_sparse->nir = in_sparse->nir;
            out_sparse->ir = (mat_uint32_t*)malloc(in_sparse->nir*sizeof(*out_sparse->ir));
            if ( out_sparse->ir != NULL )
                memcpy(out_sparse->ir, in_sparse->ir, in_sparse->nir*sizeof(*out_sparse->ir));
            out_sparse->njc = in_sparse->njc;
            out_sparse->jc = (mat_uint32_t*)malloc(in_sparse->njc*sizeof(*out_sparse->jc));
            if ( out_sparse->jc != NULL )
                memcpy(out_sparse->jc, in_sparse->jc, in_sparse->njc*sizeof(*out_sparse->jc));
            out_sparse->ndata = in_sparse->ndata;
            if ( out->isComplex && NULL != in_sparse->data ) {
                out_sparse->data = malloc(sizeof(mat_complex_split_t));
                if ( out_sparse->data != NULL ) {
                    mat_complex_split_t *out_data = (mat_complex_split_t*)out_sparse->data;
                    mat_complex_split_t *in_data  = (mat_complex_split_t*)in_sparse->data;
                    out_data->Re = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                    if ( NULL != out_data->Re )
                        memcpy(out_data->Re,in_data->Re,in_sparse->ndata*Mat_SizeOf(in->data_type));
                    out_data->Im = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                    if ( NULL != out_data->Im )
                        memcpy(out_data->Im,in_data->Im,in_sparse->ndata*Mat_SizeOf(in->data_type));
                }
            } else if ( in_sparse->data != NULL ) {
                out_sparse->data = malloc(in_sparse->ndata*Mat_SizeOf(in->data_type));
                if ( NULL != out_sparse->data )
                    memcpy(out_sparse->data, in_sparse->data, in_sparse->ndata*Mat_SizeOf(in->data_type));
            } else {
                out_sparse->data = NULL;
            }
        }
    } else if ( in->data != NULL ) {
        if ( out->isComplex ) {
            out->data = malloc(sizeof(mat_complex_split_t));
            if ( out->data != NULL ) {
                mat_complex_split_t *out_data = (mat_complex_split_t*)out->data;
                mat_complex_split_t *in_data  = (mat_complex_split_t*)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;
}

Project: matio
File: mat.c

Mat_CalcSingleSubscript2(int rank,size_t *dims,size_t *subs,size_t *index)
{
    int i, err = 0;

    for ( i = 0; i < rank; i++ ) {
        int j;
        size_t k = subs[i];
        if ( k > dims[i] ) {
            err = 1;
            Mat_Critical("Mat_CalcSingleSubscript2: index out of bounds");
            break;
        } else if ( k < 1 ) {
            err = 1;
            break;
        }
        k--;
        for ( j = i; j--; )
            k *= dims[j];
        *index += k;
    }

    return err;
}

Project: matio
File: mat.c

Mat_VarReadInfo( mat_t *mat, const char *name )
{
    matvar_t *matvar = NULL;

    if ( (mat == NULL) || (name == NULL) )
        return NULL;

    if ( mat->version == MAT_FT_MAT73 ) {
        size_t fpos = mat->next_index;
        mat->next_index = 0;
        while ( NULL == matvar && mat->next_index < mat->num_datasets ) {
            matvar = Mat_VarReadNextInfo(mat);
            if ( matvar != NULL ) {
                if ( matvar->name == NULL || 0 != strcmp(matvar->name,name) ) {
                    Mat_VarFree(matvar);
                    matvar = NULL;
                }
            } else {
                Mat_Critical("An error occurred in reading the MAT file");
                break;
            }
        }
        mat->next_index = fpos;
    } else {
        long fpos = ftell((FILE*)mat->fp);
        if ( fpos != -1L ) {
            (void)fseek((FILE*)mat->fp,mat->bof,SEEK_SET);
            do {
                matvar = Mat_VarReadNextInfo(mat);
                if ( matvar != NULL ) {
                    if ( matvar->name == NULL || 0 != strcmp(matvar->name,name) ) {
                        Mat_VarFree(matvar);
                        matvar = NULL;
                    }
                } else if ( !feof((FILE *)mat->fp) ) {
                    Mat_Critical("An error occurred in reading the MAT file");
                    break;
                }
            } while ( NULL == matvar && !feof((FILE *)mat->fp) );
            (void)fseek((FILE*)mat->fp,fpos,SEEK_SET);
        } else {
            Mat_Critical("Couldn't determine file position");
        }
    }

    return matvar;
}

Project: matio
File: mat.c

Mat_VarPrint( matvar_t *matvar, int printdata )
{
    size_t nelems = 0, i, j;
    const char *class_type_desc[18] = {"Undefined","Cell Array","Structure",
       "Object","Character Array","Sparse Array","Double Precision Array",
       "Single Precision Array", "8-bit, signed integer array",
       "8-bit, unsigned integer array","16-bit, signed integer array",
       "16-bit, unsigned integer array","32-bit, signed integer array",
       "32-bit, unsigned integer array","64-bit, signed integer array",
       "64-bit, unsigned integer array","Function","Opaque"};

    if ( matvar == NULL )
        return;
    if ( NULL != matvar->name )
        printf("      Name: %s\n", matvar->name);
    printf("      Rank: %d\n", matvar->rank);
    if ( matvar->rank <= 0 )
        return;
    if ( NULL != matvar->dims ) {
        int k;
        nelems = 1;
        SafeMulDims(matvar, &nelems);
        printf("Dimensions: %" SIZE_T_FMTSTR,matvar->dims[0]);
        for ( k = 1; k < matvar->rank; k++ ) {
            printf(" x %" SIZE_T_FMTSTR,matvar->dims[k]);
        }
        printf("\n");
    }
    printf("Class Type: %s",class_type_desc[matvar->class_type]);
    if ( matvar->isComplex )
        printf(" (complex)");
    else if ( matvar->isLogical )
        printf(" (logical)");
    printf("\n");
    if ( matvar->data_type ) {
        const char *data_type_desc[25] = {"Unknown","8-bit, signed integer",
           "8-bit, unsigned integer","16-bit, signed integer",
           "16-bit, unsigned integer","32-bit, signed integer",
           "32-bit, unsigned integer","IEEE 754 single-precision","RESERVED",
           "IEEE 754 double-precision","RESERVED","RESERVED",
           "64-bit, signed integer","64-bit, unsigned integer", "Matlab Array",
           "Compressed Data","Unicode UTF-8 Encoded Character Data",
           "Unicode UTF-16 Encoded Character Data",
           "Unicode UTF-32 Encoded Character Data","RESERVED","String","Cell Array",
           "Structure","Array","Function"};
        printf(" Data Type: %s\n", data_type_desc[matvar->data_type]);
    }

    if ( MAT_C_STRUCT == matvar->class_type ) {
        matvar_t **fields = (matvar_t **)matvar->data;
        size_t nfields = matvar->internal->num_fields;
        size_t nelems_x_nfields = 1;
        SafeMul(&nelems_x_nfields, nelems, nfields);
        if ( nelems_x_nfields > 0 ) {
            printf("Fields[%" SIZE_T_FMTSTR "] {\n", nelems_x_nfields);
            for ( i = 0; i < nelems_x_nfields; i++ ) {
                if ( NULL == fields[i] ) {
                    printf("      Name: %s\n      Rank: %d\n",
                           matvar->internal->fieldnames[i%nfields],0);
                } else {
                    Mat_VarPrint(fields[i],printdata);
                }
            }
            printf("}\n");
        } else {
            printf("Fields[%" SIZE_T_FMTSTR "] {\n", nfields);
            for ( i = 0; i < nfields; i++ )
                printf("      Name: %s\n      Rank: %d\n",
                       matvar->internal->fieldnames[i],0);
            printf("}\n");
        }
        return;
    } else if ( matvar->data == NULL || matvar->data_size < 1 ) {
        if ( printdata )
            printf("{\n}\n");
        return;
    } else if ( MAT_C_CELL == matvar->class_type ) {
        matvar_t **cells = (matvar_t **)matvar->data;
        nelems = matvar->nbytes / matvar->data_size;
        printf("{\n");
        for ( i = 0; i < nelems; i++ )
            Mat_VarPrint(cells[i],printdata);
        printf("}\n");
        return;
    } else if ( !printdata ) {
        return;
    }

    printf("{\n");

    if ( matvar->rank > 2 ) {
        printf("I can't print more than 2 dimensions\n");
    } else if ( matvar->rank == 1 && NULL != matvar->dims && matvar->dims[0] > 15 ) {
        printf("I won't print more than 15 elements in a vector\n");
    } else if ( matvar->rank == 2 && NULL != matvar->dims ) {
        switch( matvar->class_type ) {
            case MAT_C_DOUBLE:
            case MAT_C_SINGLE:
#ifdef HAVE_MAT_INT64_T
            case MAT_C_INT64:
#endif
#ifdef HAVE_MAT_UINT64_T
            case MAT_C_UINT64:
#endif
            case MAT_C_INT32:
            case MAT_C_UINT32:
            case MAT_C_INT16:
            case MAT_C_UINT16:
            case MAT_C_INT8:
            case MAT_C_UINT8:
            {
                size_t stride = Mat_SizeOf(matvar->data_type);
                if ( matvar->isComplex ) {
                    mat_complex_split_t *complex_data = (mat_complex_split_t*)matvar->data;
                    char *rp = (char*)complex_data->Re;
                    char *ip = (char*)complex_data->Im;
                    for ( i = 0; i < matvar->dims[0] && i < 15; i++ ) {
                        for ( j = 0; j < matvar->dims[1] && j < 15; j++ ) {
                            size_t idx = matvar->dims[0]*j+i;
                            Mat_PrintNumber(matvar->data_type,rp+idx*stride);
                            printf(" + ");
                            Mat_PrintNumber(matvar->data_type,ip+idx*stride);
                            printf("i ");
                        }
                        if ( j < matvar->dims[1] )
                            printf("...");
                        printf("\n");
                    }
                    if ( i < matvar->dims[0] )
                        printf(".\n.\n.\n");
               } else {
                   char *data = (char*)matvar->data;
                   for ( i = 0; i < matvar->dims[0] && i < 15; i++ ) {
                        for ( j = 0; j < matvar->dims[1] && j < 15; j++ ) {
                            size_t idx = matvar->dims[0]*j+i;
                            Mat_PrintNumber(matvar->data_type,
                                            data+idx*stride);
                            printf(" ");
                        }
                        if ( j < matvar->dims[1] )
                            printf("...");
                        printf("\n");
                    }
                    if ( i < matvar->dims[0] )
                        printf(".\n.\n.\n");
                }
                break;
            }
            case MAT_C_CHAR:
            {
                switch ( matvar->data_type ) {
                    case MAT_T_UINT16:
                    case MAT_T_UTF16:
                    {
                        const mat_uint16_t *data = (const mat_uint16_t*)matvar->data;
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
                            for ( j = 0; j < matvar->dims[1]; j++ ) {
                                const mat_uint16_t c = data[j*matvar->dims[0]+i];
#if defined VARPRINT_UTF16
                                printf("%c%c", c & 0xFF, (c>>8) & 0xFF);
#elif defined VARPRINT_UTF16_DECIMAL
                                Mat_PrintNumber(MAT_T_UINT16, &c);
                                printf(" ");
#else
                                /* Convert to UTF-8 */
                                if (c <= 0x7F) {
                                    printf("%c", c);
                                }
                                else if (c <= 0x7FF) {
                                    printf("%c%c", 0xC0 | (c>>6), 0x80 | (c & 0x3F));
                                }
                                else /* if (c <= 0xFFFF) */ {
                                    printf("%c%c%c", 0xE0 | (c>>12), 0x80 | ((c>>6) & 0x3F), 0x80 | (c & 0x3F));
                                }
#endif
                            }
                            printf("\n");
                        }
                        break;
                    }
                    default:
                    {
                        const char *data = (const char*)matvar->data;
                        for ( i = 0; i < matvar->dims[0]; i++ ) {
                            for ( j = 0; j < matvar->dims[1]; j++ )
                                printf("%c",data[j*matvar->dims[0]+i]);
                            printf("\n");
                        }
                        break;
                    }
                }
                break;
            }
            case MAT_C_SPARSE:
            {
                mat_sparse_t *sparse;
                size_t stride = Mat_SizeOf(matvar->data_type);
#if !defined(EXTENDED_SPARSE)
                if ( MAT_T_DOUBLE != matvar->data_type )
                    break;
#endif
                sparse = (mat_sparse_t*)matvar->data;
                if ( matvar->isComplex ) {
                    mat_complex_split_t *complex_data = (mat_complex_split_t*)sparse->data;
                    char *re = (char*)complex_data->Re;
                    char *im = (char*)complex_data->Im;
                    for ( i = 0; i < (size_t)sparse->njc-1; i++ ) {
                        for ( j = sparse->jc[i];
                              j < (size_t)sparse->jc[i+1] && j < (size_t)sparse->ndata; j++ ) {
                            printf("    (%d,%" SIZE_T_FMTSTR ")  ",sparse->ir[j]+1,i+1);
                            Mat_PrintNumber(matvar->data_type,re+j*stride);
                            printf(" + ");
                            Mat_PrintNumber(matvar->data_type,im+j*stride);
                            printf("i\n");
                        }
                    }
                } else {
                    char *data = (char*)sparse->data;
                    for ( i = 0; i < (size_t)sparse->njc-1; i++ ) {
                        for ( j = sparse->jc[i];
                              j < (size_t)sparse->jc[i+1] && j < (size_t)sparse->ndata; j++ ) {
                            printf("    (%d,%" SIZE_T_FMTSTR ")  ",sparse->ir[j]+1,i+1);
                            Mat_PrintNumber(matvar->data_type,data+j*stride);
                            printf("\n");
                        }
                    }
                }
                break;
            } /* case MAT_C_SPARSE: */
            default:
                break;
        } /* switch( matvar->class_type ) */
    }

    printf("}\n");

    return;
}

Project: matio
File: mat.c

Mat_GetLibraryVersion(int *major,int *minor,int *release)
{
    if ( NULL != major )
        *major = MATIO_MAJOR_VERSION;
    if ( NULL != minor )
        *minor = MATIO_MINOR_VERSION;
    if ( NULL != release )
        *release = MATIO_RELEASE_LEVEL;
}

Project: matio
File: mat.c

Mat_VarWriteInfo(mat_t *mat, matvar_t *matvar )
{
    Mat_Critical("Mat_VarWriteInfo/Mat_VarWriteData is not supported. "
        "Use %s instead!", mat->version == MAT_FT_MAT73 ?
        "Mat_VarWrite/Mat_VarWriteAppend" : "Mat_VarWrite");
    return 1;
}

Project: matio
File: mat.c

Mat_VarWriteAppend(mat_t *mat,matvar_t *matvar,enum matio_compression compress,int dim)
{
    int err;

    if ( NULL == mat || NULL == matvar )
        return -1;

    if ( NULL == mat->dir ) {
        size_t n = 0;
        (void)Mat_GetDir(mat, &n);
    }

    if ( mat->version == MAT_FT_MAT73 ) {
#if defined(MAT73) && MAT73
        int append = 0;
        {
            /* Check if MAT variable already exists in MAT file */
            size_t i;
            for ( i = 0; i < mat->num_datasets; i++ ) {
                if ( NULL != mat->dir[i] &&
                    0 == strcmp(mat->dir[i], matvar->name) ) {
                    append = 1;
                    break;
                }
            }
        }
        err = Mat_VarWriteAppend73(mat,matvar,compress,dim);
        if ( err == 0 && 0 == append ) {
            /* Update directory */
            char **dir;
            if ( NULL == mat->dir ) {
                dir = (char**)malloc(sizeof(char*));
            } else {
                dir = (char**)realloc(mat->dir,
                (mat->num_datasets + 1)*(sizeof(char*)));
            }
            if ( NULL != dir ) {
                mat->dir = dir;
                if ( NULL != matvar->name ) {
                    mat->dir[mat->num_datasets++] =
                        strdup_printf("%s", matvar->name);
                } else {
                    mat->dir[mat->num_datasets++] = NULL;
                }
            } else {
                err = 3;
                Mat_Critical("Couldn't allocate memory for the directory");
            }
        }
#else
        err = 1;
#endif
    }
    else
        err = 2;

    return err;
}

Project: matio
File: mat.c

Mat_PrintNumber(enum matio_types type, void *data)
{
    switch ( type ) {
        case MAT_T_DOUBLE:
            printf("%g",*(double*)data);
            break;
        case MAT_T_SINGLE:
            printf("%g",*(float*)data);
            break;
#ifdef HAVE_MAT_INT64_T
        case MAT_T_INT64:
#if HAVE_INTTYPES_H
            printf("%" PRIi64,*(mat_int64_t*)data);
#elif defined(_MSC_VER) && _MSC_VER >= 1200
            printf("%I64i",*(mat_int64_t*)data);
#elif defined(HAVE_LONG_LONG_INT)
            printf("%lld",(long long)(*(mat_int64_t*)data));
#else
            printf("%ld",(long)(*(mat_int64_t*)data));
#endif
            break;
#endif
#ifdef HAVE_MAT_UINT64_T
        case MAT_T_UINT64:
#if HAVE_INTTYPES_H
            printf("%" PRIu64,*(mat_uint64_t*)data);
#elif defined(_MSC_VER) && _MSC_VER >= 1200
            printf("%I64u",*(mat_uint64_t*)data);
#elif defined(HAVE_UNSIGNED_LONG_LONG_INT)
            printf("%llu",(unsigned long long)(*(mat_uint64_t*)data));
#else
            printf("%lu",(unsigned long)(*(mat_uint64_t*)data));
#endif
            break;
#endif
        case MAT_T_INT32:
            printf("%d",*(mat_int32_t*)data);
            break;
        case MAT_T_UINT32:
            printf("%u",*(mat_uint32_t*)data);
            break;
        case MAT_T_INT16:
            printf("%hd",*(mat_int16_t*)data);
            break;
        case MAT_T_UINT16:
            printf("%hu",*(mat_uint16_t*)data);
            break;
        case MAT_T_INT8:
            printf("%hhd",*(mat_int8_t*)data);
            break;
        case MAT_T_UINT8:
            printf("%hhu",*(mat_uint8_t*)data);
            break;
        default:
            break;
    }
}

Project: matio
File: mat.c

int SafeMulDims(const matvar_t *matvar, size_t* nelems)
{
    int i;

    if ( matvar->rank == 0 ) {
        *nelems = 0;
        return 0;
    }

    for ( i = 0; i < matvar->rank; i++ ) {
        if ( !psnip_safe_size_mul(nelems, *nelems, matvar->dims[i]) ) {
            *nelems = 0;
            return 1;
        }
    }

    return 0;
}

Project: matio
File: mat.c

Mat_Rewind( mat_t *mat )
{
    int err = 0;

    switch ( mat->version ) {
        case MAT_FT_MAT5:
            (void)fseek((FILE*)mat->fp,128L,SEEK_SET);
            break;
        case MAT_FT_MAT73:
            mat->next_index = 0;
            break;
        case MAT_FT_MAT4:
            (void)fseek((FILE*)mat->fp,0L,SEEK_SET);
            break;
        default:
            err = -1;
            break;
    }

    return err;
}

Project: matio
File: mat.c

Mat_VarReadDataAll(mat_t *mat,matvar_t *matvar)
{
    int err = 0;

    if ( mat == NULL || matvar == NULL )
        err = 1;
    else
        err = ReadData(mat,matvar);

    return err;
}

Project: matio
File: mat.c

Mat_Open(const char *matname,int mode)
{
    FILE *fp = NULL;
    mat_int16_t tmp, tmp2;
    mat_t *mat = NULL;
    size_t bytesread = 0;

    if ( (mode & 0x01) == MAT_ACC_RDONLY ) {
#if defined(_WIN32) && defined(_MSC_VER)
        wchar_t* wname = utf82u(matname);
        if ( NULL != wname ) {
            fp = _wfopen(wname, L"rb");
            free(wname);
        }
#else
        fp = fopen(matname, "rb");
#endif
        if ( !fp )
            return NULL;
    } else if ( (mode & 0x01) == MAT_ACC_RDWR ) {
#if defined(_WIN32) && defined(_MSC_VER)
        wchar_t* wname = utf82u(matname);
        if ( NULL != wname ) {
            fp = _wfopen(wname, L"r+b");
            free(wname);
        }
#else
        fp = fopen(matname, "r+b");
#endif
        if ( !fp ) {
            mat = Mat_CreateVer(matname,NULL,(enum mat_ft)(mode&0xfffffffe));
            return mat;
        }
    } else {
        Mat_Critical("Invalid file open mode");
        return NULL;
    }

    mat = (mat_t*)malloc(sizeof(*mat));
    if ( NULL == mat ) {
        fclose(fp);
        Mat_Critical("Couldn't allocate memory for the MAT file");
        return NULL;
    }

    mat->fp = fp;
    mat->header        = (char*)calloc(128,sizeof(char));
    if ( NULL == mat->header ) {
        free(mat);
        fclose(fp);
        Mat_Critical("Couldn't allocate memory for the MAT file header");
        return NULL;
    }
    mat->subsys_offset = (char*)calloc(8,sizeof(char));
    if ( NULL == mat->subsys_offset ) {
        free(mat->header);
        free(mat);
        fclose(fp);
        Mat_Critical("Couldn't allocate memory for the MAT file subsys offset");
        return NULL;
    }
    mat->filename      = NULL;
    mat->version       = 0;
    mat->byteswap      = 0;
    mat->num_datasets  = 0;
#if defined(MAT73) && MAT73
    mat->refs_id       = -1;
#endif
    mat->dir           = NULL;

    bytesread += fread(mat->header,1,116,fp);
    mat->header[116] = '\0';
    bytesread += fread(mat->subsys_offset,1,8,fp);
    bytesread += 2*fread(&tmp2,2,1,fp);
    bytesread += fread(&tmp,1,2,fp);

    if ( 128 == bytesread ) {
        /* v5 and v7.3 files have at least 128 byte header */
        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->version == 0x0100 || mat->version == 0x0200) &&
             -1 != mat->byteswap ) {
            mat->bof = ftell((FILE*)mat->fp);
            if ( mat->bof == -1L ) {
                free(mat->header);
                free(mat->subsys_offset);
                free(mat);
                fclose(fp);
                Mat_Critical("Couldn't determine file position");
                return NULL;
            }
            mat->next_index = 0;
        } else {
            mat->version = 0;
        }
    }

    if ( 0 == mat->version ) {
        /* Maybe a V4 MAT file */
        matvar_t *var;

        free(mat->header);
        free(mat->subsys_offset);

        mat->header        = NULL;
        mat->subsys_offset = NULL;
        mat->fp            = fp;
        mat->version       = MAT_FT_MAT4;
        mat->byteswap      = 0;
        mat->mode          = mode;
        mat->bof           = 0;
        mat->next_index    = 0;
#if defined(MAT73) && MAT73
        mat->refs_id       = -1;
#endif

        Mat_Rewind(mat);
        var = Mat_VarReadNextInfo4(mat);
        if ( NULL == var &&
             bytesread != 0 ) { /* Accept 0 bytes files as a valid V4 file */
            /* Does not seem to be a valid V4 file */
            Mat_Close(mat);
            mat = NULL;
            Mat_Critical("\"%s\" does not seem to be a valid MAT file",matname);
        } else {
            Mat_VarFree(var);
            Mat_Rewind(mat);
        }
    }

    if ( NULL == mat )
        return mat;

    mat->filename = strdup_printf("%s",matname);
    mat->mode = mode;

    if ( mat->version == 0x0200 ) {
        fclose((FILE*)mat->fp);
#if defined(MAT73) && MAT73
        mat->fp = malloc(sizeof(hid_t));

        if ( (mode & 0x01) == MAT_ACC_RDONLY )
            *(hid_t*)mat->fp=H5Fopen(matname,H5F_ACC_RDONLY,H5P_DEFAULT);
        else if ( (mode & 0x01) == MAT_ACC_RDWR ) {
            hid_t plist_ap;
            plist_ap = H5Pcreate(H5P_FILE_ACCESS);
#if H5_VERSION_GE(1,10,2)
            H5Pset_libver_bounds(plist_ap,H5F_LIBVER_EARLIEST,H5F_LIBVER_V18);
#endif
            *(hid_t*)mat->fp=H5Fopen(matname,H5F_ACC_RDWR,plist_ap);
            H5Pclose(plist_ap);
        }

        if ( -1 < *(hid_t*)mat->fp ) {
            H5G_info_t group_info;
            memset(&group_info, 0, sizeof(group_info));
            H5Gget_info(*(hid_t*)mat->fp, &group_info);
            mat->num_datasets = (size_t)group_info.nlinks;
            mat->refs_id      = -1;
        }
#else
        mat->fp = NULL;
        Mat_Close(mat);
        mat = NULL;
        Mat_Critical("No HDF5 support which is required to read the v7.3 "
                     "MAT file \"%s\"",matname);
#endif
    }

    return mat;
}

Project: matio
File: mat.c

Mat_VarReadDataLinear(mat_t *mat,matvar_t *matvar,void *data,int start,
    int stride,int edge)
{
    int err = 0;

    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:
            break;
        default:
            return -1;
    }

    switch ( mat->version ) {
        case MAT_FT_MAT5:
            err = Mat_VarReadDataLinear5(mat,matvar,data,start,stride,edge);
            break;
        case MAT_FT_MAT73:
#if defined(MAT73) && MAT73
            err = Mat_VarReadDataLinear73(mat,matvar,data,start,stride,edge);
#else
            err = 1;
#endif
            break;
        case MAT_FT_MAT4:
            err = Mat_VarReadDataLinear4(mat,matvar,data,start,stride,edge);
            break;
        default:
            err = 2;
            break;
    }

    return err;
}

Project: matio
File: mat.c

ReadData(mat_t *mat, matvar_t *matvar)
{
    if ( mat == NULL || matvar == NULL || mat->fp == NULL )
        return 1;
    else if ( mat->version == MAT_FT_MAT5 )
        return Mat_VarRead5(mat,matvar);
#if defined(MAT73) && MAT73
    else if ( mat->version == MAT_FT_MAT73 )
        return Mat_VarRead73(mat,matvar);
#endif
    else if ( mat->version == MAT_FT_MAT4 )
        return Mat_VarRead4(mat,matvar);
    return 1;
}

Project: matio
File: mat.c

Mat_GetDir(mat_t *mat, size_t *n)
{
    char ** dir = NULL;

    if ( NULL == n )
        return dir;

    if ( NULL == mat ) {
        *n = 0;
        return dir;
    }

    if ( NULL == mat->dir ) {
        matvar_t *matvar = NULL;

        if ( mat->version == MAT_FT_MAT73 ) {
            size_t i = 0;
            size_t fpos = mat->next_index;
            if ( mat->num_datasets == 0 ) {
                *n = 0;
                return dir;
            }
            mat->dir = (char**)calloc(mat->num_datasets, sizeof(char*));
            if ( NULL == mat->dir ) {
                *n = 0;
                Mat_Critical("Couldn't allocate memory for the directory");
                return dir;
            }
            mat->next_index = 0;
            while ( mat->next_index < mat->num_datasets ) {
                matvar = Mat_VarReadNextInfo(mat);
                if ( NULL != matvar ) {
                    if ( NULL != matvar->name ) {
                        mat->dir[i++] = strdup_printf("%s",
                            matvar->name);
                    }
                    Mat_VarFree(matvar);
                } else {
                    Mat_Critical("An error occurred in reading the MAT file");
                    break;
                }
            }
            mat->next_index = fpos;
            *n = i;
        } else {
            long fpos = ftell((FILE*)mat->fp);
            if ( fpos == -1L ) {
                *n = 0;
                Mat_Critical("Couldn't determine file position");
                return dir;
            }
            (void)fseek((FILE*)mat->fp,mat->bof,SEEK_SET);
            mat->num_datasets = 0;
            do {
                matvar = Mat_VarReadNextInfo(mat);
                if ( NULL != matvar ) {
                    if ( NULL != matvar->name ) {
                        if ( NULL == mat->dir ) {
                            dir = (char**)malloc(sizeof(char*));
                        } else {
                            dir = (char**)realloc(mat->dir,
                                (mat->num_datasets + 1)*(sizeof(char*)));
                        }
                        if ( NULL != dir ) {
                            mat->dir = dir;
                            mat->dir[mat->num_datasets++] =
                                strdup_printf("%s", matvar->name);
                        } else {
                            Mat_Critical("Couldn't allocate memory for the directory");
                            break;
                        }
                    }
                    Mat_VarFree(matvar);
                } else if ( !feof((FILE *)mat->fp) ) {
                    Mat_Critical("An error occurred in reading the MAT file");
                    break;
                }
            } while ( !feof((FILE *)mat->fp) );
            (void)fseek((FILE*)mat->fp,fpos,SEEK_SET);
            *n = mat->num_datasets;
        }
    } else {
        if ( mat->version == MAT_FT_MAT73 ) {
            *n = 0;
            while ( *n < mat->num_datasets && NULL != mat->dir[*n] ) {
                (*n)++;
            }
        } else {
            *n = mat->num_datasets;
        }
    }
    dir = mat->dir;
    return dir;
}

Project: matio
File: mat.c

Mat_VarWrite(mat_t *mat,matvar_t *matvar,enum matio_compression compress)
{
    int err;

    if ( NULL == mat || NULL == matvar )
        return -1;

    if ( NULL == mat->dir ) {
        size_t n = 0;
        (void)Mat_GetDir(mat, &n);
    }

    {
        /* Error if MAT variable already exists in MAT file */
        size_t i;
        for ( i = 0; i < mat->num_datasets; i++ ) {
            if ( NULL != mat->dir[i] &&
                0 == strcmp(mat->dir[i], matvar->name) ) {
                Mat_Critical("Variable %s already exists.", matvar->name);
                return 1;
            }
        }
    }

    if ( mat->version == MAT_FT_MAT5 )
        err = Mat_VarWrite5(mat,matvar,compress);
    else if ( mat->version == MAT_FT_MAT73 )
#if defined(MAT73) && MAT73
        err = Mat_VarWrite73(mat,matvar,compress);
#else
        err = 1;
#endif
    else if ( mat->version == MAT_FT_MAT4 )
        err = Mat_VarWrite4(mat,matvar);
    else
        err = 2;

    if ( err == 0 ) {
        /* Update directory */
        char **dir;
        if ( NULL == mat->dir ) {
            dir = (char**)malloc(sizeof(char*));
        } else {
            dir = (char**)realloc(mat->dir,
            (mat->num_datasets + 1)*(sizeof(char*)));
        }
        if ( NULL != dir ) {
            mat->dir = dir;
            if ( NULL != matvar->name ) {
                mat->dir[mat->num_datasets++] =
                    strdup_printf("%s", matvar->name);
            } else {
                mat->dir[mat->num_datasets++] = NULL;
            }
        } else {
            err = 3;
            Mat_Critical("Couldn't allocate memory for the directory");
        }
    }

    return err;
}

Project: matio
File: mat.c

Mat_VarCreate(const char *name,enum matio_classes class_type,
    enum matio_types data_type,int rank,size_t *dims,void *data,int opt)
{
    size_t nelems = 1, data_size;
    matvar_t *matvar = NULL;
    int j, err;

    if ( dims == NULL )
        return NULL;

    matvar = Mat_VarCalloc();
    if ( NULL == matvar )
        return NULL;

    matvar->compression = MAT_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 = (size_t*)malloc(matvar->rank*sizeof(*matvar->dims));
    for ( j = 0; j < matvar->rank; j++ ) {
        matvar->dims[j] = dims[j];
        nelems *= dims[j];
    }
    matvar->class_type = class_type;
    matvar->data_type  = data_type;
    switch ( data_type ) {
        case MAT_T_INT8:
            data_size = 1;
            break;
        case MAT_T_UINT8:
            data_size = 1;
            break;
        case MAT_T_INT16:
            data_size = 2;
            break;
        case MAT_T_UINT16:
            data_size = 2;
            break;
        case MAT_T_INT64:
            data_size = 8;
            break;
        case MAT_T_UINT64:
            data_size = 8;
            break;
        case MAT_T_INT32:
            data_size = 4;
            break;
        case MAT_T_UINT32:
            data_size = 4;
            break;
        case MAT_T_SINGLE:
            data_size = sizeof(float);
            break;
        case MAT_T_DOUBLE:
            data_size = sizeof(double);
            break;
        case MAT_T_UTF8:
            data_size = 1;
            break;
        case MAT_T_UTF16:
            data_size = 2;
            break;
        case MAT_T_UTF32:
            data_size = 4;
            break;
        case MAT_T_CELL:
            data_size = sizeof(matvar_t **);
            break;
        case MAT_T_STRUCT:
        {
            data_size = sizeof(matvar_t **);
            if ( data != NULL ) {
                matvar_t **fields = (matvar_t**)data;
                size_t nfields = 0;
                while ( fields[nfields] != NULL )
                    nfields++;
                if ( nelems )
                    nfields /= nelems;
                matvar->internal->num_fields = nfields;
                if ( nfields ) {
                    size_t i;
                    matvar->internal->fieldnames =
                        (char**)calloc(nfields,sizeof(*matvar->internal->fieldnames));
                    for ( i = 0; i < nfields; i++ )
                        matvar->internal->fieldnames[i] = strdup(fields[i]->name);
                    err = SafeMul(&nelems, nelems, nfields);
                    if ( err ) {
                        Mat_VarFree(matvar);
                        Mat_Critical("Integer multiplication overflow");
                        return NULL;
                    }
                }
            }
            break;
        }
        default:
            Mat_VarFree(matvar);
            Mat_Critical("Unrecognized data_type");
            return NULL;
    }
    if ( matvar->class_type == MAT_C_SPARSE ) {
        matvar->data_size = sizeof(mat_sparse_t);
        matvar->nbytes    = matvar->data_size;
    } else {
        matvar->data_size = data_size;
        err = SafeMul(&matvar->nbytes, nelems, matvar->data_size);
        if ( err ) {
            Mat_VarFree(matvar);
            Mat_Critical("Integer multiplication overflow");
            return NULL;
        }
    }
    if ( data == NULL ) {
        if ( MAT_C_CELL == matvar->class_type && nelems > 0 )
            matvar->data = calloc(nelems,sizeof(matvar_t*));
        else
            matvar->data = NULL;
    } else if ( opt & MAT_F_DONT_COPY_DATA ) {
        matvar->data         = data;
        matvar->mem_conserve = 1;
    } else if ( MAT_C_SPARSE == matvar->class_type ) {
        mat_sparse_t *sparse_data, *sparse_data_in;

        sparse_data_in = (mat_sparse_t*)data;
        sparse_data    = (mat_sparse_t*)malloc(sizeof(mat_sparse_t));
        if ( NULL != sparse_data ) {
            sparse_data->nzmax = sparse_data_in->nzmax;
            sparse_data->nir   = sparse_data_in->nir;
            sparse_data->njc   = sparse_data_in->njc;
            sparse_data->ndata = sparse_data_in->ndata;
            sparse_data->ir = (mat_uint32_t*)malloc(sparse_data->nir*sizeof(*sparse_data->ir));
            if ( NULL != sparse_data->ir )
                memcpy(sparse_data->ir,sparse_data_in->ir,
                       sparse_data->nir*sizeof(*sparse_data->ir));
            sparse_data->jc = (mat_uint32_t*)malloc(sparse_data->njc*sizeof(*sparse_data->jc));
            if ( NULL != sparse_data->jc )
                memcpy(sparse_data->jc,sparse_data_in->jc,
                       sparse_data->njc*sizeof(*sparse_data->jc));
            if ( matvar->isComplex ) {
                sparse_data->data = malloc(sizeof(mat_complex_split_t));
                if ( NULL != sparse_data->data ) {
                    mat_complex_split_t *complex_data,*complex_data_in;
                    complex_data     = (mat_complex_split_t*)sparse_data->data;
                    complex_data_in  = (mat_complex_split_t*)sparse_data_in->data;
                    complex_data->Re = malloc(sparse_data->ndata*data_size);
                    complex_data->Im = malloc(sparse_data->ndata*data_size);
                    if ( NULL != complex_data->Re )
                        memcpy(complex_data->Re,complex_data_in->Re,
                               sparse_data->ndata*data_size);
                    if ( NULL != complex_data->Im )
                        memcpy(complex_data->Im,complex_data_in->Im,
                               sparse_data->ndata*data_size);
                }
            } else {
                sparse_data->data = malloc(sparse_data->ndata*data_size);
                if ( NULL != sparse_data->data )
                    memcpy(sparse_data->data,sparse_data_in->data,
                           sparse_data->ndata*data_size);
            }
        }
        matvar->data = sparse_data;
    } else {
        if ( matvar->isComplex ) {
            matvar->data   = malloc(sizeof(mat_complex_split_t));
            if ( NULL != matvar->data && matvar->nbytes > 0 ) {
                mat_complex_split_t *complex_data    = (mat_complex_split_t*)matvar->data;
                mat_complex_split_t *complex_data_in = (mat_complex_split_t*)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 if ( matvar->nbytes > 0 ) {
            matvar->data   = malloc(matvar->nbytes);
            if ( NULL != matvar->data )
                memcpy(matvar->data,data,matvar->nbytes);
        }
        matvar->mem_conserve = 0;
    }

    return matvar;
}

Project: matio
File: mat.c

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;
    }
}

Project: matio
File: mat.c

Mat_VarGetSize(matvar_t *matvar)
{
    int err;
    size_t i;
    size_t bytes = 0, overhead = 0, ptr = 0;

#if defined(_WIN64) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)) || (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 8))
    /* 112 bytes cell/struct overhead for 64-bit system */
    overhead = 112;
    ptr = 8;
#elif defined(_WIN32) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)) || (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 4))
    /* 60 bytes cell/struct overhead for 32-bit system */
    overhead = 60;
    ptr = 4;
#endif

    if ( matvar->class_type == MAT_C_STRUCT ) {
        matvar_t **fields = (matvar_t**)matvar->data;
        size_t field_name_length;
        if ( NULL != fields ) {
            size_t nelems_x_nfields = matvar->internal->num_fields;
            err = SafeMulDims(matvar, &nelems_x_nfields);
            err |= SafeMul(&bytes, nelems_x_nfields, overhead);
            if ( err )
                return 0;

            for ( i = 0; i < nelems_x_nfields; i++ ) {
                if ( NULL != fields[i] ) {
                    if ( MAT_C_EMPTY != fields[i]->class_type ) {
                        err = SafeAdd(&bytes, bytes, Mat_VarGetSize(fields[i]));
                        if ( err )
                            return 0;
                    } else {
                        bytes -= overhead;
                        bytes += ptr;
                    }
                }
            }
        }
        err = SafeMul(&field_name_length, 64 /* max field name length */, matvar->internal->num_fields);
        err |= SafeAdd(&bytes, bytes, field_name_length);
        if ( err )
            return 0;
    } else if ( matvar->class_type == MAT_C_CELL ) {
        matvar_t **cells = (matvar_t**)matvar->data;
        if ( NULL != cells ) {
            size_t nelems = matvar->nbytes / matvar->data_size;
            err = SafeMul(&bytes, nelems, overhead);
            if ( err )
                return 0;

            for ( i = 0; i < nelems; i++ ) {
                if ( NULL != cells[i] ) {
                    if ( MAT_C_EMPTY != cells[i]->class_type ) {
                        err = SafeAdd(&bytes, bytes, Mat_VarGetSize(cells[i]));
                        if ( err )
                            return 0;
                    } else {
                        bytes -= overhead;
                        bytes += ptr;
                    }
                }
            }
        }
    } else if ( matvar->class_type == MAT_C_SPARSE ) {
        mat_sparse_t *sparse = (mat_sparse_t*)matvar->data;
        if ( NULL != sparse ) {
            size_t sparse_size = 0;
            err = SafeMul(&bytes, sparse->ndata, Mat_SizeOf(matvar->data_type));
            if ( err )
                return 0;

            if ( matvar->isComplex ) {
                err = SafeMul(&bytes, bytes, 2);
                if ( err )
                    return 0;
            }

#if defined(_WIN64) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 8)) || (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 8))
            /* 8 byte integers for 64-bit system (as displayed in MATLAB (x64) whos) */
            err = SafeMul(&sparse_size, sparse->nir + sparse->njc, 8);
#elif defined(_WIN32) || (defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 4)) || (defined(SIZEOF_VOID_P) && (SIZEOF_VOID_P == 4))
            /* 4 byte integers for 32-bit system (as defined by mat_sparse_t) */
            err = SafeMul(&sparse_size, sparse->nir + sparse->njc, 4);
#endif
            err |= SafeAdd(&bytes, bytes, sparse_size);
            if ( err )
                return 0;

            if ( sparse->ndata == 0 || sparse->nir == 0 || sparse->njc == 0 ) {
                err = SafeAdd(&bytes, bytes, matvar->isLogical ? 1 : 8);
                if ( err )
                    return 0;
            }
        }
    } else {
        if ( matvar->rank > 0 ) {
            bytes = Mat_SizeOfClass(matvar->class_type);
            err = SafeMulDims(matvar, &bytes);
            if ( err )
                return 0;

            if ( matvar->isComplex ) {
                err = SafeMul(&bytes, bytes, 2);
                if (err)
                    return 0;
            }
        }
    }

    return bytes;
}

Project: matio
File: mat.c

Mat_GetHeader(mat_t *mat)
{
    const char *header = NULL;
    if ( NULL != mat )
        header = mat->header;
    return header;
}

Project: matio
File: mat.c

Mat_VarDelete(mat_t *mat, const char *name)
{
    int   err = 1;
    char *tmp_name;
    char temp[7] = "XXXXXX";

    if ( NULL == mat || NULL == name )
        return err;

    if ( (tmp_name = mktemp(temp)) != NULL ) {
        enum mat_ft mat_file_ver;
        mat_t *tmp;

        switch ( mat->version ) {
            case 0x0100:
                mat_file_ver = MAT_FT_MAT5;
                break;
            case 0x0200:
                mat_file_ver = MAT_FT_MAT73;
                break;
            case 0x0010:
                mat_file_ver = MAT_FT_MAT4;
                break;
            default:
                mat_file_ver = MAT_FT_DEFAULT;
                break;
        }

        tmp = Mat_CreateVer(tmp_name,mat->header,mat_file_ver);
        if ( tmp != NULL ) {
            matvar_t *matvar;
            char **dir;
            size_t n;

            Mat_Rewind(mat);
            while ( NULL != (matvar = Mat_VarReadNext(mat)) ) {
                if ( 0 != strcmp(matvar->name,name) )
                    Mat_VarWrite(tmp,matvar,matvar->compression);
                else
                    err = 0;
                Mat_VarFree(matvar);
            }
            dir = tmp->dir; /* Keep directory for later assignment */
            tmp->dir = NULL;
            n = tmp->num_datasets;
            Mat_Close(tmp);

            if ( 0 == err ) {
                char *new_name = strdup_printf("%s",mat->filename);
#if defined(MAT73) && MAT73
                if ( mat_file_ver == MAT_FT_MAT73 ) {
                    if ( mat->refs_id > -1 )
                        H5Gclose(mat->refs_id);
                    H5Fclose(*(hid_t*)mat->fp);
                    free(mat->fp);
                    mat->fp = NULL;
                }
#endif
                if ( mat->fp != NULL ) {
                    fclose((FILE*)mat->fp);
                    mat->fp = NULL;
                }

                if ( (err = mat_copy(tmp_name,new_name)) == -1 ) {
                    if ( NULL != dir ) {
                        size_t i;
                        for ( i = 0; i < n; i++ ) {
                            if ( dir[i] )
                                free(dir[i]);
                        }
                        free(dir);
                    }
                    Mat_Critical("Cannot copy file from \"%s\" to \"%s\".",
                        tmp_name, new_name);
                } else if ( (err = remove(tmp_name)) == -1 ) {
                    if ( NULL != dir ) {
                        size_t i;
                        for ( i = 0; i < n; i++ ) {
                            if ( dir[i] )
                                free(dir[i]);
                        }
                        free(dir);
                    }
                    Mat_Critical("Cannot remove file \"%s\".",tmp_name);
                } else {
                    tmp = Mat_Open(new_name,mat->mode);
                    if ( NULL != tmp ) {
                        if ( mat->header )
                            free(mat->header);
                        if ( mat->subsys_offset )
                            free(mat->subsys_offset);
                        if ( mat->filename )
                            free(mat->filename);
                        if ( mat->dir ) {
                            size_t i;
                            for ( i = 0; i < mat->num_datasets; i++ ) {
                                if ( mat->dir[i] )
                                    free(mat->dir[i]);
                            }
                            free(mat->dir);
                        }
                        memcpy(mat,tmp,sizeof(mat_t));
                        free(tmp);
                        mat->num_datasets = n;
                        mat->dir = dir;
                    } else {
                        Mat_Critical("Cannot open file \"%s\".",new_name);
                    }
                }
                free(new_name);
            } else if ( (err = remove(tmp_name)) == -1 ) {
                Mat_Critical("Cannot remove file \"%s\".",tmp_name);
            }
        }
    } else {
        Mat_Critical("Cannot create a unique file name.");
    }

    return err;
}

Project: matio
File: mat.c

int SafeAdd(size_t* res, size_t a, size_t b)
{
    if ( !psnip_safe_size_add(res, a, b) ) {
        *res = 0;
        return 1;
    }

    return 0;
}

Project: matio
File: mat.c

Mat_VarWriteData(mat_t *mat,matvar_t *matvar,void *data,
      int *start,int *stride,int *edge)
{
    Mat_Critical("Mat_VarWriteInfo/Mat_VarWriteData is not supported. "
        "Use %s instead!", mat->version == MAT_FT_MAT73 ?
        "Mat_VarWrite/Mat_VarWriteAppend" : "Mat_VarWrite");
    return 1;
}

Project: matio
File: mat.c

Mat_VarReadNext( mat_t *mat )
{
    long fpos = 0;
    matvar_t *matvar = NULL;

    if ( mat->version != MAT_FT_MAT73 ) {
        if ( feof((FILE *)mat->fp) )
            return NULL;
        /* Read position so we can reset the file position if an error occurs */
        fpos = ftell((FILE*)mat->fp);
        if ( fpos == -1L ) {
            Mat_Critical("Couldn't determine file position");
            return NULL;
        }
    }
    matvar = Mat_VarReadNextInfo(mat);
    if ( matvar ) {
        const int err = ReadData(mat,matvar);
        if ( err ) {
            Mat_VarFree(matvar);
            matvar = NULL;
        }
    } else if ( mat->version != MAT_FT_MAT73 ) {
        (void)fseek((FILE*)mat->fp,fpos,SEEK_SET);
    }

    return matvar;
}

Project: matio
File: mat.c

Mat_CalcSubscripts(int rank,int *dims,int index)
{
    int i, j, *subs;
    double l;

    subs = (int*)malloc(rank*sizeof(int));
    l = index;
    for ( i = rank; i--; ) {
        int k = 1;
        for ( j = i; j--; )
            k *= dims[j];
        subs[i] = (int)floor(l / (double)k);
        l -= subs[i]*k;
        subs[i]++;
    }

    return subs;
}

Project: matio
File: mat.c

Mat_CreateVer(const char *matname,const char *hdr_str,enum mat_ft mat_file_ver)
{
    mat_t *mat;

    switch ( mat_file_ver ) {
        case MAT_FT_MAT4:
            mat = Mat_Create4(matname);
            break;
        case MAT_FT_MAT5:
            mat = Mat_Create5(matname,hdr_str);
            break;
        case MAT_FT_MAT73:
#if defined(MAT73) && MAT73
            mat = Mat_Create73(matname,hdr_str);
#else
            mat = NULL;
#endif
            break;
        default:
            mat = NULL;
            break;
    }

    return mat;
}

Project: matio
File: mat.c

Mat_Close( mat_t *mat )
{
    int err = 0;

    if ( NULL != mat ) {
#if defined(MAT73) && MAT73
        if ( mat->version == 0x0200 ) {
            if ( mat->refs_id > -1 )
                H5Gclose(mat->refs_id);
            if ( 0 > H5Fclose(*(hid_t*)mat->fp) )
                err = 1;
            free(mat->fp);
            mat->fp = NULL;
        }
#endif
        if ( NULL != mat->fp )
            fclose((FILE*)mat->fp);
        if ( NULL != mat->header )
            free(mat->header);
        if ( NULL != mat->subsys_offset )
            free(mat->subsys_offset);
        if ( NULL != mat->filename )
            free(mat->filename);
        if ( NULL != mat->dir ) {
            size_t i;
            for ( i = 0; i < mat->num_datasets; i++ ) {
                if ( NULL != mat->dir[i] )
                    free(mat->dir[i]);
            }
            free(mat->dir);
        }
        free(mat);
    }

    return err;
}

Project: matio
File: mat.c

Mat_VarReadNextInfo( mat_t *mat )
{
    matvar_t *matvar;
    if ( mat == NULL )
        return NULL;

    switch ( mat->version ) {
        case MAT_FT_MAT5:
            matvar = Mat_VarReadNextInfo5(mat);
            break;
        case MAT_FT_MAT73:
#if defined(MAT73) && MAT73
            matvar = Mat_VarReadNextInfo73(mat);
#else
            matvar = NULL;
#endif
            break;
        case MAT_FT_MAT4:
            matvar = Mat_VarReadNextInfo4(mat);
            break;
        default:
            matvar = NULL;
            break;
    }

    return matvar;
}

Project: matio
File: mat.c

Mat_GetFilename(mat_t *mat)
{
    const char *filename = NULL;
    if ( NULL != mat )
        filename = mat->filename;
    return filename;
}

Project: matio
File: mat.c

Mat_CalcSubscripts2(int rank,size_t *dims,size_t index)
{
    int i;
    size_t *subs;
    double l;

    subs = (size_t*)malloc(rank*sizeof(size_t));
    l = (double)index;
    for ( i = rank; i--; ) {
        int j;
        size_t k = 1;
        for ( j = i; j--; )
            k *= dims[j];
        subs[i] = (size_t)floor(l / (double)k);
        l -= subs[i]*k;
        subs[i]++;
    }

    return subs;
}

Project: matio
File: mat.c

ComplexMalloc(size_t nbytes)
{
    mat_complex_split_t *complex_data = (mat_complex_split_t*)malloc(sizeof(*complex_data));
    if ( NULL != complex_data ) {
        complex_data->Re = malloc(nbytes);
        if ( NULL != complex_data->Re ) {
            complex_data->Im = malloc(nbytes);
            if ( NULL == complex_data->Im ) {
                free(complex_data->Re);
                free(complex_data);
                complex_data = NULL;
            }
        }
        else {
            free(complex_data);
            complex_data = NULL;
        }
    }

    return complex_data;
}