#include "H5LDprivate.h"
static herr_t H5LD_construct_info(H5LD_memb_t *memb, hid_t par_tid);
static herr_t H5LD_get_dset_dims(hid_t did, hsize_t *cur_dims);
static size_t H5LD_get_dset_type_size(hid_t did, const char *fields);
static herr_t H5LD_get_dset_elmts(hid_t did, const hsize_t *prev_dims,
const hsize_t *cur_dims, const char *fields, void *buf);
void
H5LD_clean_vector(H5LD_memb_t *listv[])
{
unsigned n;
HDassert(listv);
for(n = 0; listv[n] != NULL; n++) {
if(listv[n]->names) {
HDfree(listv[n]->names);
listv[n]->names = NULL;
}
if(!(listv[n]->last_tid < 0)) {
H5Tclose(listv[n]->last_tid);
listv[n]->last_tid = -1;
}
HDfree(listv[n]);
listv[n] = NULL;
}
}
static herr_t
H5LD_construct_info(H5LD_memb_t *memb, hid_t par_tid)
{
hid_t tmp_tid = -1;
unsigned i;
herr_t ret_value = FAIL;
tmp_tid = H5Tcopy(par_tid);
for(i = 0; memb->names[i] != NULL; i++) {
hid_t memb_tid;
int idx;
if((idx = H5Tget_member_index(tmp_tid, memb->names[i])) < 0)
goto done;
if((memb_tid = H5Tget_member_type(tmp_tid, (unsigned)idx)) < 0)
goto done;
memb->tot_offset += H5Tget_member_offset(tmp_tid, (unsigned)idx);
if(H5Tclose(tmp_tid) < 0)
goto done;
tmp_tid = memb_tid;
}
memb->last_tsize = H5Tget_size(tmp_tid);
memb->last_tid = H5Tcopy(tmp_tid);
ret_value = SUCCEED;
done:
H5E_BEGIN_TRY
H5Tclose(tmp_tid);
H5E_END_TRY
return(ret_value);
}
int
H5LD_construct_vector(char *fields, H5LD_memb_t *listv[], hid_t par_tid)
{
int nfields;
hbool_t end_of_fields = FALSE;
char *fields_ptr;
int ret_value = FAIL;
HDassert(listv);
HDassert(fields);
fields_ptr = fields;
nfields = 0;
while(!end_of_fields) {
H5LD_memb_t *memb = NULL;
char *cur;
size_t len;
hbool_t gotcomma = FALSE;
hbool_t gotmember = FALSE;
hbool_t valid = TRUE;
int j = 0;
len = (HDstrlen(fields_ptr) / 2) + 2;
if(NULL == (memb = (H5LD_memb_t *)HDcalloc((size_t)1, sizeof(H5LD_memb_t))))
goto done;
if(NULL == (memb->names = (char **)HDcalloc(len, sizeof(char *))))
goto done;
memb->names[j] = fields_ptr;
memb->last_tid = -1;
cur = fields_ptr;
while(valid && !gotcomma && !end_of_fields) {
switch(*fields_ptr) {
case '\0':
if(gotmember) {
*cur++ = '\0';;
memb->names[++j] = NULL;
}
else
valid = FALSE;
end_of_fields = TRUE;
break;
case '\\':
++fields_ptr;
if(*fields_ptr == '\0')
valid = FALSE;
else {
*cur++ = *fields_ptr++;
gotmember = TRUE;
}
break;
case '.':
*fields_ptr++ = *cur++ = '\0';;
if(gotmember) {
memb->names[++j] = cur;
gotmember = FALSE;
}
else
valid = FALSE;
break;
case ',':
*fields_ptr++ = *cur++ = '\0';;
if(gotmember) {
memb->names[++j] = NULL;
gotmember = FALSE;
}
else
valid = FALSE;
gotcomma = TRUE;
break;
default:
*cur++ = *fields_ptr++;
gotmember = TRUE;
break;
}
}
if(valid) {
listv[nfields++] = memb;
if(H5LD_construct_info(memb, par_tid) < 0)
goto done;
}
else {
if(memb)
HDfree(memb);
goto done;
}
}
ret_value = nfields;
done:
listv[nfields] = NULL;
if(ret_value == FAIL)
H5LD_clean_vector(listv);
return(ret_value);
}
static herr_t
H5LD_get_dset_dims(hid_t did, hsize_t *cur_dims)
{
hid_t sid = -1;
herr_t ret_value = FAIL;
if(cur_dims == NULL)
goto done;
if((sid = H5Dget_space(did)) < 0)
goto done;
if(H5Sget_simple_extent_dims(sid, cur_dims, NULL) < 0)
goto done;
ret_value = SUCCEED;
done:
H5E_BEGIN_TRY {
H5Sclose(sid);
} H5E_END_TRY;
return(ret_value);
}
static size_t
H5LD_get_dset_type_size(hid_t did, const char *fields)
{
hid_t dset_tid = -1;
hid_t tid = -1;
H5LD_memb_t **listv = NULL;
char *dup_fields = NULL;
size_t ret_value = 0;
if((dset_tid = H5Dget_type(did)) < 0)
goto done;
if((tid = H5Tget_native_type(dset_tid, H5T_DIR_DEFAULT)) < 0)
goto done;
if(fields == NULL)
ret_value = H5Tget_size(tid);
else {
size_t len;
size_t tot = 0;
int n = 0, num = 0;
HDassert(fields && *fields);
if(H5Tget_class(dset_tid) != H5T_COMPOUND)
goto done;
if(NULL == (dup_fields = HDstrdup(fields)))
goto done;
len = (HDstrlen(fields) / 2) + 2;
if(NULL == (listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))))
goto done;
if((num = H5LD_construct_vector(dup_fields, listv, tid)) < 0)
goto done;
for(n = 0; n < num; n++)
tot += listv[n]->last_tsize;
H5LD_clean_vector(listv);
ret_value = tot;
}
done:
H5E_BEGIN_TRY
H5Tclose(tid);
H5Tclose(dset_tid);
H5E_END_TRY
if(listv)
HDfree(listv);
if(dup_fields)
HDfree(dup_fields);
return(ret_value);
}
static herr_t
H5LD_get_dset_elmts(hid_t did, const hsize_t *prev_dims, const hsize_t *cur_dims,
const char *fields, void *buf)
{
hid_t dtid = -1, tid = -1;
hid_t sid = -1, mid = -1;
hssize_t snum_elmts;
hsize_t num_elmts;
hsize_t start[H5S_MAX_RANK];
hsize_t count[H5S_MAX_RANK];
H5LD_memb_t **listv = NULL;
char *dup_fields = NULL;
char *sav_buf = NULL;
unsigned ctr;
int ndims;
int i;
herr_t ret_value = FAIL;
if(prev_dims == NULL || cur_dims == NULL || buf == NULL)
goto done;
if((sid = H5Dget_space(did)) < 0)
goto done;
if((ndims = H5Sget_simple_extent_ndims(sid)) < 0)
goto done;
HDmemset(start, 0, sizeof start);
HDmemset(count, 0, sizeof count);
ctr = 0;
for(i = 0; i < ndims; i++)
if(cur_dims[i] > prev_dims[i]) {
++ctr;
count[i] = cur_dims[i] - prev_dims[i];
start[i] = prev_dims[i];
}
else {
start[i] = 0;
count[i] = MIN(prev_dims[i], cur_dims[i]);
}
if(!ctr)
goto done;
if(ctr == 1) {
if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0)
goto done;
}
else {
HDmemset(start, 0, sizeof start);
if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, cur_dims, NULL) < 0)
goto done;
if(H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, prev_dims, NULL) < 0)
goto done;
}
if(0 == (snum_elmts = H5Sget_select_npoints(sid)))
goto done;
num_elmts = (hsize_t)snum_elmts;
if((mid = H5Screate_simple(1, &num_elmts, NULL)) < 0)
goto done;
if((dtid = H5Dget_type(did)) < 0)
goto done;
if((tid = H5Tget_native_type(dtid, H5T_DIR_DEFAULT)) < 0)
goto done;
if(fields == NULL) {
if(H5Dread(did, tid, mid, sid, H5P_DEFAULT, buf) < 0)
goto done;
}
else {
unsigned char *buf_p = (unsigned char *)buf;
char *tmp_buf;
size_t tot_tsize;
size_t len;
if(H5Tget_class(tid) != H5T_COMPOUND)
goto done;
if(0 == (tot_tsize = H5LD_get_dset_type_size(did, NULL)))
goto done;
if(NULL == (sav_buf = tmp_buf = (char *)HDcalloc((size_t)num_elmts, tot_tsize)))
goto done;
if(H5Dread(did, tid, mid, sid, H5P_DEFAULT, tmp_buf) < 0)
goto done;
if(NULL == (dup_fields = HDstrdup(fields)))
goto done;
len = (HDstrlen(fields) / 2) + 2;
if(NULL == (listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))))
goto done;
if(H5LD_construct_vector(dup_fields, listv, tid) < 0)
goto done;
for(i = 0; i < (int)num_elmts; i++) {
int j;
for(j = 0; listv[j] != NULL; j++) {
HDmemcpy(buf_p, tmp_buf + listv[j]->tot_offset, listv[j]->last_tsize);
buf_p += listv[j]->last_tsize;
}
tmp_buf += tot_tsize;
}
H5LD_clean_vector(listv);
}
ret_value = SUCCEED;
done:
H5E_BEGIN_TRY
H5Tclose(dtid);
H5Tclose(tid);
H5Sclose(sid);
H5Sclose(mid);
H5E_END_TRY
if(listv)
HDfree(listv);
if(dup_fields)
HDfree(dup_fields);
if(sav_buf)
HDfree(sav_buf);
return(ret_value);
}
herr_t
H5LDget_dset_dims(hid_t did, hsize_t *cur_dims)
{
return(H5LD_get_dset_dims(did, cur_dims));
}
size_t
H5LDget_dset_type_size(hid_t did, const char *fields)
{
return(H5LD_get_dset_type_size(did, fields));
}
herr_t
H5LDget_dset_elmts(hid_t did, const hsize_t *prev_dims, const hsize_t *cur_dims, const char *fields, void *buf)
{
return(H5LD_get_dset_elmts(did, prev_dims, cur_dims, fields, buf) );
}