ultimatepp/bazaar/plugin/matio/lib/mat73.c
koldo 2ae72cfcea matio: Matlab files IO
git-svn-id: svn://ultimatepp.org/upp/trunk@13328 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2019-05-19 18:29:21 +00:00

2816 lines
95 KiB
C

/** @file mat73.c
* Matlab MAT version 7.3 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.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#if defined(_MSC_VER) || defined(__MINGW32__)
# define strdup _strdup
#endif
#include "matio_private.h"
#if defined(MAT73) && MAT73
#if HAVE_HDF5
#include "mat73.h"
static const char *ClassNames[] = {
"",
"cell",
"struct",
"object",
"char",
"sparse",
"double",
"single",
"int8",
"uint8",
"int16",
"uint16",
"int32",
"uint32",
"int64",
"uint64",
"function"
};
struct ReadNextIterData {
mat_t *mat;
matvar_t *matvar;
};
struct ReadGroupInfoIterData {
hsize_t nfields;
matvar_t *matvar;
};
#if H5_VERSION_GE(1,10,0)
#define H5RDEREFERENCE(obj_id, ref_type, _ref) H5Rdereference2((obj_id), H5P_DATASET_ACCESS_DEFAULT, (ref_type), (_ref))
#else
#define H5RDEREFERENCE(obj_id, ref_type, _ref) H5Rdereference((obj_id), (ref_type), (_ref))
#endif
#if H5_VERSION_GE(1,10,3)
#define H5OGET_INFO_BY_NAME(loc_id, name, oinfo, lapl_id) H5Oget_info_by_name2((loc_id), (name), (oinfo), H5O_INFO_BASIC, (lapl_id));
#else
#define H5OGET_INFO_BY_NAME(loc_id, name, oinfo, lapl_id) H5Oget_info_by_name((loc_id), (name), (oinfo), (lapl_id));
#endif
#if !defined(MAX_RANK)
/* Maximal number of dimensions for stack allocated temporary dimension arrays */
#define MAX_RANK (3)
#endif
/*===========================================================================
* Private functions
*===========================================================================
*/
static enum matio_classes ClassStr2ClassType(const char *name);
static enum matio_classes DataType2ClassType(enum matio_types type);
static hid_t ClassType2H5T(enum matio_classes class_type);
static hid_t DataType2H5T(enum matio_types data_type);
static hid_t SizeType2H5T(void);
static hid_t DataType(hid_t h5_type, int isComplex);
static void Mat_H5GetChunkSize(size_t rank,hsize_t *dims,hsize_t *chunk_dims);
static void Mat_H5ReadVarInfo(matvar_t *matvar,hid_t dset_id);
static size_t* Mat_H5ReadDims(hid_t dset_id, hsize_t *nelems, int *rank);
static void Mat_H5ReadFieldNames(matvar_t *matvar, hid_t dset_id, hsize_t *nfields);
static void Mat_H5ReadDatasetInfo(mat_t *mat,matvar_t *matvar,hid_t dset_id);
static void Mat_H5ReadGroupInfo(mat_t *mat,matvar_t *matvar,hid_t dset_id);
static void Mat_H5ReadNextReferenceInfo(hid_t ref_id,matvar_t *matvar,mat_t *mat);
static void Mat_H5ReadNextReferenceData(hid_t ref_id,matvar_t *matvar,mat_t *mat);
static int Mat_VarWriteEmpty(hid_t id,matvar_t *matvar,const char *name,
const char* class_name);
static int Mat_VarWriteCell73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,hsize_t *dims);
static int Mat_VarWriteChar73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims);
static int Mat_WriteEmptyVariable73(hid_t id,const char *name,hsize_t rank,
size_t *dims);
static int Mat_VarWriteLogical73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims);
static int Mat_VarWriteNumeric73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims,
hsize_t* max_dims);
static int Mat_VarWriteAppendNumeric73(hid_t id,matvar_t *matvar,const char *name,
hsize_t *dims,int dim);
static int Mat_VarWriteSparse73(hid_t id,matvar_t *matvar,const char *name);
static int Mat_VarWriteStruct73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,hsize_t *dims,hsize_t* max_dims);
static int Mat_VarWriteAppendStruct73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,hsize_t *dims,int dim);
static int Mat_VarWriteNext73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id);
static int Mat_VarWriteAppendNext73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,int dim);
static int Mat_VarWriteNextType73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,hsize_t *dims);
static int Mat_VarWriteAppendNextType73(hid_t id,matvar_t *matvar,const char *name,
hid_t *refs_id,hsize_t *dims,int dim);
static herr_t Mat_VarReadNextInfoIterate(hid_t id, const char *name,
const H5L_info_t *info, void *op_data);
static herr_t Mat_H5ReadGroupInfoIterate(hid_t dset_id, const char *name,
const H5L_info_t *info, void *op_data);
static void Mat_H5ReadData(hid_t dset_id, hid_t h5_type, hid_t mem_space, hid_t dset_space,
int isComplex, void *data);
static int Mat_H5WriteData(hid_t dset_id, hid_t h5_type, hid_t mem_space, hid_t dset_space,
int isComplex, void *data);
static int Mat_H5WriteAppendData(hid_t id, hid_t h5_type, int mrank, const char *name,
const size_t* mdims, hsize_t *dims, int dim, int isComplex, void* data);
static int Mat_VarWriteRef(hid_t id, matvar_t* matvar, enum matio_compression compression,
hid_t *refs_id, hobj_ref_t* ref);
static enum matio_classes
ClassStr2ClassType(const char *name)
{
enum matio_classes id = MAT_C_EMPTY;
if ( NULL != name ) {
int k;
for ( k = 1; k < 17; k++ ) {
if ( 0 == strcmp(name,ClassNames[k]) ) {
id = (enum matio_classes)k;
break;
}
}
}
return id;
}
static enum matio_classes
DataType2ClassType(enum matio_types type)
{
switch ( type ) {
case MAT_T_DOUBLE:
return MAT_C_DOUBLE;
case MAT_T_SINGLE:
return MAT_C_SINGLE;
#ifdef HAVE_MAT_INT64_T
case MAT_T_INT64:
return MAT_C_INT64;
#endif
#ifdef HAVE_MAT_UINT64_T
case MAT_T_UINT64:
return MAT_C_UINT64;
#endif
case MAT_T_INT32:
return MAT_C_INT32;
case MAT_T_UINT32:
return MAT_C_UINT32;
case MAT_T_INT16:
return MAT_C_INT16;
case MAT_T_UINT16:
return MAT_C_UINT16;
case MAT_T_INT8:
return MAT_C_INT8;
case MAT_T_UINT8:
return MAT_C_UINT8;
default:
return MAT_C_EMPTY;
}
}
static hid_t
ClassType2H5T(enum matio_classes class_type)
{
switch ( class_type ) {
case MAT_C_DOUBLE:
return H5T_NATIVE_DOUBLE;
case MAT_C_SINGLE:
return H5T_NATIVE_FLOAT;
case MAT_C_INT64:
# if CHAR_BIT*SIZEOF_SHORT == 64
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 64
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 64
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 64
return H5T_NATIVE_LLONG;
# endif
case MAT_C_UINT64:
# if CHAR_BIT*SIZEOF_SHORT == 64
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 64
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 64
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 64
return H5T_NATIVE_ULLONG;
# endif
case MAT_C_INT32:
# if CHAR_BIT == 32
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 32
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 32
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 32
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 32
return H5T_NATIVE_LLONG;
# endif
case MAT_C_UINT32:
# if CHAR_BIT == 32
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 32
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 32
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 32
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 32
return H5T_NATIVE_ULLONG;
# endif
case MAT_C_INT16:
# if CHAR_BIT == 16
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 16
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 16
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 16
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 16
return H5T_NATIVE_LLONG;
# endif
case MAT_C_UINT16:
# if CHAR_BIT == 16
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 16
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 16
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 16
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 16
return H5T_NATIVE_ULLONG;
# endif
case MAT_C_INT8:
# if CHAR_BIT == 8
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 8
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 8
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 8
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 8
return H5T_NATIVE_LLONG;
# endif
case MAT_C_UINT8:
# if CHAR_BIT == 8
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 8
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 8
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 8
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 8
return H5T_NATIVE_ULLONG;
# endif
default:
return -1;
}
}
static hid_t
DataType2H5T(enum matio_types data_type)
{
switch ( data_type ) {
case MAT_T_DOUBLE:
return H5T_NATIVE_DOUBLE;
case MAT_T_SINGLE:
return H5T_NATIVE_FLOAT;
case MAT_T_INT64:
# if CHAR_BIT*SIZEOF_SHORT == 64
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 64
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 64
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 64
return H5T_NATIVE_LLONG;
# endif
case MAT_T_UINT64:
# if CHAR_BIT*SIZEOF_SHORT == 64
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 64
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 64
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 64
return H5T_NATIVE_ULLONG;
# endif
case MAT_T_INT32:
# if CHAR_BIT == 32
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 32
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 32
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 32
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 32
return H5T_NATIVE_LLONG;
# endif
case MAT_T_UINT32:
# if CHAR_BIT == 32
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 32
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 32
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 32
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 32
return H5T_NATIVE_ULLONG;
# endif
case MAT_T_INT16:
# if CHAR_BIT == 16
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 16
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 16
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 16
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 16
return H5T_NATIVE_LLONG;
# endif
case MAT_T_UINT16:
case MAT_T_UTF16:
# if CHAR_BIT == 16
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 16
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 16
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 16
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 16
return H5T_NATIVE_ULLONG;
# endif
case MAT_T_INT8:
# if CHAR_BIT == 8
return H5T_NATIVE_SCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 8
return H5T_NATIVE_SHORT;
# elif CHAR_BIT*SIZEOF_INT == 8
return H5T_NATIVE_INT;
# elif CHAR_BIT*SIZEOF_LONG == 8
return H5T_NATIVE_LONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 8
return H5T_NATIVE_LLONG;
# endif
case MAT_T_UINT8:
# if CHAR_BIT == 8
return H5T_NATIVE_UCHAR;
# elif CHAR_BIT*SIZEOF_SHORT == 8
return H5T_NATIVE_USHORT;
# elif CHAR_BIT*SIZEOF_INT == 8
return H5T_NATIVE_UINT;
# elif CHAR_BIT*SIZEOF_LONG == 8
return H5T_NATIVE_ULONG;
# elif CHAR_BIT*SIZEOF_LONG_LONG == 8
return H5T_NATIVE_ULLONG;
# endif
case MAT_T_UTF8:
return H5T_NATIVE_CHAR;
default:
return -1;
}
}
static hid_t
SizeType2H5T(void)
{
if ( sizeof(size_t) == H5Tget_size(H5T_NATIVE_HSIZE) )
return H5T_NATIVE_HSIZE;
else if ( sizeof(size_t) == H5Tget_size(H5T_NATIVE_ULLONG) )
return H5T_NATIVE_ULLONG;
else if ( sizeof(size_t) == H5Tget_size(H5T_NATIVE_ULONG) )
return H5T_NATIVE_ULONG;
else if ( sizeof(size_t) == H5Tget_size(H5T_NATIVE_UINT) )
return H5T_NATIVE_UINT;
else if ( sizeof(size_t) == H5Tget_size(H5T_NATIVE_USHORT) )
return H5T_NATIVE_USHORT;
else
return -1;
}
static hid_t
DataType(hid_t h5_type, int isComplex)
{
hid_t h5_dtype;
if ( isComplex ) {
size_t h5_size = H5Tget_size(h5_type);
h5_dtype = H5Tcreate(H5T_COMPOUND, 2*h5_size);
H5Tinsert(h5_dtype,"real",0,h5_type);
H5Tinsert(h5_dtype,"imag",h5_size,h5_type);
} else {
h5_dtype = H5Tcopy(h5_type);
}
return h5_dtype;
}
static void
Mat_H5GetChunkSize(size_t rank,hsize_t *dims,hsize_t *chunk_dims)
{
hsize_t i, j, chunk_size = 1;
for ( i = 0; i < rank; i++ ) {
chunk_dims[i] = 1;
for ( j = 4096/chunk_size; j > 1; j >>= 1 ) {
if ( dims[i] >= j ) {
chunk_dims[i] = j;
break;
}
}
chunk_size *= chunk_dims[i];
}
}
static void
Mat_H5ReadVarInfo(matvar_t *matvar,hid_t dset_id)
{
hid_t attr_id, type_id;
ssize_t name_len;
/* Get the HDF5 name of the variable */
name_len = H5Iget_name(dset_id,NULL,0);
if ( name_len > 0 ) {
matvar->internal->hdf5_name = (char*)malloc(name_len+1);
(void)H5Iget_name(dset_id,matvar->internal->hdf5_name,name_len+1);
} else {
/* Can not get an internal name, so leave the identifier open */
matvar->internal->id = dset_id;
}
attr_id = H5Aopen_by_name(dset_id,".","MATLAB_class",H5P_DEFAULT,H5P_DEFAULT);
type_id = H5Aget_type(attr_id);
if ( H5T_STRING == H5Tget_class(type_id) ) {
char *class_str = (char*)calloc(H5Tget_size(type_id)+1,1);
if ( NULL != class_str ) {
hid_t class_id = H5Tcopy(H5T_C_S1);
H5Tset_size(class_id,H5Tget_size(type_id));
H5Aread(attr_id,class_id,class_str);
H5Tclose(class_id);
matvar->class_type = ClassStr2ClassType(class_str);
if ( MAT_C_EMPTY == matvar->class_type || MAT_C_CHAR == matvar->class_type ) {
int int_decode = 0;
if ( H5Aexists_by_name(dset_id,".","MATLAB_int_decode",H5P_DEFAULT) ) {
hid_t attr_id2 = H5Aopen_by_name(dset_id,".","MATLAB_int_decode",H5P_DEFAULT,H5P_DEFAULT);
/* FIXME: Check that dataspace is scalar */
H5Aread(attr_id2,H5T_NATIVE_INT,&int_decode);
H5Aclose(attr_id2);
}
switch ( int_decode ) {
case 2:
matvar->data_type = MAT_T_UINT16;
break;
case 1:
matvar->data_type = MAT_T_UINT8;
break;
case 4:
matvar->data_type = MAT_T_UINT32;
break;
default:
matvar->data_type = MAT_T_UNKNOWN;
break;
}
if ( MAT_C_EMPTY == matvar->class_type ) {
/* Check if this is a logical variable */
if ( 0 == strcmp(class_str, "logical") ) {
matvar->isLogical = MAT_F_LOGICAL;
}
matvar->class_type = DataType2ClassType(matvar->data_type);
} else if ( MAT_T_UNKNOWN == matvar->data_type ) {
matvar->data_type = MAT_T_UINT16;
}
} else {
matvar->data_type = ClassType2DataType(matvar->class_type);
}
free(class_str);
}
}
H5Tclose(type_id);
H5Aclose(attr_id);
/* Check if the variable is global */
if ( H5Aexists_by_name(dset_id,".","MATLAB_global",H5P_DEFAULT) ) {
attr_id = H5Aopen_by_name(dset_id,".","MATLAB_global",H5P_DEFAULT,H5P_DEFAULT);
/* FIXME: Check that dataspace is scalar */
H5Aread(attr_id,H5T_NATIVE_INT,&matvar->isGlobal);
H5Aclose(attr_id);
}
}
static size_t*
Mat_H5ReadDims(hid_t dset_id, hsize_t *nelems, int *rank)
{
hid_t space_id;
size_t* perm_dims;
*nelems = 0;
space_id = H5Dget_space(dset_id);
*rank = H5Sget_simple_extent_ndims(space_id);
if ( 0 > *rank ) {
*rank = 0;
H5Sclose(space_id);
return NULL;
}
perm_dims = (size_t*)malloc(*rank*sizeof(*perm_dims));
if ( NULL != perm_dims ) {
if ( MAX_RANK >= *rank ) {
hsize_t dims[MAX_RANK];
int k;
size_t tmp = 1;
(void)H5Sget_simple_extent_dims(space_id,dims,NULL);
/* Permute dimensions */
for ( k = 0; k < *rank; k++ ) {
perm_dims[k] = (size_t)dims[*rank - k - 1];
SafeMul(&tmp, tmp, perm_dims[k]);
}
*nelems = (hsize_t)tmp;
H5Sclose(space_id);
} else {
hsize_t* dims = (hsize_t*)malloc(*rank*sizeof(hsize_t));
if ( NULL != dims ) {
int k;
size_t tmp = 1;
(void)H5Sget_simple_extent_dims(space_id,dims,NULL);
/* Permute dimensions */
for ( k = 0; k < *rank; k++ ) {
perm_dims[k] = (size_t)dims[*rank - k - 1];
SafeMul(&tmp, tmp, perm_dims[k]);
}
*nelems = (hsize_t)tmp;
free(dims);
H5Sclose(space_id);
} else {
free(perm_dims);
perm_dims = NULL;
*rank = 0;
H5Sclose(space_id);
Mat_Critical("Error allocating memory for dims");
}
}
} else {
*rank = 0;
H5Sclose(space_id);
Mat_Critical("Error allocating memory for matvar->dims");
}
return perm_dims;
}
static void
Mat_H5ReadFieldNames(matvar_t *matvar, hid_t dset_id, hsize_t *nfields)
{
hsize_t i;
hid_t field_id, attr_id, space_id;
hvl_t *fieldnames_vl;
attr_id = H5Aopen_by_name(dset_id,".","MATLAB_fields",H5P_DEFAULT,H5P_DEFAULT);
space_id = H5Aget_space(attr_id);
(void)H5Sget_simple_extent_dims(space_id,nfields,NULL);
field_id = H5Aget_type(attr_id);
fieldnames_vl = (hvl_t*)malloc((size_t)(*nfields)*sizeof(*fieldnames_vl));
H5Aread(attr_id,field_id,fieldnames_vl);
matvar->internal->num_fields = (unsigned int)*nfields;
matvar->internal->fieldnames =
(char**)malloc((size_t)(*nfields)*sizeof(*matvar->internal->fieldnames));
for ( i = 0; i < *nfields; i++ ) {
matvar->internal->fieldnames[i] =
(char*)calloc(fieldnames_vl[i].len+1,1);
memcpy(matvar->internal->fieldnames[i],fieldnames_vl[i].p,
fieldnames_vl[i].len);
}
H5Dvlen_reclaim(field_id,space_id,H5P_DEFAULT,fieldnames_vl);
H5Sclose(space_id);
H5Tclose(field_id);
H5Aclose(attr_id);
free(fieldnames_vl);
}
static void
Mat_H5ReadDatasetInfo(mat_t *mat,matvar_t *matvar,hid_t dset_id)
{
hid_t attr_id,type_id;
hsize_t nelems;
Mat_H5ReadVarInfo(matvar, dset_id);
matvar->dims = Mat_H5ReadDims(dset_id, &nelems, &matvar->rank);
if ( NULL == matvar->dims ) {
return;
}
/* Check for attribute that indicates an empty array */
if ( H5Aexists_by_name(dset_id,".","MATLAB_empty",H5P_DEFAULT) ) {
int empty = 0;
attr_id = H5Aopen_by_name(dset_id,".","MATLAB_empty",H5P_DEFAULT,H5P_DEFAULT);
/* FIXME: Check that dataspace is scalar */
H5Aread(attr_id,H5T_NATIVE_INT,&empty);
H5Aclose(attr_id);
if ( empty ) {
matvar->rank = matvar->dims[0];
free(matvar->dims);
matvar->dims = (size_t*)calloc(matvar->rank,sizeof(*matvar->dims));
H5Dread(dset_id,SizeType2H5T(),H5S_ALL,H5S_ALL,H5P_DEFAULT,matvar->dims);
{
size_t tmp = 1;
SafeMulDims(matvar, &tmp);
nelems = (hsize_t)tmp;
}
}
}
/* Test if dataset type is compound and if so if it's complex */
type_id = H5Dget_type(dset_id);
if ( H5T_COMPOUND == H5Tget_class(type_id) ) {
/* FIXME: Any more checks? */
matvar->isComplex = MAT_F_COMPLEX;
}
H5Tclose(type_id);
/* If the dataset is a cell array read the info of the cells */
if ( MAT_C_CELL == matvar->class_type ) {
matvar_t **cells;
hobj_ref_t *ref_ids;
matvar->data_size = sizeof(matvar_t**);
SafeMul(&matvar->nbytes, nelems, matvar->data_size);
matvar->data = malloc(matvar->nbytes);
cells = (matvar_t**)matvar->data;
if ( nelems ) {
size_t i;
ref_ids = (hobj_ref_t*)malloc(nelems*sizeof(*ref_ids));
H5Dread(dset_id,H5T_STD_REF_OBJ,H5S_ALL,H5S_ALL,H5P_DEFAULT,ref_ids);
for ( i = 0; i < nelems; i++ ) {
hid_t ref_id;
cells[i] = Mat_VarCalloc();
cells[i]->internal->hdf5_ref = ref_ids[i];
/* Closing of ref_id is done in Mat_H5ReadNextReferenceInfo */
ref_id = H5RDEREFERENCE(dset_id,H5R_OBJECT,ref_ids+i);
cells[i]->internal->id = ref_id;
Mat_H5ReadNextReferenceInfo(ref_id,cells[i],mat);
}
free(ref_ids);
}
} else if ( MAT_C_STRUCT == matvar->class_type ) {
/* Empty structures can be a dataset */
/* Check if the structure defines its fields in MATLAB_fields */
if ( H5Aexists_by_name(dset_id,".","MATLAB_fields",H5P_DEFAULT) ) {
hsize_t nfields;
Mat_H5ReadFieldNames(matvar, dset_id, &nfields);
}
}
}
static void
Mat_H5ReadGroupInfo(mat_t *mat,matvar_t *matvar,hid_t dset_id)
{
int fields_are_variables = 1;
hsize_t nfields=0,nelems;
hid_t attr_id,field_id;
matvar_t **fields;
H5O_type_t obj_type;
Mat_H5ReadVarInfo(matvar,dset_id);
/* Check if the variable is sparse */
if ( H5Aexists_by_name(dset_id,".","MATLAB_sparse",H5P_DEFAULT) ) {
hid_t sparse_dset_id;
unsigned nrows = 0;
attr_id = H5Aopen_by_name(dset_id,".","MATLAB_sparse",H5P_DEFAULT,H5P_DEFAULT);
H5Aread(attr_id,H5T_NATIVE_UINT,&nrows);
H5Aclose(attr_id);
matvar->class_type = MAT_C_SPARSE;
sparse_dset_id = H5Dopen(dset_id,"jc",H5P_DEFAULT);
matvar->dims = Mat_H5ReadDims(sparse_dset_id, &nelems, &matvar->rank);
H5Dclose(sparse_dset_id);
if ( NULL != matvar->dims ) {
if ( 1 == matvar->rank ) {
size_t* dims = (size_t*)realloc(matvar->dims, 2*sizeof(*matvar->dims));
if ( NULL != dims ) {
matvar->rank = 2;
matvar->dims = dims;
}
}
if ( 2 == matvar->rank ) {
matvar->dims[1] = matvar->dims[0] - 1;
matvar->dims[0] = nrows;
}
} else {
return;
}
/* Test if dataset type is compound and if so if it's complex */
if ( H5Lexists(dset_id,"data",H5P_DEFAULT) ) {
hid_t type_id;
sparse_dset_id = H5Dopen(dset_id,"data",H5P_DEFAULT);
type_id = H5Dget_type(sparse_dset_id);
if ( H5T_COMPOUND == H5Tget_class(type_id) ) {
/* FIXME: Any more checks? */
matvar->isComplex = MAT_F_COMPLEX;
}
H5Tclose(type_id);
H5Dclose(sparse_dset_id);
}
return;
}
/* Check if the structure defines its fields in MATLAB_fields */
if ( H5Aexists_by_name(dset_id,".","MATLAB_fields",H5P_DEFAULT) ) {
Mat_H5ReadFieldNames(matvar, dset_id, &nfields);
} else {
H5G_info_t group_info;
matvar->internal->num_fields = 0;
H5Gget_info(dset_id, &group_info);
if ( group_info.nlinks > 0 ) {
struct ReadGroupInfoIterData group_data = {0, NULL};
herr_t herr;
/* First iteration to retrieve number of relevant links */
herr = H5Literate_by_name(dset_id, matvar->internal->hdf5_name, H5_INDEX_NAME,
H5_ITER_NATIVE, NULL, Mat_H5ReadGroupInfoIterate,
(void *)&group_data, H5P_DEFAULT);
if ( herr > 0 && group_data.nfields > 0 ) {
matvar->internal->fieldnames =
(char**)calloc((size_t)(group_data.nfields),sizeof(*matvar->internal->fieldnames));
group_data.nfields = 0;
group_data.matvar = matvar;
if ( matvar->internal->fieldnames != NULL ) {
/* Second iteration to fill fieldnames */
H5Literate_by_name(dset_id, matvar->internal->hdf5_name, H5_INDEX_NAME,
H5_ITER_NATIVE, NULL, Mat_H5ReadGroupInfoIterate,
(void *)&group_data, H5P_DEFAULT);
}
matvar->internal->num_fields = (unsigned)group_data.nfields;
nfields = group_data.nfields;
}
}
}
if ( nfields > 0 ) {
H5O_info_t object_info;
H5OGET_INFO_BY_NAME(dset_id, matvar->internal->fieldnames[0], &object_info, H5P_DEFAULT);
obj_type = object_info.type;
} else {
obj_type = H5O_TYPE_UNKNOWN;
}
if ( obj_type == H5O_TYPE_DATASET ) {
hid_t field_type_id;
field_id = H5Dopen(dset_id,matvar->internal->fieldnames[0],H5P_DEFAULT);
field_type_id = H5Dget_type(field_id);
if ( H5T_REFERENCE == H5Tget_class(field_type_id) ) {
/* Check if the field has the MATLAB_class attribute. If so, it
* means the structure is a scalar. Otherwise, the dimensions of
* the field dataset is the dimensions of the structure
*/
if ( H5Aexists_by_name(field_id,".","MATLAB_class",H5P_DEFAULT) ) {
matvar->rank = 2;
matvar->dims = (size_t*)malloc(2*sizeof(*matvar->dims));
if ( NULL != matvar->dims ) {
matvar->dims[0] = 1;
matvar->dims[1] = 1;
nelems = 1;
} else {
H5Tclose(field_type_id);
H5Dclose(field_id);
Mat_Critical("Error allocating memory for matvar->dims");
return;
}
} else {
matvar->dims = Mat_H5ReadDims(field_id, &nelems, &matvar->rank);
if ( NULL != matvar->dims ) {
fields_are_variables = 0;
} else {
H5Tclose(field_type_id);
H5Dclose(field_id);
return;
}
}
} else {
/* Structure should be a scalar */
matvar->rank = 2;
matvar->dims = (size_t*)malloc(2*sizeof(*matvar->dims));
if ( NULL != matvar->dims ) {
matvar->dims[0] = 1;
matvar->dims[1] = 1;
nelems = 1;
} else {
H5Tclose(field_type_id);
H5Dclose(field_id);
Mat_Critical("Error allocating memory for matvar->dims");
return;
}
}
H5Tclose(field_type_id);
H5Dclose(field_id);
} else {
/* Structure should be a scalar */
matvar->rank = 2;
matvar->dims = (size_t*)malloc(2*sizeof(*matvar->dims));
if ( NULL != matvar->dims ) {
matvar->dims[0] = 1;
matvar->dims[1] = 1;
nelems = 1;
} else {
Mat_Critical("Error allocating memory for matvar->dims");
return;
}
}
if ( nelems < 1 || nfields < 1 )
return;
matvar->data_size = sizeof(*fields);
{
size_t nelems_x_nfields;
SafeMul(&nelems_x_nfields, nelems, nfields);
SafeMul(&matvar->nbytes, nelems_x_nfields, matvar->data_size);
}
fields = (matvar_t**)malloc(matvar->nbytes);
matvar->data = fields;
if ( NULL != fields ) {
int k;
for ( k = 0; k < nfields; k++ ) {
H5O_info_t object_info;
fields[k] = NULL;
H5OGET_INFO_BY_NAME(dset_id, matvar->internal->fieldnames[k], &object_info, H5P_DEFAULT);
if ( object_info.type == H5O_TYPE_DATASET ) {
field_id = H5Dopen(dset_id,matvar->internal->fieldnames[k],
H5P_DEFAULT);
if ( !fields_are_variables ) {
int l;
hobj_ref_t *ref_ids = (hobj_ref_t*)malloc((size_t)nelems*sizeof(*ref_ids));
H5Dread(field_id,H5T_STD_REF_OBJ,H5S_ALL,H5S_ALL,
H5P_DEFAULT,ref_ids);
for ( l = 0; l < nelems; l++ ) {
hid_t ref_id;
ssize_t name_len;
fields[l*nfields+k] = Mat_VarCalloc();
fields[l*nfields+k]->name =
strdup(matvar->internal->fieldnames[k]);
fields[l*nfields+k]->internal->hdf5_ref=ref_ids[l];
/* Get the HDF5 name of the variable */
name_len = H5Iget_name(field_id,NULL,0);
if ( name_len > 0 ) {
fields[l*nfields+k]->internal->hdf5_name =
(char*)malloc(name_len+1);
(void)H5Iget_name(field_id,
fields[l*nfields+k]->internal->hdf5_name,
name_len+1);
}
/* Closing of ref_id is done in Mat_H5ReadNextReferenceInfo */
ref_id = H5RDEREFERENCE(field_id,H5R_OBJECT,ref_ids+l);
fields[l*nfields+k]->internal->id = ref_id;
Mat_H5ReadNextReferenceInfo(ref_id,fields[l*nfields+k],mat);
}
free(ref_ids);
} else {
fields[k] = Mat_VarCalloc();
fields[k]->name = strdup(matvar->internal->fieldnames[k]);
Mat_H5ReadDatasetInfo(mat,fields[k],field_id);
}
H5Dclose(field_id);
} else if ( object_info.type == H5O_TYPE_GROUP ) {
field_id = H5Gopen(dset_id,matvar->internal->fieldnames[k],
H5P_DEFAULT);
if ( -1 < field_id ) {
fields[k] = Mat_VarCalloc();
fields[k]->name = strdup(matvar->internal->fieldnames[k]);
Mat_H5ReadGroupInfo(mat,fields[k],field_id);
H5Gclose(field_id);
}
}
}
}
}
static herr_t
Mat_H5ReadGroupInfoIterate(hid_t dset_id, const char *name, const H5L_info_t *info, void *op_data)
{
matvar_t *matvar;
H5O_info_t object_info;
struct ReadGroupInfoIterData *group_data;
/* FIXME: follow symlinks, datatypes? */
H5OGET_INFO_BY_NAME(dset_id, name, &object_info, H5P_DEFAULT);
if ( H5O_TYPE_DATASET != object_info.type && H5O_TYPE_GROUP != object_info.type )
return 0;
group_data = (struct ReadGroupInfoIterData *)op_data;
if ( group_data == NULL )
return -1;
matvar = group_data->matvar;
switch ( object_info.type ) {
case H5O_TYPE_GROUP:
/* Check that this is not the /#refs# group */
if ( 0 == strcmp(name,"#refs#") )
return 0;
/* Fall through */
case H5O_TYPE_DATASET:
if ( matvar != NULL ) {
matvar->internal->fieldnames[group_data->nfields] = strdup(name);
}
group_data->nfields++;
break;
default:
/* Not possible to get here */
break;
}
return 1;
}
static void
Mat_H5ReadNextReferenceInfo(hid_t ref_id,matvar_t *matvar,mat_t *mat)
{
if( ref_id < 0 || matvar == NULL)
return;
switch ( H5Iget_type(ref_id) ) {
case H5I_DATASET:
Mat_H5ReadDatasetInfo(mat,matvar,ref_id);
if ( matvar->internal->id != ref_id ) {
/* Close dataset and increment count */
H5Dclose(ref_id);
}
/*H5Dclose(ref_id);*/
break;
case H5I_GROUP:
Mat_H5ReadGroupInfo(mat,matvar,ref_id);
break;
default:
break;
}
return;
}
static void
Mat_H5ReadData(hid_t dset_id, hid_t h5_type, hid_t mem_space, hid_t dset_space, int isComplex, void *data)
{
if ( !isComplex ) {
H5Dread(dset_id,h5_type,mem_space,dset_space,H5P_DEFAULT,data);
} else {
mat_complex_split_t *complex_data = (mat_complex_split_t*)data;
hid_t h5_complex;
size_t h5_size = H5Tget_size(h5_type);
h5_complex = H5Tcreate(H5T_COMPOUND, h5_size);
H5Tinsert(h5_complex,"real",0,h5_type);
H5Dread(dset_id,h5_complex,mem_space,dset_space,H5P_DEFAULT,
complex_data->Re);
H5Tclose(h5_complex);
h5_complex = H5Tcreate(H5T_COMPOUND, h5_size);
H5Tinsert(h5_complex,"imag",0,h5_type);
H5Dread(dset_id,h5_complex,mem_space,dset_space,H5P_DEFAULT,
complex_data->Im);
H5Tclose(h5_complex);
}
}
static void
Mat_H5ReadNextReferenceData(hid_t ref_id,matvar_t *matvar,mat_t *mat)
{
size_t nelems = 1;
if ( ref_id < 0 || matvar == NULL )
return;
/* If the datatype with references is a cell, we've already read info into
* the variable data, so just loop over each cell element and call
* Mat_H5ReadNextReferenceData on it.
*/
if ( MAT_C_CELL == matvar->class_type ) {
size_t i;
matvar_t **cells = (matvar_t**)matvar->data;
SafeMulDims(matvar, &nelems);
for ( i = 0; i < nelems; i++ )
Mat_H5ReadNextReferenceData(cells[i]->internal->id,cells[i],mat);
return;
}
switch ( H5Iget_type(ref_id) ) {
case H5I_DATASET:
{
hid_t data_type_id, dset_id;
SafeMulDims(matvar, &nelems);
if ( MAT_C_CHAR == matvar->class_type ) {
matvar->data_type = MAT_T_UINT8;
matvar->data_size = Mat_SizeOf(MAT_T_UINT8);
data_type_id = DataType2H5T(MAT_T_UINT8);
} else if ( MAT_C_STRUCT == matvar->class_type ) {
/* Empty structure array */
break;
} else {
matvar->data_size = Mat_SizeOfClass(matvar->class_type);
data_type_id = ClassType2H5T(matvar->class_type);
}
SafeMul(&matvar->nbytes, nelems, matvar->data_size);
if ( matvar->nbytes < 1 ) {
H5Dclose(ref_id);
break;
}
dset_id = ref_id;
if ( !matvar->isComplex ) {
matvar->data = malloc(matvar->nbytes);
} else {
matvar->data = ComplexMalloc(matvar->nbytes);
}
if ( NULL != matvar->data ) {
Mat_H5ReadData(dset_id, data_type_id,
H5S_ALL, H5S_ALL, matvar->isComplex, matvar->data);
}
H5Dclose(dset_id);
break;
}
case H5I_GROUP:
{
if ( MAT_C_SPARSE == matvar->class_type ) {
Mat_VarRead73(mat,matvar);
} else {
matvar_t **fields;
size_t i;
if ( !matvar->nbytes || !matvar->data_size || NULL == matvar->data )
break;
nelems = matvar->nbytes / matvar->data_size;
fields = (matvar_t**)matvar->data;
for ( i = 0; i < nelems; i++ ) {
if ( 0 < fields[i]->internal->hdf5_ref &&
-1 < fields[i]->internal->id ) {
/* Dataset of references */
Mat_H5ReadNextReferenceData(fields[i]->internal->id,fields[i],mat);
} else {
Mat_VarRead73(mat,fields[i]);
}
}
}
break;
}
default:
break;
}
return;
}
static int
Mat_H5WriteData(hid_t dset_id, hid_t h5_type, hid_t mem_space, hid_t dset_space, int isComplex, void *data)
{
int err = 0;
if ( !isComplex ) {
if ( 0 > H5Dwrite(dset_id,h5_type,mem_space,dset_space,H5P_DEFAULT,data) )
err = 5;
} else {
mat_complex_split_t *complex_data = (mat_complex_split_t*)data;
hid_t h5_complex;
size_t h5_size = H5Tget_size(h5_type);
/* Write real part of dataset */
h5_complex = H5Tcreate(H5T_COMPOUND, h5_size);
H5Tinsert(h5_complex, "real", 0, h5_type);
err = Mat_H5WriteData(dset_id, h5_complex, mem_space, dset_space, 0, complex_data->Re);
H5Tclose(h5_complex);
/* Write imaginary part of dataset */
h5_complex = H5Tcreate(H5T_COMPOUND, h5_size);
H5Tinsert(h5_complex,"imag", 0, h5_type);
err += Mat_H5WriteData(dset_id, h5_complex, mem_space, dset_space, 0, complex_data->Im);
H5Tclose(h5_complex);
}
return err;
}
static int
Mat_H5WriteAppendData(hid_t id, hid_t h5_type, int mrank, const char *name, const size_t* mdims, hsize_t *dims, int dim, int isComplex, void* data)
{
int err = 0;
hid_t dset_id, space_id;
int rank;
if ( dim < 1 || dim > mrank )
return -2;
dset_id = H5Dopen(id, name, H5P_DEFAULT);
space_id = H5Dget_space(dset_id);
rank = H5Sget_simple_extent_ndims(space_id);
if ( rank == mrank ) {
hsize_t* size_offset_dims;
size_offset_dims = (hsize_t*)malloc(rank*sizeof(*size_offset_dims));
if ( NULL != size_offset_dims ) {
hsize_t offset;
hid_t mspace_id;
int k;
(void)H5Sget_simple_extent_dims(space_id,size_offset_dims,NULL);
offset = size_offset_dims[rank - dim];
size_offset_dims[rank - dim] += mdims[dim - 1];
H5Dset_extent(dset_id, size_offset_dims);
for ( k = 0; k < rank; k++ ) {
size_offset_dims[k] = 0;
}
size_offset_dims[rank - dim] = offset;
/* Need to reopen */
H5Sclose(space_id);
space_id = H5Dget_space(dset_id);
H5Sselect_hyperslab(space_id, H5S_SELECT_SET, size_offset_dims,
NULL, dims, NULL);
free(size_offset_dims);
mspace_id = H5Screate_simple(rank, dims, NULL);
err = Mat_H5WriteData(dset_id, h5_type, mspace_id, space_id, isComplex, data);
H5Sclose(mspace_id);
} else {
err = -3;
}
} else {
err = -4;
}
H5Sclose(space_id);
H5Dclose(dset_id);
return err;
}
static int
Mat_VarWriteRef(hid_t id, matvar_t* matvar, enum matio_compression compression, hid_t *refs_id, hobj_ref_t* ref)
{
int err;
char obj_name[64];
H5G_info_t group_info;
H5Gget_info(*refs_id, &group_info);
sprintf(obj_name,"%llu", group_info.nlinks);
if ( NULL != matvar )
matvar->compression = compression;
err = Mat_VarWriteNext73(*refs_id, matvar, obj_name, refs_id);
sprintf(obj_name, "/#refs#/%llu", group_info.nlinks);
H5Rcreate(ref, id, obj_name, H5R_OBJECT, -1);
return err;
}
static int
Mat_VarWriteEmpty(hid_t id,matvar_t *matvar,const char *name,const char* class_name)
{
int err = 0;
hsize_t rank = matvar->rank;
unsigned empty = 1;
hid_t mspace_id, dset_id, attr_type_id, aspace_id, attr_id;
mspace_id = H5Screate_simple(1,&rank,NULL);
dset_id = H5Dcreate(id,name,H5T_NATIVE_HSIZE,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id, strlen(class_name));
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id, attr_type_id, class_name) )
err = 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
H5Tclose(attr_type_id);
if ( 0 == strcmp(class_name, "struct") ) {
/* Write the fields attribute */
hsize_t nfields = matvar->internal->num_fields;
if ( nfields ) {
hvl_t *fieldnames = (hvl_t*)malloc((size_t)nfields*sizeof(*fieldnames));
if ( NULL != fieldnames ) {
hid_t str_type_id,fieldnames_id;
hsize_t k;
str_type_id = H5Tcopy(H5T_C_S1);
for ( k = 0; k < nfields; k++ ) {
fieldnames[k].len =
strlen(matvar->internal->fieldnames[k]);
fieldnames[k].p = matvar->internal->fieldnames[k];
}
H5Tset_size(str_type_id,1);
fieldnames_id = H5Tvlen_create(str_type_id);
aspace_id = H5Screate_simple(1,&nfields,NULL);
attr_id = H5Acreate(dset_id,"MATLAB_fields",fieldnames_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,fieldnames_id,fieldnames) )
err += 5;
H5Aclose(attr_id);
H5Sclose(aspace_id);
H5Tclose(fieldnames_id);
H5Tclose(str_type_id);
free(fieldnames);
} else {
err = 1;
}
}
} else if ( 0 == strcmp(class_name, "logical") ) {
/* Write the MATLAB_int_decode attribute */
int int_decode = 1;
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_int_decode",H5T_NATIVE_INT,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,H5T_NATIVE_INT,&int_decode) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
}
/* Write the empty attribute */
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_empty",H5T_NATIVE_UINT,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,H5T_NATIVE_UINT,&empty) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
/* Write the dimensions as the data */
if ( 0 > H5Dwrite(dset_id,SizeType2H5T(),H5S_ALL,H5S_ALL,
H5P_DEFAULT,matvar->dims) )
err += 5;
H5Dclose(dset_id);
H5Sclose(mspace_id);
return err;
}
/** @if mat_devman
* @brief Writes a cell array matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the cell array variable
* @param name Name of the HDF dataset
* @param refs_id pointer to the id of the /#refs# group in HDF5
* @param dims array of permuted dimensions
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteCell73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,hsize_t *dims)
{
int k;
hsize_t nelems = 1;
matvar_t **cells;
int err = 0;
cells = (matvar_t**)matvar->data;
for ( k = 0; k < matvar->rank; k++ )
nelems *= dims[k];
if ( 0 == nelems || NULL == matvar->data ) {
err = Mat_VarWriteEmpty(id, matvar, name, ClassNames[matvar->class_type]);
} else {
if ( *refs_id < 0 ) {
if ( H5Lexists(id,"/#refs#",H5P_DEFAULT) ) {
*refs_id = H5Gopen(id,"/#refs#",H5P_DEFAULT);
} else {
*refs_id = H5Gcreate(id,"/#refs#",H5P_DEFAULT,
H5P_DEFAULT,H5P_DEFAULT);
}
}
if ( *refs_id > -1 ) {
hobj_ref_t *refs;
hid_t str_type_id,mspace_id,dset_id,attr_id,aspace_id;
refs = (hobj_ref_t*)malloc((size_t)nelems*sizeof(*refs));
mspace_id = H5Screate_simple(matvar->rank,dims,NULL);
dset_id = H5Dcreate(id,name,H5T_STD_REF_OBJ,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
for ( k = 0; k < nelems; k++ ) {
err += Mat_VarWriteRef(id, cells[k], matvar->compression,
refs_id, refs+k);
}
err += Mat_H5WriteData(dset_id, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL,
0, refs);
str_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(str_type_id,4);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",str_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,str_type_id,"cell") )
err += 5;
H5Aclose(attr_id);
H5Sclose(aspace_id);
H5Tclose(str_type_id);
H5Dclose(dset_id);
free(refs);
H5Sclose(mspace_id);
} else {
err = -1;
}
}
return err;
}
/** @if mat_devman
* @brief Writes a character matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the character variable
* @param name Name of the HDF dataset
* @param dims array of permuted dimensions
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteChar73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims)
{
int err = 0, k;
hsize_t nelems = 1;
for ( k = 0; k < matvar->rank; k++ ) {
nelems *= dims[k];
}
if ( 0 == nelems || NULL == matvar->data ) {
err = Mat_VarWriteEmpty(id, matvar, name, ClassNames[matvar->class_type]);
} else {
int matlab_int_decode = 2;
hid_t mspace_id,dset_id,attr_type_id,attr_id,aspace_id;
mspace_id = H5Screate_simple(matvar->rank,dims,NULL);
switch ( matvar->data_type ) {
case MAT_T_UTF32:
case MAT_T_INT32:
case MAT_T_UINT32:
/* Not sure matlab will actually handle this */
dset_id = H5Dcreate(id,name,
ClassType2H5T(MAT_C_UINT32),
mspace_id,H5P_DEFAULT,H5P_DEFAULT,
H5P_DEFAULT);
break;
case MAT_T_UTF16:
case MAT_T_UTF8:
case MAT_T_INT16:
case MAT_T_UINT16:
case MAT_T_INT8:
case MAT_T_UINT8:
dset_id = H5Dcreate(id,name,
ClassType2H5T(MAT_C_UINT16),
mspace_id,H5P_DEFAULT,H5P_DEFAULT,
H5P_DEFAULT);
break;
default:
H5Sclose(mspace_id);
return -1;
}
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id, strlen(ClassNames[matvar->class_type]));
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,attr_type_id,ClassNames[matvar->class_type]) )
err = 5;
H5Aclose(attr_id);
H5Tclose(attr_type_id);
attr_type_id = H5Tcopy(H5T_NATIVE_INT);
attr_id = H5Acreate(dset_id,"MATLAB_int_decode",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,attr_type_id,&matlab_int_decode) )
err += 5;
H5Aclose(attr_id);
H5Tclose(attr_type_id);
H5Sclose(aspace_id);
if ( 0 > H5Dwrite(dset_id,DataType2H5T(matvar->data_type),
H5S_ALL,H5S_ALL,H5P_DEFAULT,matvar->data) )
err += 5;
H5Dclose(dset_id);
H5Sclose(mspace_id);
}
return err;
}
static int
Mat_WriteEmptyVariable73(hid_t id,const char *name,hsize_t rank,size_t *dims)
{
int err = 0;
unsigned empty = 1;
hid_t mspace_id,dset_id;
mspace_id = H5Screate_simple(1,&rank,NULL);
dset_id = H5Dcreate(id,name,H5T_NATIVE_HSIZE,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
if ( dset_id > -1 ) {
hid_t attr_type_id,attr_id,aspace_id;
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id,6);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,attr_type_id,"double") )
err = 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
H5Tclose(attr_type_id);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_empty",H5T_NATIVE_UINT,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,H5T_NATIVE_UINT,&empty) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
/* Write the dimensions as the data */
if ( 0 > H5Dwrite(dset_id,SizeType2H5T(),H5S_ALL,H5S_ALL,
H5P_DEFAULT,dims) )
err += 5;
H5Dclose(dset_id);
} else {
err = -1;
}
H5Sclose(mspace_id);
return err;
}
/** @if mat_devman
* @brief Writes a logical matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the logical variable
* @param name Name of the HDF dataset
* @param dims array of permuted dimensions
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteLogical73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims)
{
int err = 0, k;
hsize_t nelems = 1;
hid_t plist;
for ( k = 0; k < matvar->rank; k++ ) {
nelems *= dims[k];
}
if ( matvar->compression == MAT_COMPRESSION_ZLIB ) {
plist = H5Pcreate(H5P_DATASET_CREATE);
if ( MAX_RANK >= matvar->rank ) {
hsize_t chunk_dims[MAX_RANK];
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
} else {
hsize_t *chunk_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != chunk_dims ) {
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
free(chunk_dims);
} else {
H5Pclose(plist);
return -1;
}
}
H5Pset_deflate(plist, 9);
} else {
plist = H5P_DEFAULT;
}
if ( 0 == nelems || NULL == matvar->data ) {
err = Mat_VarWriteEmpty(id, matvar, name, "logical");
} else {
int int_decode = 1;
hid_t mspace_id,dset_id,attr_type_id,attr_id,aspace_id;
mspace_id = H5Screate_simple(matvar->rank,dims,NULL);
/* Note that MATLAB only recognizes uint8 as logical */
dset_id = H5Dcreate(id,name,
ClassType2H5T(MAT_C_UINT8),
mspace_id,H5P_DEFAULT,plist,H5P_DEFAULT);
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id,7);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,attr_type_id,"logical") )
err = 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
H5Tclose(attr_type_id);
/* Write the MATLAB_int_decode attribute */
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_int_decode",H5T_NATIVE_INT,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,H5T_NATIVE_INT,&int_decode) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
if ( 0 > H5Dwrite(dset_id,DataType2H5T(matvar->data_type),
H5S_ALL,H5S_ALL,H5P_DEFAULT,matvar->data) )
err += 5;
H5Dclose(dset_id);
H5Sclose(mspace_id);
}
if ( H5P_DEFAULT != plist )
H5Pclose(plist);
return err;
}
/** @if mat_devman
* @brief Writes a numeric matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the numeric variable
* @param name Name of the HDF dataset
* @param dims array of permuted dimensions
* @param max_dims maximum dimensions
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteNumeric73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims,hsize_t* max_dims)
{
int err = 0, k;
hsize_t nelems = 1;
hid_t plist;
for ( k = 0; k < matvar->rank; k++ ) {
nelems *= dims[k];
}
if ( matvar->compression || NULL != max_dims ) {
plist = H5Pcreate(H5P_DATASET_CREATE);
if ( MAX_RANK >= matvar->rank ) {
hsize_t chunk_dims[MAX_RANK];
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
} else {
hsize_t *chunk_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != chunk_dims ) {
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
free(chunk_dims);
} else {
H5Pclose(plist);
return -1;
}
}
if ( matvar->compression == MAT_COMPRESSION_ZLIB )
H5Pset_deflate(plist, 9);
} else {
plist = H5P_DEFAULT;
}
if ( 0 == nelems || NULL == matvar->data ) {
err = Mat_VarWriteEmpty(id, matvar, name, ClassNames[matvar->class_type]);
} else {
hid_t mspace_id,dset_id,attr_type_id,attr_id,aspace_id;
hid_t h5_type = ClassType2H5T(matvar->class_type);
hid_t h5_dtype = DataType(h5_type, matvar->isComplex);
mspace_id = H5Screate_simple(matvar->rank,dims,max_dims);
dset_id = H5Dcreate(id,name,h5_dtype,mspace_id,
H5P_DEFAULT,plist,H5P_DEFAULT);
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id, strlen(ClassNames[matvar->class_type]));
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(dset_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id, attr_type_id, ClassNames[matvar->class_type]) )
err = 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
H5Tclose(attr_type_id);
H5Tclose(h5_dtype);
err += Mat_H5WriteData(dset_id, h5_type, H5S_ALL, H5S_ALL,
matvar->isComplex, matvar->data);
H5Dclose(dset_id);
H5Sclose(mspace_id);
}
if ( H5P_DEFAULT != plist )
H5Pclose(plist);
return err;
}
/** @if mat_devman
* @brief Writes/appends a numeric matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the numeric variable
* @param name Name of the HDF dataset
* @param dims array of permuted dimensions
* @param dim dimension to append data
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteAppendNumeric73(hid_t id,matvar_t *matvar,const char *name,hsize_t *dims,int dim)
{
int err = 0, k;
hsize_t nelems = 1;
for ( k = 0; k < matvar->rank; k++ ) {
nelems *= dims[k];
}
if ( 0 != nelems && NULL != matvar->data ) {
if ( H5Lexists(id, matvar->name, H5P_DEFAULT) ) {
err = Mat_H5WriteAppendData(id, ClassType2H5T(matvar->class_type), matvar->rank,
matvar->name, matvar->dims, dims, dim, matvar->isComplex, matvar->data);
} else {
/* Create with unlimited number of dimensions */
if ( MAX_RANK >= matvar->rank ) {
hsize_t max_dims[MAX_RANK];
for ( k = 0; k < matvar->rank; k++ ) {
max_dims[k] = H5S_UNLIMITED;
}
err = Mat_VarWriteNumeric73(id, matvar, name, dims, max_dims);
} else {
hsize_t* max_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != max_dims ) {
for ( k = 0; k < matvar->rank; k++ ) {
max_dims[k] = H5S_UNLIMITED;
}
err = Mat_VarWriteNumeric73(id, matvar, name, dims, max_dims);
free(max_dims);
} else {
err = -1;
}
}
}
} else {
err = -1;
}
return err;
}
/** @if mat_devman
* @brief Writes a sparse matrix variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the structure variable
* @param name Name of the HDF dataset
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteSparse73(hid_t id,matvar_t *matvar,const char *name)
{
int err = 0;
hid_t sparse_id;
sparse_id = H5Gcreate(id,name,H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
if ( sparse_id < 0 ) {
Mat_Critical("Error creating group for sparse array %s",
matvar->name);
err = -1;
} else {
hid_t size_type_id,h5_type,h5_dtype;
hid_t mspace_id,dset_id,attr_type_id,attr_id,aspace_id;
mat_sparse_t *sparse;
hsize_t nir, njc, ndata;
mat_uint64_t sparse_attr_value;
enum matio_classes class_type;
sparse = (mat_sparse_t*)matvar->data;
class_type = DataType2ClassType(matvar->data_type);
attr_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(attr_type_id,
matvar->isLogical ? 7 : strlen(ClassNames[class_type]));
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(sparse_id,"MATLAB_class",attr_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id, attr_type_id,
matvar->isLogical ? "logical" : ClassNames[class_type]) )
err = 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
H5Tclose(attr_type_id);
if ( matvar->isLogical ) {
/* Write the MATLAB_int_decode attribute */
int int_decode = 1;
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(sparse_id, "MATLAB_int_decode", H5T_NATIVE_INT,
aspace_id, H5P_DEFAULT, H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id, H5T_NATIVE_INT, &int_decode) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
}
sparse_attr_value = matvar->dims[0];
size_type_id = ClassType2H5T(MAT_C_UINT64);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(sparse_id,"MATLAB_sparse",size_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,size_type_id,&sparse_attr_value) )
err += 5;
H5Sclose(aspace_id);
H5Aclose(attr_id);
ndata = sparse->ndata;
h5_type = DataType2H5T(matvar->data_type);
h5_dtype = DataType(h5_type, matvar->isComplex);
mspace_id = H5Screate_simple(1,&ndata,NULL);
dset_id = H5Dcreate(sparse_id,"data",h5_dtype,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
H5Tclose(h5_dtype);
err += Mat_H5WriteData(dset_id, h5_type, H5S_ALL, H5S_ALL,
matvar->isComplex, sparse->data);
H5Dclose(dset_id);
H5Sclose(mspace_id);
nir = sparse->nir;
mspace_id = H5Screate_simple(1,&nir,NULL);
dset_id = H5Dcreate(sparse_id,"ir",size_type_id,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
err += Mat_H5WriteData(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
0, sparse->ir);
H5Dclose(dset_id);
H5Sclose(mspace_id);
njc = sparse->njc;
mspace_id = H5Screate_simple(1,&njc,NULL);
dset_id = H5Dcreate(sparse_id,"jc",size_type_id,mspace_id,
H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
err += Mat_H5WriteData(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
0, sparse->jc);
H5Dclose(dset_id);
H5Sclose(mspace_id);
H5Gclose(sparse_id);
}
return err;
}
/** @if mat_devman
* @brief Writes a structure matlab variable to the specified HDF id with the
* given name
*
* @ingroup mat_internal
* @param id HDF id of the parent object
* @param matvar pointer to the structure variable
* @param name Name of the HDF dataset
* @param refs_id pointer to the id of the /#refs# group in HDF5
* @param dims array of permuted dimensions
* @param max_dims maximum dimensions
* @retval 0 on success
* @endif
*/
static int
Mat_VarWriteStruct73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,hsize_t *dims,hsize_t* max_dims)
{
int err = 0, k;
hsize_t nelems;
{
size_t tmp = 1;
SafeMulDims(matvar, &tmp);
nelems = (hsize_t)tmp;
}
if ( 0 == nelems || NULL == matvar->data ) {
err = Mat_VarWriteEmpty(id, matvar, name, ClassNames[matvar->class_type]);
} else {
hid_t struct_id = H5Gcreate(id,name,H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
if ( struct_id < 0 ) {
Mat_Critical("Error creating group for struct %s",name);
err = -1;
} else {
hid_t attr_id,aspace_id;
hid_t str_type_id,fieldnames_id;
matvar_t **fields = (matvar_t**)matvar->data;
hvl_t *fieldnames;
hsize_t nfields = matvar->internal->num_fields;
str_type_id = H5Tcopy(H5T_C_S1);
H5Tset_size(str_type_id,6);
aspace_id = H5Screate(H5S_SCALAR);
attr_id = H5Acreate(struct_id,"MATLAB_class",str_type_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,str_type_id,"struct") )
err = 5;
H5Aclose(attr_id);
H5Sclose(aspace_id);
/* Structure with no fields */
if ( nfields == 0 ) {
H5Gclose(struct_id);
H5Tclose(str_type_id);
return err;
}
fieldnames = (hvl_t*)malloc((size_t)nfields*sizeof(*fieldnames));
for ( k = 0; k < nfields; k++ ) {
fieldnames[k].len =
strlen(matvar->internal->fieldnames[k]);
fieldnames[k].p = matvar->internal->fieldnames[k];
}
H5Tset_size(str_type_id,1);
fieldnames_id = H5Tvlen_create(str_type_id);
aspace_id = H5Screate_simple(1,&nfields,NULL);
attr_id = H5Acreate(struct_id,"MATLAB_fields",fieldnames_id,
aspace_id,H5P_DEFAULT,H5P_DEFAULT);
if ( 0 > H5Awrite(attr_id,fieldnames_id,fieldnames) )
err += 5;
H5Aclose(attr_id);
H5Sclose(aspace_id);
H5Tclose(fieldnames_id);
H5Tclose(str_type_id);
free(fieldnames);
if ( 1 == nelems && NULL == max_dims ) {
for ( k = 0; k < nfields; k++ ) {
if ( NULL != fields[k] )
fields[k]->compression = matvar->compression;
if ( 0 != Mat_VarWriteNext73(struct_id,fields[k],
matvar->internal->fieldnames[k],refs_id) )
err += 5;
}
} else {
if ( *refs_id < 0 ) {
if ( H5Lexists(id,"/#refs#",H5P_DEFAULT) ) {
*refs_id = H5Gopen(id,"/#refs#",H5P_DEFAULT);
} else {
*refs_id = H5Gcreate(id,"/#refs#",H5P_DEFAULT,
H5P_DEFAULT,H5P_DEFAULT);
}
}
if ( *refs_id > -1 ) {
hobj_ref_t **refs;
int l;
hid_t plist,mspace_id,dset_id;
refs = (hobj_ref_t**)malloc((size_t)nfields*sizeof(*refs));
for ( l = 0; l < nfields; l++ )
refs[l] = (hobj_ref_t*)malloc((size_t)nelems*sizeof(*refs[l]));
for ( k = 0; k < nelems; k++ ) {
for ( l = 0; l < nfields; l++ ) {
err += Mat_VarWriteRef(id, fields[k*nfields+l], matvar->compression,
refs_id, refs[l]+k);
}
}
if ( NULL != max_dims ) {
plist = H5Pcreate(H5P_DATASET_CREATE);
if ( MAX_RANK >= matvar->rank ) {
hsize_t chunk_dims[MAX_RANK];
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
} else {
hsize_t *chunk_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != chunk_dims ) {
Mat_H5GetChunkSize(matvar->rank, dims, chunk_dims);
H5Pset_chunk(plist, matvar->rank, chunk_dims);
free(chunk_dims);
} else {
H5Pclose(plist);
plist = H5P_DEFAULT;
}
}
} else {
plist = H5P_DEFAULT;
}
mspace_id = H5Screate_simple(matvar->rank,dims,max_dims);
for ( l = 0; l < nfields; l++ ) {
dset_id = H5Dcreate(struct_id,
matvar->internal->fieldnames[l],
H5T_STD_REF_OBJ,mspace_id,
H5P_DEFAULT,plist,H5P_DEFAULT);
err += Mat_H5WriteData(dset_id, H5T_STD_REF_OBJ, H5S_ALL,
H5S_ALL, 0, refs[l]);
H5Dclose(dset_id);
free(refs[l]);
}
free(refs);
H5Sclose(mspace_id);
if ( H5P_DEFAULT != plist )
H5Pclose(plist);
} else {
err = -1;
}
}
H5Gclose(struct_id);
}
}
return err;
}
static int
Mat_VarWriteAppendStruct73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,hsize_t *dims,int dim)
{
int err = 0, k;
hsize_t nelems = 1;
for ( k = 0; k < matvar->rank; k++ ) {
nelems *= dims[k];
}
if ( 0 != nelems && NULL != matvar->data ) {
if ( H5Lexists(id, name, H5P_DEFAULT) ) {
hid_t struct_id;
hobj_ref_t **refs;
int l;
hsize_t nfields = matvar->internal->num_fields;
matvar_t** fields = (matvar_t**)matvar->data;
if ( *refs_id <= -1 )
return -3;
refs = (hobj_ref_t**)malloc((size_t)nfields*sizeof(*refs));
for ( l = 0; l < nfields; l++ )
refs[l] = (hobj_ref_t*)malloc((size_t)nelems*sizeof(*refs[l]));
for ( k = 0; k < nelems; k++ ) {
for ( l = 0; l < nfields; l++ ) {
err += Mat_VarWriteRef(id, fields[k*nfields+l], matvar->compression,
refs_id, refs[l]+k);
}
}
struct_id = H5Gopen(id, name, H5P_DEFAULT);
for ( l = 0; l < nfields; l++ ) {
err += Mat_H5WriteAppendData(struct_id, H5T_STD_REF_OBJ, matvar->rank,
matvar->internal->fieldnames[l], matvar->dims, dims, dim, 0, refs[l]);
free(refs[l]);
}
free(refs);
H5Gclose(struct_id);
} else {
/* Create with unlimited number of dimensions */
if ( MAX_RANK >= matvar->rank ) {
hsize_t max_dims[MAX_RANK];
for ( k = 0; k < matvar->rank; k++ ) {
max_dims[k] = H5S_UNLIMITED;
}
err = Mat_VarWriteStruct73(id,matvar,name,refs_id,dims,max_dims);
} else {
hsize_t* max_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != max_dims ) {
for ( k = 0; k < matvar->rank; k++ ) {
max_dims[k] = H5S_UNLIMITED;
}
err = Mat_VarWriteStruct73(id,matvar,name,refs_id,dims,max_dims);
free(max_dims);
} else {
err = -1;
}
}
}
}
return err;
}
static int
Mat_VarWriteNext73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id)
{
int err = -1;
if ( NULL == matvar ) {
size_t dims[2] = {0,0};
return Mat_WriteEmptyVariable73(id,name,2,dims);
}
if ( MAX_RANK >= matvar->rank ) {
hsize_t perm_dims[MAX_RANK];
err = Mat_VarWriteNextType73(id, matvar, name, refs_id, perm_dims);
} else {
hsize_t *perm_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != perm_dims ) {
err = Mat_VarWriteNextType73(id, matvar, name, refs_id, perm_dims);
free(perm_dims);
}
}
return err;
}
static int
Mat_VarWriteAppendNext73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,int dim)
{
int err = -1;
if ( MAX_RANK >= matvar->rank ) {
hsize_t perm_dims[MAX_RANK];
err = Mat_VarWriteAppendNextType73(id, matvar, name, refs_id, perm_dims, dim);
} else {
hsize_t *perm_dims = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL != perm_dims ) {
err = Mat_VarWriteAppendNextType73(id, matvar, name, refs_id, perm_dims, dim);
free(perm_dims);
}
}
return err;
}
static int
Mat_VarWriteNextType73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,hsize_t *dims)
{
int err = -1, k;
/* Permute dimensions */
for ( k = 0; k < matvar->rank; k++ ) {
dims[k] = matvar->dims[matvar->rank - k - 1];
}
if ( matvar->isLogical && matvar->class_type != MAT_C_SPARSE ) {
err = Mat_VarWriteLogical73(id,matvar,name,dims);
} else {
switch ( matvar->class_type ) {
case MAT_C_DOUBLE:
case MAT_C_SINGLE:
case MAT_C_INT64:
case MAT_C_UINT64:
case MAT_C_INT32:
case MAT_C_UINT32:
case MAT_C_INT16:
case MAT_C_UINT16:
case MAT_C_INT8:
case MAT_C_UINT8:
err = Mat_VarWriteNumeric73(id,matvar,name,dims,NULL);
break;
case MAT_C_CHAR:
err = Mat_VarWriteChar73(id,matvar,name,dims);
break;
case MAT_C_STRUCT:
err = Mat_VarWriteStruct73(id,matvar,name,refs_id,dims,NULL);
break;
case MAT_C_CELL:
err = Mat_VarWriteCell73(id,matvar,name,refs_id,dims);
break;
case MAT_C_SPARSE:
err = Mat_VarWriteSparse73(id,matvar,name);
break;
case MAT_C_EMPTY:
err = Mat_WriteEmptyVariable73(id,name,matvar->rank,matvar->dims);
break;
case MAT_C_FUNCTION:
case MAT_C_OBJECT:
case MAT_C_OPAQUE:
break;
}
}
return err;
}
static int
Mat_VarWriteAppendNextType73(hid_t id,matvar_t *matvar,const char *name,hid_t *refs_id,hsize_t *dims,int dim)
{
int err = -1, k;
/* Permute dimensions */
for ( k = 0; k < matvar->rank; k++ ) {
dims[k] = matvar->dims[matvar->rank - k - 1];
}
if ( !matvar->isLogical ) {
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:
err = Mat_VarWriteAppendNumeric73(id,matvar,name,dims,dim);
break;
case MAT_C_STRUCT:
err = Mat_VarWriteAppendStruct73(id,matvar,name,refs_id,dims,dim);
break;
case MAT_C_EMPTY:
case MAT_C_CHAR:
case MAT_C_CELL:
case MAT_C_SPARSE:
case MAT_C_FUNCTION:
case MAT_C_OBJECT:
case MAT_C_OPAQUE:
err = Mat_VarWriteNextType73(id,matvar,name,refs_id,dims);
break;
}
}
return err;
}
/** @if mat_devman
* @brief Creates a new Matlab MAT version 7.3 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_internal
* @param matname Name of MAT file to create
* @param hdr_str Optional header string, NULL to use default
* @return A pointer to the MAT file or NULL if it failed. This is not a
* simple FILE * and should not be used as one.
* @endif
*/
mat_t *
Mat_Create73(const char *matname,const char *hdr_str)
{
FILE *fp;
mat_int16_t endian = 0, version;
mat_t *mat = NULL;
size_t err;
time_t t;
hid_t plist_id,fid,plist_ap;
plist_id = H5Pcreate(H5P_FILE_CREATE);
H5Pset_userblock(plist_id,512);
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
fid = H5Fcreate(matname,H5F_ACC_TRUNC,plist_id,plist_ap);
H5Fclose(fid);
H5Pclose(plist_id);
fp = fopen(matname,"r+b");
if ( !fp ) {
H5Pclose(plist_ap);
return NULL;
}
(void)fseek(fp,0,SEEK_SET);
mat = (mat_t*)malloc(sizeof(*mat));
if ( mat == NULL ) {
fclose(fp);
H5Pclose(plist_ap);
return NULL;
}
mat->fp = NULL;
mat->header = NULL;
mat->subsys_offset = NULL;
mat->filename = NULL;
mat->version = 0;
mat->byteswap = 0;
mat->mode = 0;
mat->bof = 128;
mat->next_index = 0;
mat->num_datasets = 0;
mat->refs_id = -1;
mat->dir = NULL;
t = time(NULL);
mat->filename = strdup_printf("%s",matname);
mat->mode = MAT_ACC_RDWR;
mat->byteswap = 0;
mat->header = (char*)malloc(128*sizeof(char));
mat->subsys_offset = (char*)malloc(8*sizeof(char));
memset(mat->header,' ',128);
if ( hdr_str == NULL ) {
err = mat_snprintf(mat->header,116,"MATLAB 7.3 MAT-file, Platform: %s, "
"Created by: libmatio v%d.%d.%d on %s HDF5 schema 0.5",
MATIO_PLATFORM, MATIO_MAJOR_VERSION, MATIO_MINOR_VERSION,
MATIO_RELEASE_LEVEL, ctime(&t));
} else {
err = mat_snprintf(mat->header,116,"%s",hdr_str);
}
if ( err >= 116 )
mat->header[115] = '\0'; /* Just to make sure it's NULL terminated */
memset(mat->subsys_offset,' ',8);
mat->version = (int)0x0200;
endian = 0x4d49;
version = 0x0200;
fwrite(mat->header,1,116,fp);
fwrite(mat->subsys_offset,1,8,fp);
fwrite(&version,2,1,fp);
fwrite(&endian,2,1,fp);
fclose(fp);
fid = H5Fopen(matname,H5F_ACC_RDWR,plist_ap);
H5Pclose(plist_ap);
mat->fp = malloc(sizeof(hid_t));
*(hid_t*)mat->fp = fid;
return mat;
}
/** @if mat_devman
* @brief Reads the MAT variable identified by matvar
*
* @ingroup mat_internal
* @param mat MAT file pointer
* @param matvar MAT variable pointer
* @endif
*/
void
Mat_VarRead73(mat_t *mat,matvar_t *matvar)
{
hid_t fid,dset_id,ref_id;
if ( NULL == mat || NULL == matvar )
return;
else if ( NULL == matvar->internal->hdf5_name && 0 > matvar->internal->id )
return;
fid = *(hid_t*)mat->fp;
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:
{
size_t nelems = 1;
SafeMulDims(matvar, &nelems);
matvar->data_size = Mat_SizeOfClass(matvar->class_type);
SafeMul(&matvar->nbytes, nelems, matvar->data_size);
if ( nelems < 1 )
break;
if ( NULL != matvar->internal->hdf5_name ) {
ref_id = H5Dopen(fid,matvar->internal->hdf5_name,H5P_DEFAULT);
} else {
ref_id = matvar->internal->id;
H5Iinc_ref(ref_id);
}
if ( 0 < matvar->internal->hdf5_ref ) {
dset_id = H5RDEREFERENCE(ref_id,H5R_OBJECT,&matvar->internal->hdf5_ref);
} else {
dset_id = ref_id;
H5Iinc_ref(dset_id);
}
if ( !matvar->isComplex ) {
matvar->data = malloc(matvar->nbytes);
} else {
matvar->data = ComplexMalloc(matvar->nbytes);
}
if ( NULL != matvar->data ) {
Mat_H5ReadData(dset_id, ClassType2H5T(matvar->class_type),
H5S_ALL, H5S_ALL, matvar->isComplex, matvar->data);
}
H5Dclose(dset_id);
H5Dclose(ref_id);
break;
}
case MAT_C_CHAR:
{
size_t nelems = 1;
SafeMulDims(matvar, &nelems);
matvar->data_size = Mat_SizeOf(matvar->data_type);
SafeMul(&matvar->nbytes, nelems, matvar->data_size);
if ( NULL != matvar->internal->hdf5_name ) {
dset_id = H5Dopen(fid,matvar->internal->hdf5_name,H5P_DEFAULT);
} else {
dset_id = matvar->internal->id;
H5Iinc_ref(dset_id);
}
if ( matvar->nbytes > 0 ) {
matvar->data = malloc(matvar->nbytes);
if ( NULL != matvar->data ) {
H5Dread(dset_id,DataType2H5T(matvar->data_type),
H5S_ALL,H5S_ALL,H5P_DEFAULT,matvar->data);
}
}
H5Dclose(dset_id);
break;
}
case MAT_C_STRUCT:
{
matvar_t **fields;
size_t i, nelems_x_nfields, nelems = 1;
if ( !matvar->internal->num_fields || NULL == matvar->data )
break;
SafeMulDims(matvar, &nelems);
SafeMul(&nelems_x_nfields, nelems, matvar->internal->num_fields);
fields = (matvar_t**)matvar->data;
for ( i = 0; i < nelems_x_nfields; i++ ) {
if ( 0 < fields[i]->internal->hdf5_ref &&
-1 < fields[i]->internal->id ) {
/* Dataset of references */
Mat_H5ReadNextReferenceData(fields[i]->internal->id,fields[i],mat);
} else {
Mat_VarRead73(mat,fields[i]);
}
}
break;
}
case MAT_C_CELL:
{
matvar_t **cells;
size_t i, nelems = 0;
nelems = matvar->nbytes / matvar->data_size;
cells = (matvar_t**)matvar->data;
for ( i = 0; i < nelems; i++ )
Mat_H5ReadNextReferenceData(cells[i]->internal->id,cells[i],mat);
break;
}
case MAT_C_SPARSE:
{
hid_t sparse_dset_id;
mat_sparse_t *sparse_data = (mat_sparse_t *)calloc(1,
sizeof(*sparse_data));
if ( NULL != matvar->internal->hdf5_name ) {
dset_id = H5Gopen(fid,matvar->internal->hdf5_name,H5P_DEFAULT);
} else {
dset_id = matvar->internal->id;
H5Iinc_ref(dset_id);
}
if ( H5Lexists(dset_id,"ir",H5P_DEFAULT) ) {
size_t *dims;
hsize_t nelems;
int rank;
sparse_dset_id = H5Dopen(dset_id,"ir",H5P_DEFAULT);
dims = Mat_H5ReadDims(sparse_dset_id, &nelems, &rank);
if ( NULL != dims ) {
sparse_data->nir = dims[0];
free(dims);
sparse_data->ir = (int*)malloc(sparse_data->nir*
sizeof(*sparse_data->ir));
H5Dread(sparse_dset_id,H5T_NATIVE_INT,
H5S_ALL,H5S_ALL,H5P_DEFAULT,sparse_data->ir);
}
H5Dclose(sparse_dset_id);
}
if ( H5Lexists(dset_id,"jc",H5P_DEFAULT) ) {
size_t *dims;
hsize_t nelems;
int rank;
sparse_dset_id = H5Dopen(dset_id,"jc",H5P_DEFAULT);
dims = Mat_H5ReadDims(sparse_dset_id, &nelems, &rank);
if ( NULL != dims ) {
sparse_data->njc = dims[0];
free(dims);
sparse_data->jc = (int*)malloc(sparse_data->njc*
sizeof(*sparse_data->jc));
H5Dread(sparse_dset_id,H5T_NATIVE_INT,
H5S_ALL,H5S_ALL,H5P_DEFAULT,sparse_data->jc);
}
H5Dclose(sparse_dset_id);
}
if ( H5Lexists(dset_id,"data",H5P_DEFAULT) ) {
size_t *dims;
hsize_t nelems;
int rank;
sparse_dset_id = H5Dopen(dset_id,"data",H5P_DEFAULT);
dims = Mat_H5ReadDims(sparse_dset_id, &nelems, &rank);
if ( NULL != dims ) {
size_t ndata_bytes;
sparse_data->nzmax = dims[0];
sparse_data->ndata = dims[0];
free(dims);
matvar->data_size = sizeof(mat_sparse_t);
matvar->nbytes = matvar->data_size;
ndata_bytes = sparse_data->nzmax*Mat_SizeOf(matvar->data_type);
if ( !matvar->isComplex ) {
sparse_data->data = malloc(ndata_bytes);
} else {
sparse_data->data = ComplexMalloc(ndata_bytes);
}
if ( NULL != sparse_data->data ) {
Mat_H5ReadData(sparse_dset_id, DataType2H5T(matvar->data_type),
H5S_ALL, H5S_ALL, matvar->isComplex, sparse_data->data);
}
}
H5Dclose(sparse_dset_id);
}
H5Gclose(dset_id);
matvar->data = sparse_data;
break;
}
case MAT_C_EMPTY:
case MAT_C_FUNCTION:
case MAT_C_OBJECT:
case MAT_C_OPAQUE:
break;
}
}
/** @if mat_devman
* @brief Reads a slab of data from the mat variable @c matvar
*
* @ingroup mat_internal
* @param mat MAT file pointer
* @param matvar pointer to the mat variable
* @param data pointer to store the read data in (must be of size
* edge[0]*...edge[rank-1]*Mat_SizeOfClass(matvar->class_type))
* @param start index to start reading data in each dimension
* @param stride write data every @c stride elements in each dimension
* @param edge number of elements to read in each dimension
* @retval 0 on success
* @endif
*/
int
Mat_VarReadData73(mat_t *mat,matvar_t *matvar,void *data,
int *start,int *stride,int *edge)
{
int err = -1, k;
hid_t fid,dset_id,ref_id,dset_space,mem_space;
hsize_t *dset_start_stride_edge;
hsize_t *dset_start, *dset_stride, *dset_edge;
if ( NULL == mat || NULL == matvar || NULL == data || NULL == start ||
NULL == stride || NULL == edge )
return err;
else if ( NULL == matvar->internal->hdf5_name && 0 > matvar->internal->id )
return err;
fid = *(hid_t*)mat->fp;
dset_start_stride_edge = (hsize_t*)malloc(matvar->rank*3*sizeof(hsize_t));
if ( NULL == dset_start_stride_edge ) {
return err;
}
dset_start = &dset_start_stride_edge[0];
dset_stride = &dset_start_stride_edge[matvar->rank];
dset_edge = &dset_start_stride_edge[2*matvar->rank];
for ( k = 0; k < matvar->rank; k++ ) {
dset_start[k] = start[matvar->rank-k-1];
dset_stride[k] = stride[matvar->rank-k-1];
dset_edge[k] = edge[matvar->rank-k-1];
}
mem_space = H5Screate_simple(matvar->rank, dset_edge, NULL);
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:
if ( NULL != matvar->internal->hdf5_name ) {
ref_id = H5Dopen(fid,matvar->internal->hdf5_name,H5P_DEFAULT);
} else {
ref_id = matvar->internal->id;
H5Iinc_ref(ref_id);
}
if ( 0 < matvar->internal->hdf5_ref ) {
dset_id = H5RDEREFERENCE(ref_id,H5R_OBJECT,&matvar->internal->hdf5_ref);
} else {
dset_id = ref_id;
H5Iinc_ref(dset_id);
}
dset_space = H5Dget_space(dset_id);
H5Sselect_hyperslab(dset_space, H5S_SELECT_SET, dset_start,
dset_stride, dset_edge, NULL);
Mat_H5ReadData(dset_id, ClassType2H5T(matvar->class_type), mem_space,
dset_space, matvar->isComplex, data);
H5Sclose(dset_space);
H5Dclose(dset_id);
H5Dclose(ref_id);
err = 0;
break;
default:
break;
}
H5Sclose(mem_space);
free(dset_start_stride_edge);
return err;
}
/** @if mat_devman
* @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_internal
* @param mat MAT file pointer
* @param matvar pointer to the mat variable
* @param data pointer to store the read data in (must be of size
* edge*Mat_SizeOfClass(matvar->class_type))
* @param start starting index
* @param stride stride of data
* @param edge number of elements to read
* @retval 0 on success
* @endif
*/
int
Mat_VarReadDataLinear73(mat_t *mat,matvar_t *matvar,void *data,
int start,int stride,int edge)
{
int err = -1, k;
hid_t fid,dset_id,dset_space,mem_space;
hsize_t *points, dset_edge, *dimp;
if ( NULL == mat || NULL == matvar || NULL == data )
return err;
else if ( NULL == matvar->internal->hdf5_name && 0 > matvar->internal->id )
return err;
fid = *(hid_t*)mat->fp;
dset_edge = edge;
mem_space = H5Screate_simple(1, &dset_edge, NULL);
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:
points = (hsize_t*)malloc(matvar->rank*(size_t)dset_edge*sizeof(*points));
if ( NULL == points ) {
err = -2;
break;
}
dimp = (hsize_t*)malloc(matvar->rank*sizeof(hsize_t));
if ( NULL == dimp ) {
err = -2;
free(points);
break;
}
dimp[0] = 1;
for ( k = 1; k < matvar->rank; k++ )
dimp[k] = dimp[k-1]*matvar->dims[k-1];
for ( k = 0; k < edge; k++ ) {
size_t l, coord;
coord = (size_t)(start + k*stride);
for ( l = matvar->rank; l--; ) {
size_t idx = (size_t)(coord / dimp[l]);
points[matvar->rank*(k+1)-1-l] = idx;
coord -= idx*(size_t)dimp[l];
}
}
free(dimp);
if ( NULL != matvar->internal->hdf5_name ) {
dset_id = H5Dopen(fid,matvar->internal->hdf5_name,H5P_DEFAULT);
} else {
dset_id = matvar->internal->id;
H5Iinc_ref(dset_id);
}
dset_space = H5Dget_space(dset_id);
H5Sselect_elements(dset_space,H5S_SELECT_SET,(size_t)dset_edge,points);
free(points);
Mat_H5ReadData(dset_id, ClassType2H5T(matvar->class_type), mem_space,
dset_space, matvar->isComplex, data);
H5Sclose(dset_space);
H5Dclose(dset_id);
err = 0;
break;
default:
break;
}
H5Sclose(mem_space);
return err;
}
/** @if mat_devman
* @brief Reads the header information for the next MAT variable
*
* @ingroup mat_internal
* @param mat MAT file pointer
* @return pointer to the MAT variable or NULL
* @endif
*/
matvar_t *
Mat_VarReadNextInfo73( mat_t *mat )
{
hid_t id;
hsize_t idx;
herr_t herr;
struct ReadNextIterData mat_data;
if ( mat == NULL )
return NULL;
if ( mat->next_index >= mat->num_datasets )
return NULL;
id = *(hid_t*)mat->fp;
idx = (hsize_t)mat->next_index;
mat_data.mat = mat;
mat_data.matvar = NULL;
herr = H5Literate(id, H5_INDEX_NAME, H5_ITER_NATIVE, &idx, Mat_VarReadNextInfoIterate, (void*)&mat_data);
if ( herr > 0 )
mat->next_index = (size_t)idx;
return mat_data.matvar;
}
static herr_t
Mat_VarReadNextInfoIterate(hid_t id, const char *name, const H5L_info_t *info, void *op_data)
{
mat_t *mat;
matvar_t *matvar;
H5O_info_t object_info;
struct ReadNextIterData *mat_data;
/* FIXME: follow symlinks, datatypes? */
/* Check that this is not the /#refs# or /"#subsystem#" group */
if ( 0 == strcmp(name, "#refs#") || 0 == strcmp(name, "#subsystem#") )
return 0;
H5OGET_INFO_BY_NAME(id, name, &object_info, H5P_DEFAULT);
if ( H5O_TYPE_DATASET != object_info.type && H5O_TYPE_GROUP != object_info.type )
return 0;
mat_data = (struct ReadNextIterData *)op_data;
if ( NULL == mat_data )
return -1;
mat = mat_data->mat;
matvar = Mat_VarCalloc();
if ( NULL == matvar )
return -1;
matvar->name = strdup(name);
if ( NULL == matvar->name ) {
Mat_VarFree(matvar);
return -1;
}
switch ( object_info.type ) {
case H5O_TYPE_DATASET:
{
hid_t dset_id = H5Dopen(id,matvar->name,H5P_DEFAULT);
Mat_H5ReadDatasetInfo(mat,matvar,dset_id);
if ( matvar->internal->id != dset_id ) {
/* Close dataset and increment count */
H5Dclose(dset_id);
}
mat_data->matvar = matvar;
break;
}
case H5O_TYPE_GROUP:
{
hid_t dset_id = H5Gopen(id,matvar->name,H5P_DEFAULT);
Mat_H5ReadGroupInfo(mat,matvar,dset_id);
H5Gclose(dset_id);
mat_data->matvar = matvar;
break;
}
default:
break;
}
return 1;
}
/** @if mat_devman
* @brief Writes a matlab variable to a version 7.3 matlab file
*
* @ingroup mat_internal
* @param mat MAT file pointer
* @param matvar pointer to the mat variable
* @param compress option to compress the variable
* (only works for numeric types)
* @retval 0 on success
* @endif
*/
int
Mat_VarWrite73(mat_t *mat,matvar_t *matvar,int compress)
{
hid_t id;
if ( NULL == mat || NULL == matvar )
return -1;
matvar->compression = (enum matio_compression)compress;
id = *(hid_t*)mat->fp;
return Mat_VarWriteNext73(id,matvar,matvar->name,&(mat->refs_id));
}
/** @if mat_devman
* @brief Writes/appends a matlab variable to a version 7.3 matlab file
*
* @ingroup mat_internal
* @param mat MAT file pointer
* @param matvar pointer to the mat variable
* @param compress option to compress the variable
* (only works for numeric types)
* @param dim dimension to append data
* (only works for numeric types)
* @retval 0 on success
* @endif
*/
int
Mat_VarWriteAppend73(mat_t *mat,matvar_t *matvar,int compress,int dim)
{
hid_t id;
if ( NULL == mat || NULL == matvar )
return -1;
matvar->compression = (enum matio_compression)compress;
id = *(hid_t*)mat->fp;
return Mat_VarWriteAppendNext73(id,matvar,matvar->name,&(mat->refs_id),dim);
}
#endif
#endif