/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include #include "H5LDprivate.h" /*------------------------------------------------------------------------- * * internal functions * *------------------------------------------------------------------------- */ 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); static herr_t H5LD_get_dset_dims(hid_t did, hsize_t *cur_dims); static herr_t H5LD_construct_info(H5LD_memb_t *memb, hid_t par_tid); /*------------------------------------------------------------------------- * Function: H5LD_clean_vector * * Purpose: Process the vector of info: * 1) free the array of pointers to member names in listv[n] * 2) close the type id of the last member in listv[n] * 3) free the H5LD_memb_t structure itself as pointed to by listv[n] * * Return: void * * Programmer: Vailin Choi; Aug 2010 * *------------------------------------------------------------------------- */ void H5LD_clean_vector(H5LD_memb_t *listv[]) { unsigned n; /* Local index variable */ HDassert(listv); /* Go through info for each field stored in listv[] */ for(n = 0; listv[n] != NULL; n++) { if(listv[n]->names) { HDfree(listv[n]->names); listv[n]->names = NULL; } /* Close the type id of the last member in the field */ if(!(listv[n]->last_tid < 0)) { H5Tclose(listv[n]->last_tid); listv[n]->last_tid = -1; } /* Free the H5LD_memb_t structure for the field */ HDfree(listv[n]); listv[n] = NULL; } } /* H5LD_clean_vector() */ /*------------------------------------------------------------------------- * Function: H5LD_construct_info() * * Purpose: Get the remaining info for a field: * 1) Get the type id of the last member in the field * 2) Get the total offset of all the members in the field * 3) Get the type size of the last member in the field * * Return: Success: 0 * Failure: negative * * Programmer: Vailin Choi; Aug 2010 * *------------------------------------------------------------------------- */ static herr_t H5LD_construct_info(H5LD_memb_t *memb, hid_t par_tid) { hid_t tmp_tid; /* Dataset type id */ hid_t memb_tid; /* Type id for a member in a field */ unsigned i; /* Local index variable */ int idx; /* Index # of a member in a compound data type */ herr_t ret_value = SUCCEED; /* Return value */ tmp_tid = H5Tcopy(par_tid); /* Validate all the members in a field */ for(i = 0; memb->names[i] != NULL; i++) { /* Get the member index and member type id */ if((idx = H5Tget_member_index(tmp_tid, memb->names[i])) < 0 || (memb_tid = H5Tget_member_type(tmp_tid, (unsigned)idx)) < 0) { ret_value = FAIL; goto error; } /* Sum up the offset of all the members in the field */ memb->tot_offset += H5Tget_member_offset(tmp_tid, (unsigned)idx); if(H5Tclose(tmp_tid) < 0) { ret_value = FAIL; goto error; } tmp_tid = memb_tid; } /* Get the type size of the last member in the field */ memb->last_tsize = H5Tget_size(tmp_tid); /* Save the type id of the last member in the field */ memb->last_tid = H5Tcopy(tmp_tid); error: H5E_BEGIN_TRY H5Tclose(tmp_tid); H5E_END_TRY return(ret_value); } /* H5LD_construct_info() */ /*------------------------------------------------------------------------- * Function: H5LD_construct_vector * * Purpose: Process the comma-separated list of fields in "fields" as follows: * Example: * "fields": "a.b.c,d" * listv[0]->tot_offset = total offset of "a" & "b" & "c" * listv[0]->last_tid = type id of "c" * listv[0]->last_tsize = type size of "c" * listv[0]->names[0] = "a" * listv[0]->names[1] = "b" * listv[0]->names[2] = "c" * listv[0]->names[3] = NULL * * listv[1]->tot_offset = offset of "d" * listv[1]->last_tid = type id of "d" * listv[1]->last_tsize = type size of "d" * listv[1]->names[0] = "d" * listv[1]->names[1] = NULL * * Return: Success: # of comma-separated fields in "fields" * Failure: negative value * * Programmer: Vailin Choi; Aug 2010 * *------------------------------------------------------------------------- */ int H5LD_construct_vector(char *fields, H5LD_memb_t *listv[]/*OUT*/, hid_t par_tid) { int n; /* The # of comma-separated fields in "fields" */ hbool_t valid; /* Whether a field being processed is valid or not */ hbool_t end_of_fields = FALSE; /* end of "fields" */ char *fields_ptr; /* Pointer to "fields" */ char *cur; /* Pointer to a member in a field */ int ret_value = SUCCEED; /* Return value */ HDassert(listv); HDassert(fields); fields_ptr = fields; n = 0; /* Process till end of "fields" */ while(!end_of_fields) { hbool_t gotcomma = FALSE; /* A comma encountered */ hbool_t gotmember = FALSE; /* Getting member in a field */ H5LD_memb_t *memb = NULL; /* Pointer to structure for storing a field's info */ size_t len; /* Estimated # of members in a field */ int j = 0; /* The # of members in a field */ valid = TRUE; len = HDstrlen(fields_ptr)/2 + 2; /* Allocate memory for an H5LD_memb_t for storing a field's info */ if((memb = (H5LD_memb_t *)HDcalloc(1, sizeof(H5LD_memb_t))) == NULL) { ret_value = FAIL; break; } /* Allocate memory for an array of pointers to member names */ if((memb->names = (char **)HDcalloc(len, sizeof(char *))) == NULL) { ret_value = FAIL; break; } memb->names[j] = fields_ptr; memb->last_tid = -1; cur = fields_ptr; /* Continue processing till: not valid or comma encountered or "fields" ended */ while(valid && !gotcomma && !end_of_fields) { switch(*fields_ptr) { case '\0': /* end of list */ if(gotmember) { /* getting something and end of "fields" */ *cur++ = '\0';; memb->names[++j] = NULL; } else /* getting nothing but end of list */ valid = FALSE; end_of_fields = TRUE; break; case '\\': /* escape character */ ++fields_ptr; /* skip it */ if(*fields_ptr == '\0') valid = FALSE; else { *cur++ = *fields_ptr++; gotmember = TRUE; } break; case '.': /* nested field separator */ *fields_ptr++ = *cur++ = '\0';; if(gotmember) { memb->names[++j] = cur; gotmember = FALSE; } else valid = FALSE; break; case ',': /* field separator */ *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; } } /* while (valid && !gotcomma && !end_of_fields) */ /* If valid, put into listv and continue processing further info */ if(valid) { listv[n++] = memb; if((ret_value = H5LD_construct_info(memb, par_tid)) < 0) break; } else { if(memb) HDfree(memb); ret_value = FAIL; break; } } /* while !end_of_fields */ listv[n] = NULL; if(ret_value == FAIL) (void) H5LD_clean_vector(listv); else ret_value = n; return(ret_value); } /* H5LD_construct_vector() */ /*------------------------------------------------------------------------- * Function: H5LD_get_dset_dims * * Purpose: To return the current size for each dimension of the * dataset's dataspace * * Return: Success: 0 * Failure: negative value * * Programmer: Vailin Choi; March 2010 * *------------------------------------------------------------------------- */ static herr_t H5LD_get_dset_dims(hid_t did, hsize_t *cur_dims) { hid_t sid; /* dataspace id */ int ret_value = SUCCEED; /* return_value */ /* Verify parameter */ if(cur_dims == NULL) { ret_value = FAIL; goto out; } /* Get the dataset's dataspace */ if((sid = H5Dget_space(did)) < 0) { ret_value = FAIL; goto out; } /* Get the current dimension size */ if(H5Sget_simple_extent_dims(sid, cur_dims, NULL) < 0) ret_value = FAIL; out: H5E_BEGIN_TRY { H5Sclose(sid); } H5E_END_TRY; return(ret_value); } /* H5LD_get_dset_dims() */ /*------------------------------------------------------------------------- * Function: H5LD_get_dset_type_size * * Purpose: To return the size of the dataset's data type in bytes * null "fields": return the size of the dataset's data type * non-null "fields": return the size of the dataset's data type * with respect to the selection in "fields" * * Return: Success: size of the dataset's data type * Failure: 0 (valid datatypes are never zero size) * * Programmer: Vailin Choi; March 2010 * *------------------------------------------------------------------------- */ static size_t H5LD_get_dset_type_size(hid_t did, const char *fields) { hid_t dset_tid; /* Dataset's type identifier */ hid_t tid; /* Native Type identifier */ size_t tot = 0; /* Data type size of all the fields in "fields" */ H5LD_memb_t **listv = NULL; /* Vector for storing information in "fields" */ char *dup_fields = NULL; /* A copy of "fields" */ int n = 0, num = 0; /* Local index variable */ size_t len; /* Estimate the number of comma-separated fields in "fields" */ size_t ret_value = 0; /* Return value */ /* Get the data type of the dataset */ if(((dset_tid = H5Dget_type(did)) < 0) || (tid = H5Tget_native_type(dset_tid, H5T_DIR_DEFAULT)) < 0) goto out; if(fields == NULL) /* If no "fields" is specified */ ret_value = H5Tget_size(tid); else { /* "fields" are specified */ HDassert(fields && *fields); /* Should be a compound data type if "fields" exists */ if(H5Tget_class(dset_tid) != H5T_COMPOUND) goto out; /* Get a copy of "fields" */ if((dup_fields = HDstrdup(fields)) == NULL) goto out; /* Allocate memory for a list of H5LD_memb_t pointers to store "fields" info */ len = HDstrlen(fields)/2 + 2; if((listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))) == NULL) goto out; /* Process and store info for "fields" */ if((num = H5LD_construct_vector(dup_fields, listv/*OUT*/, tid)) < 0) goto out; /* Sum up the size of all the data types in "fields" */ for(n = 0; n < num; n++) tot += listv[n]->last_tsize; /* Clean up the vector of H5LD_memb_t structures */ (void) H5LD_clean_vector(listv); /* Return the total size */ ret_value = tot; } out: H5E_BEGIN_TRY H5Tclose(tid); H5Tclose(dset_tid); H5E_END_TRY /* Free the array of H5LD_memb_t pointers */ if(listv) HDfree(listv); /* Free memory */ if(dup_fields) HDfree(dup_fields); return(ret_value); } /* H5LD_get_dset_type_size() */ /*------------------------------------------------------------------------- * Function: H5LD_get_dset_elmts * * Purpose: To retrieve selected data from the dataset * * Return: Success: 0 * Failure: negative * * Programmer: Vailin Choi; August 2010 * *------------------------------------------------------------------------- */ 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) { int ndims; /* Number of dimensions for the dataset */ hid_t dtid, tid; /* Dataset type id */ size_t tot_tsize; /* Total data type size */ hid_t sid, mid; /* Dataspace and memory space id */ hsize_t num_elmts; /* Number of dataset elements in the selection */ hsize_t start[H5S_MAX_RANK];/* Starting offset */ hsize_t count[H5S_MAX_RANK];/* ??offset */ H5LD_memb_t **listv = NULL; /* Vector for storing information in "fields" */ char *dup_fields = NULL; /* A copy of "fields" */ char *tmp_buf = NULL; /* Temporary buffer for data read */ char *sav_buf = NULL; /* Saved pointer temporary buffer */ int n = 0, i = 0; /* Local index variable */ size_t len; /* Estimate the number of comma-separated fields in "fields" */ unsigned int ctr = 0; /* Counter for # of curr_dims > prev_dims */ herr_t ret_value = SUCCEED; /* Return value */ /* Verify parameters */ if(prev_dims == NULL || cur_dims == NULL || buf == NULL) { ret_value = FAIL; goto done; } /* Get dataset's dataspace */ if((sid = H5Dget_space(did)) < 0) { ret_value = FAIL; goto done; } /* Get the number of dimensions */ if((ndims = H5Sget_simple_extent_ndims(sid)) < 0) { ret_value = FAIL; goto done; } /* Verify that cur_dims must have one dimension whose size is greater than prev_dims */ HDmemset(start, 0, sizeof start); HDmemset(count, 0, sizeof count); 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 { /* < or = */ start[i] = 0; count[i] = MIN(prev_dims[i], cur_dims[i]); } if(!ctr) { ret_value = FAIL; goto done; } if(ctr == 1) { /* changes for only one dimension */ /* Make the selection in the dataset based on "cur_dims" and "prev_dims" */ if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { ret_value = FAIL; goto done; } } else { /* changes for more than one dimensions */ HDmemset(start, 0, sizeof start); /* Make the selection in the dataset based on "cur_dims" and "prev_dims" */ if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, cur_dims, NULL) < 0) { ret_value = FAIL; goto done; } if(H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, prev_dims, NULL) < 0) { ret_value = FAIL; goto done; } } /* Get the number of elements in the selection */ if((num_elmts = H5Sget_select_npoints(sid)) == 0) { ret_value = FAIL; goto done; } /* Create the memory space for the selection */ if((mid = H5Screate_simple(1, &num_elmts, NULL)) < 0) { ret_value = FAIL; goto done; } /* Get the native data type size */ if(((dtid = H5Dget_type(did)) < 0) || (tid = H5Tget_native_type(dtid, H5T_DIR_DEFAULT)) < 0) { ret_value = FAIL; goto done; } if(fields == NULL) { /* nothing in "fields" */ /* Read and store all the elements in "buf" */ if(H5Dread(did, tid, mid, sid, H5P_DEFAULT, buf) < 0) { ret_value = FAIL; goto done; } } else { /* "fields" is specified */ unsigned char *buf_p = (unsigned char *)buf; /* Pointer to the destination buffer */ /* should be a compound data type if "fields" exists */ if(H5Tget_class(tid) != H5T_COMPOUND) { ret_value = FAIL; goto done; } /* Get the total size of the dataset's data types */ if((tot_tsize = H5LD_get_dset_type_size(did, NULL)) == 0) { ret_value = FAIL; goto done; } /* Allocate memory for reading in the elements in the dataset selection */ if((sav_buf = tmp_buf = (char *)HDcalloc((size_t)num_elmts, tot_tsize)) == NULL) { ret_value = FAIL; goto done; } /* Read the dataset elements in the selection */ if(H5Dread(did, tid, mid, sid, H5P_DEFAULT, tmp_buf) < 0) { ret_value = FAIL; goto done; } /* Make a copy of "fields" */ if((dup_fields = HDstrdup(fields)) == NULL) { ret_value = FAIL; goto done; } /* Allocate memory for the vector of H5LD_memb_t pointers */ len = HDstrlen(fields)/2 + 2; if((listv = (H5LD_memb_t **)HDcalloc(len, sizeof(H5LD_memb_t *))) == NULL) { ret_value = FAIL; goto done; } /* Process and store information for "fields" */ if(H5LD_construct_vector(dup_fields, listv, tid) < 0) { ret_value = FAIL; goto done; } /* Copy data for each dataset element in the selection */ for(i = 0; i < (int)num_elmts; i++) { /* Copy data for "fields" to the input buffer */ for(n = 0; listv[n] != NULL; n++) { HDmemcpy(buf_p, tmp_buf + listv[n]->tot_offset, listv[n]->last_tsize); buf_p += listv[n]->last_tsize; } tmp_buf += tot_tsize; } /* Clean up the vector of H5LD_memb_t structures */ (void) H5LD_clean_vector(listv); } done: H5E_BEGIN_TRY H5Tclose(dtid); H5Tclose(tid); H5Sclose(sid); H5Sclose(mid); H5E_END_TRY /* Free the array of H5LD_memb_t pointers */ if(listv) HDfree(listv); /* Free memory */ if(dup_fields) HDfree(dup_fields); if(sav_buf) HDfree(sav_buf); return(ret_value); } /* H5LD_get_dset_elmts() */ /*------------------------------------------------------------------------- * * Public functions * *------------------------------------------------------------------------- */ /*------------------------------------------------------------------------- * Function: H5LDget_dset_dims * * Purpose: To retrieve the current dimension sizes for a dataset * * Return: Success: 0 * Failure: negative value * * Programmer: Vailin Choi; March 2010 * *------------------------------------------------------------------------- */ herr_t H5LDget_dset_dims(hid_t did, hsize_t *cur_dims) { int ret_value; /* return_value */ ret_value = H5LD_get_dset_dims(did, cur_dims); return(ret_value); } /* H5LDget_dset_dims() */ /*------------------------------------------------------------------------- * Function: H5LDget_dset_type_size * * Purpose: To return the size in bytes of the data type for the dataset * * Return: Success: size in bytes of the dataset's data type * Failure: 0 (valid datatypes are never zero size) * * Programmer: Vailin Choi; March 2010 * *------------------------------------------------------------------------- */ size_t H5LDget_dset_type_size(hid_t did, const char *fields) { size_t ret_value; /* Return value */ ret_value = H5LD_get_dset_type_size(did, fields); return(ret_value); } /* H5LDget_dset_type_size() */ /*------------------------------------------------------------------------- * Function: H5LDget_dset_elmts * * Purpose: To retrieve selected data from the dataset * * Return: Success: 0 * Failure: negative value * * Programmer: Vailin Choi; March 2010 * *------------------------------------------------------------------------- */ herr_t H5LDget_dset_elmts(hid_t did, const hsize_t *prev_dims, const hsize_t *cur_dims, const char *fields, void *buf) { herr_t ret_value; /* Return value */ ret_value = H5LD_get_dset_elmts(did, prev_dims, cur_dims, fields, buf); return(ret_value); } /* H5LDget_dset_elmts() */