mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-16 14:15:26 -06:00
2592 lines
85 KiB
C
2592 lines
85 KiB
C
/** @file mat.c
|
|
* Matlab MAT file functions
|
|
* @ingroup MAT
|
|
*/
|
|
/*
|
|
* Copyright (c) 2005-2019, Christopher C. Hulbert
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* FIXME: Implement Unicode support */
|
|
#include "safe-math.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#if HAVE_INTTYPES_H
|
|
# define __STDC_FORMAT_MACROS
|
|
# include <inttypes.h>
|
|
#endif
|
|
#if defined(_WIN64) || defined(_WIN32)
|
|
# include <io.h>
|
|
# define mktemp _mktemp
|
|
#endif
|
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
# define SIZE_T_FMTSTR "Iu"
|
|
# define strdup _strdup
|
|
#else
|
|
# define SIZE_T_FMTSTR "zu"
|
|
#endif
|
|
#include "matio_private.h"
|
|
#include "mat5.h"
|
|
#include "mat4.h"
|
|
#if defined(MAT73) && MAT73
|
|
# include "mat73.h"
|
|
#endif
|
|
|
|
/*
|
|
*===================================================================
|
|
* Private Functions
|
|
*===================================================================
|
|
*/
|
|
|
|
static void
|
|
ReadData(mat_t *mat, matvar_t *matvar)
|
|
{
|
|
if ( mat == NULL || matvar == NULL || mat->fp == NULL )
|
|
return;
|
|
else if ( mat->version == MAT_FT_MAT5 )
|
|
Mat_VarRead5(mat,matvar);
|
|
#if defined(MAT73) && MAT73
|
|
else if ( mat->version == MAT_FT_MAT73 )
|
|
Mat_VarRead73(mat,matvar);
|
|
#endif
|
|
else if ( mat->version == MAT_FT_MAT4 )
|
|
Mat_VarRead4(mat,matvar);
|
|
return;
|
|
}
|
|
|
|
static void
|
|
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;
|
|
}
|
|
}
|
|
|
|
mat_complex_split_t *
|
|
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;
|
|
}
|
|
|
|
enum matio_types
|
|
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;
|
|
}
|
|
}
|
|
|
|
/** @brief Gets number of elements from a variable
|
|
*
|
|
* Gets number of elements from a variable by overflow-safe
|
|
* multiplication
|
|
* @ingroup MAT
|
|
* @param matvar MAT variable information
|
|
* @param nelems Number of elements
|
|
* @retval 0 on success
|
|
*/
|
|
int SafeMulDims(const matvar_t *matvar, size_t* nelems)
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < matvar->rank; i++ ) {
|
|
if ( !psnip_safe_size_mul(nelems, *nelems, matvar->dims[i]) ) {
|
|
*nelems = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** @brief Multiplies two unsigned integers
|
|
*
|
|
* @param res Result
|
|
* @param a First operand
|
|
* @param b Second operand
|
|
* @retval 0 on success
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/*
|
|
*===================================================================
|
|
* Public Functions
|
|
*===================================================================
|
|
*/
|
|
|
|
/** @brief Get the version of the library
|
|
*
|
|
* Gets the version number of the library
|
|
* @param major Pointer to store the library major version number
|
|
* @param minor Pointer to store the library minor version number
|
|
* @param release Pointer to store the library release version number
|
|
*/
|
|
void
|
|
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;
|
|
}
|
|
|
|
/** @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
|
|
* @param mat_file_ver MAT file version to create
|
|
* @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_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;
|
|
}
|
|
|
|
/** @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;
|
|
mat_t *mat = NULL;
|
|
size_t bytesread = 0;
|
|
|
|
if ( (mode & 0x01) == MAT_ACC_RDONLY ) {
|
|
fp = fopen( matname, "rb" );
|
|
if ( !fp )
|
|
return NULL;
|
|
} else if ( (mode & 0x01) == MAT_ACC_RDWR ) {
|
|
fp = fopen( matname, "r+b" );
|
|
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(mat->filename,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(mat->filename,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;
|
|
}
|
|
|
|
/** @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 on success
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @brief Gets the filename for the given MAT file
|
|
*
|
|
* Gets the filename for the given MAT file
|
|
* @ingroup MAT
|
|
* @param mat Pointer to the MAT file
|
|
* @return MAT filename
|
|
*/
|
|
const char *
|
|
Mat_GetFilename(mat_t *mat)
|
|
{
|
|
const char *filename = NULL;
|
|
if ( NULL != mat )
|
|
filename = mat->filename;
|
|
return filename;
|
|
}
|
|
|
|
/** @brief Gets the header for the given MAT file
|
|
*
|
|
* Gets the header for the given MAT file
|
|
* @ingroup MAT
|
|
* @param mat Pointer to the MAT file
|
|
* @return MAT header
|
|
*/
|
|
const char *
|
|
Mat_GetHeader(mat_t *mat)
|
|
{
|
|
const char *header = NULL;
|
|
if ( NULL != mat )
|
|
header = mat->header;
|
|
return header;
|
|
}
|
|
|
|
/** @brief Gets the version of the given MAT file
|
|
*
|
|
* Gets the version of the given MAT file
|
|
* @ingroup MAT
|
|
* @param mat Pointer to the MAT file
|
|
* @return MAT file version
|
|
*/
|
|
enum mat_ft
|
|
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;
|
|
}
|
|
|
|
/** @brief Gets a list of the variables of a MAT file
|
|
*
|
|
* Gets a list of the variables of a MAT file
|
|
* @ingroup MAT
|
|
* @param mat Pointer to the MAT file
|
|
* @param[out] n Number of variables in the given MAT file
|
|
* @return Array of variable names
|
|
*/
|
|
char **
|
|
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;
|
|
}
|
|
|
|
/** @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 )
|
|
{
|
|
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;
|
|
}
|
|
|
|
/** @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 = (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 defined(HAVE_ZLIB)
|
|
matvar->internal->z = NULL;
|
|
matvar->internal->data = 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:
|
|
* - MAT_F_DONT_COPY_DATA 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 MAT_F_DONT_COPY_DATA, so free it yourself.
|
|
* - MAT_F_COMPLEX to specify that the data is complex. The data variable
|
|
* should be a pointer to a mat_complex_split_t type.
|
|
* - 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,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;
|
|
|
|
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);
|
|
SafeMul(&nelems, nelems, nfields);
|
|
}
|
|
}
|
|
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;
|
|
SafeMul(&matvar->nbytes, nelems, matvar->data_size);
|
|
}
|
|
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_int32_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_int32_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;
|
|
}
|
|
|
|
/** @brief Copies a file
|
|
*
|
|
* @param src source file path
|
|
* @param dst destination file path
|
|
* @retval 0 on success
|
|
*/
|
|
static int
|
|
mat_copy(const char* src, const char* dst)
|
|
{
|
|
size_t len;
|
|
char buf[BUFSIZ] = {'\0'};
|
|
FILE* in;
|
|
FILE* out;
|
|
|
|
in = fopen(src, "rb");
|
|
if ( in == NULL ) {
|
|
Mat_Critical("Cannot open file \"%s\" for reading.", src);
|
|
return -1;
|
|
}
|
|
|
|
out = fopen(dst, "wb");
|
|
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;
|
|
}
|
|
|
|
/** @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, 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 (matvar->name == NULL) // Added to avoid exception in strcmp() when name == NULL
|
|
;
|
|
else 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;
|
|
}
|
|
|
|
/** @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;
|
|
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 defined(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 defined(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_int32_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_int32_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_int32_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_int32_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;
|
|
}
|
|
|
|
/** @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 MAT_F_DONT_COPY_DATA was not used.
|
|
* @ingroup MAT
|
|
* @param matvar Pointer to the matvar_t structure
|
|
*/
|
|
void
|
|
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 ) {
|
|
mat_complex_split_t *complex_data = (mat_complex_split_t*)sparse->data;
|
|
free(complex_data->Re);
|
|
free(complex_data->Im);
|
|
free(complex_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 ) {
|
|
mat_complex_split_t *complex_data = (mat_complex_split_t*)matvar->data;
|
|
free(complex_data->Re);
|
|
free(complex_data->Im);
|
|
free(complex_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 defined(HAVE_ZLIB)
|
|
if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
|
|
inflateEnd(matvar->internal->z);
|
|
free(matvar->internal->z);
|
|
if ( (matvar->internal->data != NULL) && (matvar->class_type == MAT_C_SPARSE) ) {
|
|
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 ) {
|
|
mat_complex_split_t *complex_data = (mat_complex_split_t*)sparse->data;
|
|
free(complex_data->Re);
|
|
free(complex_data->Im);
|
|
free(complex_data);
|
|
} else if ( sparse->data != NULL ) {
|
|
free(sparse->data);
|
|
}
|
|
free(sparse);
|
|
}
|
|
else if ( (matvar->internal->data != NULL) && matvar->isComplex ) {
|
|
mat_complex_split_t *complex_data =
|
|
(mat_complex_split_t*)matvar->internal->data;
|
|
free(complex_data->Re);
|
|
free(complex_data->Im);
|
|
free(complex_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);
|
|
}
|
|
|
|
/** @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 corresponding 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 Array of dimension subscripts
|
|
* @return Single (linear) subscript
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @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 corresponding 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 Array of dimension subscripts
|
|
* @param[out] index Single (linear) subscript
|
|
* @retval 0 on success
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @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, *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;
|
|
}
|
|
|
|
/** @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
|
|
*/
|
|
size_t *
|
|
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;
|
|
}
|
|
|
|
/** @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)
|
|
{
|
|
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;
|
|
if ( NULL != fields ) {
|
|
size_t nelems_x_nfields = matvar->internal->num_fields;
|
|
SafeMulDims(matvar, &nelems_x_nfields);
|
|
SafeMul(&bytes, nelems_x_nfields, overhead);
|
|
for ( i = 0; i < nelems_x_nfields; i++ ) {
|
|
if ( NULL != fields[i] ) {
|
|
if ( MAT_C_EMPTY != fields[i]->class_type )
|
|
bytes += Mat_VarGetSize(fields[i]);
|
|
else
|
|
bytes += ptr - overhead;
|
|
}
|
|
}
|
|
}
|
|
bytes += 64 /* max field name length */ *matvar->internal->num_fields;
|
|
} 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;
|
|
bytes = nelems*overhead;
|
|
for ( i = 0; i < nelems; i++ ) {
|
|
if ( NULL != cells[i] ) {
|
|
if ( MAT_C_EMPTY != cells[i]->class_type )
|
|
bytes += Mat_VarGetSize(cells[i]);
|
|
else
|
|
bytes += ptr - overhead;
|
|
}
|
|
}
|
|
}
|
|
} else if ( matvar->class_type == MAT_C_SPARSE ) {
|
|
mat_sparse_t *sparse = (mat_sparse_t*)matvar->data;
|
|
if ( NULL != sparse ) {
|
|
bytes = sparse->ndata*Mat_SizeOf(matvar->data_type);
|
|
if ( matvar->isComplex )
|
|
bytes *= 2;
|
|
#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) */
|
|
bytes += (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) */
|
|
bytes += (sparse->nir + sparse->njc)*4;
|
|
#endif
|
|
if ( sparse->ndata == 0 || sparse->nir == 0 || sparse->njc == 0 )
|
|
bytes += matvar->isLogical ? 1 : 8;
|
|
}
|
|
} else {
|
|
if ( matvar->rank > 0 ) {
|
|
bytes = Mat_SizeOfClass(matvar->class_type);
|
|
SafeMulDims(matvar, &bytes);
|
|
if ( matvar->isComplex )
|
|
bytes *= 2;
|
|
}
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
/** @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 )
|
|
{
|
|
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 < sparse->njc-1; i++ ) {
|
|
for ( j = sparse->jc[i];
|
|
j < sparse->jc[i+1] && j < 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 < sparse->njc-1; i++ ) {
|
|
for ( j = sparse->jc[i];
|
|
j < sparse->jc[i+1] && j < 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;
|
|
}
|
|
|
|
/** @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 indices
|
|
* @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;
|
|
|
|
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;
|
|
}
|
|
|
|
/** @brief Reads all the data for a matlab variable
|
|
*
|
|
* Allocates memory and 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 a subset of a MAT variable using a 1-D indexing
|
|
*
|
|
* Reads data from a MAT variable using a linear (1-D) indexing mode. 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;
|
|
|
|
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;
|
|
}
|
|
|
|
/** @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 )
|
|
{
|
|
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;
|
|
}
|
|
|
|
/** @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, 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;
|
|
}
|
|
|
|
/** @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, 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 )
|
|
ReadData(mat,matvar);
|
|
(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 )
|
|
ReadData(mat,matvar);
|
|
mat->next_index = fpos;
|
|
}
|
|
|
|
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 = 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 ) {
|
|
ReadData(mat,matvar);
|
|
} else if ( mat->version != MAT_FT_MAT73 ) {
|
|
(void)fseek((FILE*)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 1
|
|
* @deprecated
|
|
* @see Mat_VarWrite/Mat_VarWriteAppend
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @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 indices
|
|
* @param stride stride of data
|
|
* @param edge array specifying the number to read in each direction
|
|
* @retval 1
|
|
* @deprecated
|
|
* @see Mat_VarWrite/Mat_VarWriteAppend
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @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 and 7.3 MAT files and variables with
|
|
numeric data)
|
|
* @retval 0 on success
|
|
*/
|
|
int
|
|
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;
|
|
}
|
|
|
|
/** @brief Writes/appends the given MAT variable to a version 7.3 MAT file
|
|
*
|
|
* Writes the numeric data of the MAT variable stored in matvar to the given
|
|
* MAT file. The variable will be written to the end of the file if it does
|
|
* not yet exist or appended to the existing variable.
|
|
* @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 7.3 MAT files and variables with numeric data)
|
|
* @param dim dimension to append data
|
|
* (Only valid for version 7.3 MAT files and variables with numeric data)
|
|
* @retval 0 on success
|
|
*/
|
|
int
|
|
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;
|
|
}
|