diff options
Diffstat (limited to 'src/H5Tvlen.c')
-rw-r--r-- | src/H5Tvlen.c | 1259 |
1 files changed, 1259 insertions, 0 deletions
diff --git a/src/H5Tvlen.c b/src/H5Tvlen.c new file mode 100644 index 0000000..00e61e5 --- /dev/null +++ b/src/H5Tvlen.c @@ -0,0 +1,1259 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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 COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Module Info: This module contains the functionality for variable-length + * datatypes in the H5T interface. + */ + +#include "H5Tmodule.h" /* This source code file is part of the H5T module */ + + +#include "H5private.h" /* Generic Functions */ +#include "H5Dprivate.h" /* Dataset functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5HGprivate.h" /* Global Heaps */ +#include "H5Iprivate.h" /* IDs */ +#include "H5MMprivate.h" /* Memory management */ +#include "H5Pprivate.h" /* Property lists */ +#include "H5Tpkg.h" /* Datatypes */ + +/* Local functions */ +static herr_t H5T_vlen_reclaim_recurse(void *elem, const H5T_t *dt, H5MM_free_t free_func, void *free_info); +static ssize_t H5T_vlen_seq_mem_getlen(const void *_vl); +static void * H5T_vlen_seq_mem_getptr(void *_vl); +static htri_t H5T_vlen_seq_mem_isnull(const H5F_t *f, void *_vl); +static herr_t H5T_vlen_seq_mem_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len); +static herr_t H5T_vlen_seq_mem_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size); +static herr_t H5T_vlen_seq_mem_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg); +static ssize_t H5T_vlen_str_mem_getlen(const void *_vl); +static void * H5T_vlen_str_mem_getptr(void *_vl); +static htri_t H5T_vlen_str_mem_isnull(const H5F_t *f, void *_vl); +static herr_t H5T_vlen_str_mem_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len); +static herr_t H5T_vlen_str_mem_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size); +static herr_t H5T_vlen_str_mem_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg); +static ssize_t H5T_vlen_disk_getlen(const void *_vl); +static void * H5T_vlen_disk_getptr(void *_vl); +static htri_t H5T_vlen_disk_isnull(const H5F_t *f, void *_vl); +static herr_t H5T_vlen_disk_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *_buf, size_t len); +static herr_t H5T_vlen_disk_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *_buf, void *_bg, size_t seq_len, size_t base_size); +static herr_t H5T_vlen_disk_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg); + +/* Local variables */ + +/* Default settings for variable-length allocation routines */ +static H5T_vlen_alloc_info_t H5T_vlen_def_vl_alloc_info ={ + H5D_VLEN_ALLOC, + H5D_VLEN_ALLOC_INFO, + H5D_VLEN_FREE, + H5D_VLEN_FREE_INFO +}; + + + +/*------------------------------------------------------------------------- + * Function: H5Tvlen_create + * + * Purpose: Create a new variable-length datatype based on the specified + * BASE_TYPE. + * + * Return: Success: ID of new VL datatype + * + * Failure: Negative + * + * Programmer: Quincey Koziol + * Thursday, May 20, 1999 + * + *------------------------------------------------------------------------- + */ +hid_t +H5Tvlen_create(hid_t base_id) +{ + H5T_t *base = NULL; /*base datatype */ + H5T_t *dt = NULL; /*new datatype */ + hid_t ret_value; /*return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE1("i", "i", base_id); + + /* Check args */ + if(NULL == (base = (H5T_t *)H5I_object_verify(base_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an valid base datatype") + + /* Create up VL datatype */ + if((dt = H5T__vlen_create(base)) == NULL) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "invalid VL location") + + /* Atomize the type */ + if((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL, "unable to register datatype") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Tvlen_create() */ + + +/*------------------------------------------------------------------------- + * Function: H5T__vlen_create + * + * Purpose: Create a new variable-length datatype based on the specified + * BASE_TYPE. + * + * Return: Success: new VL datatype + * + * Failure: NULL + * + * Programmer: Quincey Koziol + * Tuesday, November 20, 2001 + * + *------------------------------------------------------------------------- + */ +H5T_t * +H5T__vlen_create(const H5T_t *base) +{ + H5T_t *dt = NULL; /* New VL datatype */ + H5T_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check args */ + HDassert(base); + + /* Build new type */ + if(NULL == (dt = H5T__alloc())) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, NULL, "memory allocation failed") + dt->shared->type = H5T_VLEN; + + /* + * Force conversions (i.e. memory to memory conversions should duplicate + * data, not point to the same VL sequences) + */ + dt->shared->force_conv = TRUE; + if(NULL == (dt->shared->parent = H5T_copy(base, H5T_COPY_ALL))) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "can't copy base datatype") + + /* Inherit encoding version from base type */ + dt->shared->version = base->shared->version; + + /* This is a sequence, not a string */ + dt->shared->u.vlen.type = H5T_VLEN_SEQUENCE; + + /* Set up VL information */ + if(H5T_set_loc(dt, NULL, H5T_LOC_MEMORY) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "invalid datatype location") + + /* Set return value */ + ret_value = dt; + +done: + if(!ret_value) + if(dt && H5T_close(dt) < 0) + HDONE_ERROR(H5E_DATATYPE, H5E_CANTRELEASE, NULL, "unable to release datatype info") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T__vlen_create() */ + + +/*------------------------------------------------------------------------- + * Function: H5T__vlen_set_loc + * + * Purpose: Sets the location of a VL datatype to be either on disk or in memory + * + * Return: + * One of two values on success: + * TRUE - If the location of any vlen types changed + * FALSE - If the location of any vlen types is the same + * <0 is returned on failure + * + * Programmer: Quincey Koziol + * Friday, June 4, 1999 + * + *------------------------------------------------------------------------- + */ +htri_t +H5T__vlen_set_loc(const H5T_t *dt, H5F_t *f, H5T_loc_t loc) +{ + htri_t ret_value = FALSE; /* Indicate success, but no location change */ + + FUNC_ENTER_PACKAGE + + /* check parameters */ + HDassert(dt); + HDassert(loc >= H5T_LOC_BADLOC && loc < H5T_LOC_MAXLOC); + + /* Only change the location if it's different */ + if(loc != dt->shared->u.vlen.loc || f != dt->shared->u.vlen.f) { + switch(loc) { + case H5T_LOC_MEMORY: /* Memory based VL datatype */ + HDassert(NULL == f); + + /* Mark this type as being stored in memory */ + dt->shared->u.vlen.loc = H5T_LOC_MEMORY; + + if(dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) { + /* size in memory, disk size is different */ + dt->shared->size = sizeof(hvl_t); + + /* Set up the function pointers to access the VL sequence in memory */ + dt->shared->u.vlen.getlen = H5T_vlen_seq_mem_getlen; + dt->shared->u.vlen.getptr = H5T_vlen_seq_mem_getptr; + dt->shared->u.vlen.isnull = H5T_vlen_seq_mem_isnull; + dt->shared->u.vlen.read = H5T_vlen_seq_mem_read; + dt->shared->u.vlen.write = H5T_vlen_seq_mem_write; + dt->shared->u.vlen.setnull = H5T_vlen_seq_mem_setnull; + } else if(dt->shared->u.vlen.type == H5T_VLEN_STRING) { + /* size in memory, disk size is different */ + dt->shared->size = sizeof(char *); + + /* Set up the function pointers to access the VL string in memory */ + dt->shared->u.vlen.getlen = H5T_vlen_str_mem_getlen; + dt->shared->u.vlen.getptr = H5T_vlen_str_mem_getptr; + dt->shared->u.vlen.isnull = H5T_vlen_str_mem_isnull; + dt->shared->u.vlen.read = H5T_vlen_str_mem_read; + dt->shared->u.vlen.write = H5T_vlen_str_mem_write; + dt->shared->u.vlen.setnull = H5T_vlen_str_mem_setnull; + } else { + HDassert(0 && "Invalid VL type"); + } + + /* Reset file ID (since this VL is in memory) */ + dt->shared->u.vlen.f = NULL; + break; + + case H5T_LOC_DISK: /* Disk based VL datatype */ + HDassert(f); + + /* Mark this type as being stored on disk */ + dt->shared->u.vlen.loc = H5T_LOC_DISK; + + /* + * Size of element on disk is 4 bytes for the length, plus the size + * of an address in this file, plus 4 bytes for the size of a heap + * ID. Memory size is different + */ + dt->shared->size = 4 + (size_t)H5F_SIZEOF_ADDR(f) + 4; + + /* Set up the function pointers to access the VL information on disk */ + /* VL sequences and VL strings are stored identically on disk, so use the same functions */ + dt->shared->u.vlen.getlen = H5T_vlen_disk_getlen; + dt->shared->u.vlen.getptr = H5T_vlen_disk_getptr; + dt->shared->u.vlen.isnull = H5T_vlen_disk_isnull; + dt->shared->u.vlen.read = H5T_vlen_disk_read; + dt->shared->u.vlen.write = H5T_vlen_disk_write; + dt->shared->u.vlen.setnull = H5T_vlen_disk_setnull; + + /* Set file ID (since this VL is on disk) */ + dt->shared->u.vlen.f = f; + break; + + case H5T_LOC_BADLOC: + /* Allow undefined location. In H5Odtype.c, H5O_dtype_decode sets undefined + * location for VL type and leaves it for the caller to decide. + */ + break; + + case H5T_LOC_MAXLOC: + /* MAXLOC is invalid */ + default: + HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype location") + } /* end switch */ /*lint !e788 All appropriate cases are covered */ + + /* Indicate that the location changed */ + ret_value = TRUE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T__vlen_set_loc() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_getlen + * + * Purpose: Retrieves the length of a memory based VL element. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static ssize_t +H5T_vlen_seq_mem_getlen(const void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */ +#else + hvl_t vl; /* User's hvl_t information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters, return result */ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(vl); + + FUNC_LEAVE_NOAPI((ssize_t)vl->len) +#else + HDassert(_vl); + HDmemcpy(&vl, _vl, sizeof(hvl_t)); + + FUNC_LEAVE_NOAPI((ssize_t)vl.len) +#endif +} /* end H5T_vlen_seq_mem_getlen() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_getptr + * + * Purpose: Retrieves the pointer for a memory based VL element. + * + * Return: Non-NULL on success/NULL on failure + * + * Programmer: Quincey Koziol + * Saturday, June 12, 2004 + * + *------------------------------------------------------------------------- + */ +static void * +H5T_vlen_seq_mem_getptr(void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */ +#else + hvl_t vl; /* User's hvl_t information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters, return result */ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(vl); + + FUNC_LEAVE_NOAPI(vl->p) +#else + HDassert(_vl); + HDmemcpy(&vl, _vl, sizeof(hvl_t)); + + FUNC_LEAVE_NOAPI(vl.p) +#endif +} /* end H5T_vlen_seq_mem_getptr() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_isnull + * + * Purpose: Checks if a memory sequence is the "null" sequence + * + * Return: TRUE/FALSE on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5T_vlen_seq_mem_isnull(const H5F_t H5_ATTR_UNUSED *f, void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */ +#else + hvl_t vl; /* User's hvl_t information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters, return result */ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(vl); + + FUNC_LEAVE_NOAPI((vl->len==0 || vl->p==NULL) ? TRUE : FALSE) +#else + HDassert(_vl); + HDmemcpy(&vl, _vl, sizeof(hvl_t)); + + FUNC_LEAVE_NOAPI((vl.len==0 || vl.p==NULL) ? TRUE : FALSE) +#endif +} /* end H5T_vlen_seq_mem_isnull() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_read + * + * Purpose: "Reads" the memory based VL sequence into a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_seq_mem_read(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void *buf, size_t len) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + const hvl_t *vl=(const hvl_t *)_vl; /* Pointer to the user's hvl_t information */ +#else + hvl_t vl; /* User's hvl_t information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters, copy data */ + HDassert(buf); +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(vl && vl->p); + + HDmemcpy(buf,vl->p,len); +#else + HDassert(_vl); + HDmemcpy(&vl, _vl, sizeof(hvl_t)); + HDassert(vl.p); + + HDmemcpy(buf,vl.p,len); +#endif + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5T_vlen_seq_mem_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_write + * + * Purpose: "Writes" the memory based VL sequence from a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_seq_mem_write(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size) +{ + hvl_t vl; /* Temporary hvl_t to use during operation */ + size_t len; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* check parameters */ + HDassert(_vl); + HDassert(buf); + + if(seq_len!=0) { + len=seq_len*base_size; + + /* Use the user's memory allocation routine is one is defined */ + if(vl_alloc_info->alloc_func!=NULL) { + if(NULL==(vl.p=(vl_alloc_info->alloc_func)(len,vl_alloc_info->alloc_info))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data") + } /* end if */ + else { /* Default to system malloc */ + if(NULL == (vl.p = HDmalloc(len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data") + } /* end else */ + + /* Copy the data into the newly allocated buffer */ + HDmemcpy(vl.p,buf,len); + + } /* end if */ + else + vl.p=NULL; + + /* Set the sequence length */ + vl.len=seq_len; + + /* Set pointer in user's buffer with memcpy, to avoid alignment issues */ + HDmemcpy(_vl,&vl,sizeof(hvl_t)); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_seq_mem_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_seq_mem_setnull + * + * Purpose: Sets a VL info object in memory to the "nil" value + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_seq_mem_setnull(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void H5_ATTR_UNUSED *_bg) +{ + hvl_t vl; /* Temporary hvl_t to use during operation */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ + HDassert(_vl); + + /* Set the "nil" hvl_t */ + vl.len=0; + vl.p=NULL; + + /* Set pointer in user's buffer with memcpy, to avoid alignment issues */ + HDmemcpy(_vl,&vl,sizeof(hvl_t)); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5T_vlen_seq_mem_setnull() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_getlen + * + * Purpose: Retrieves the length of a memory based VL string. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static ssize_t +H5T_vlen_str_mem_getlen(const void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + const char *s=*(const char * const *)_vl; /* Pointer to the user's string information */ +#else + const char *s; /* Pointer to the user's string information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(s); +#else + HDassert(_vl); + HDmemcpy(&s, _vl, sizeof(char *)); +#endif + + FUNC_LEAVE_NOAPI((ssize_t)HDstrlen(s)) +} /* end H5T_vlen_str_mem_getlen() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_getptr + * + * Purpose: Retrieves the pointer for a memory based VL string. + * + * Return: Non-NULL on success/NULL on failure + * + * Programmer: Quincey Koziol + * Saturday, June 12, 2004 + * + *------------------------------------------------------------------------- + */ +static void * +H5T_vlen_str_mem_getptr(void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + char *s=*(char **)_vl; /* Pointer to the user's string information */ +#else + char *s; /* Pointer to the user's string information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(s); +#else + HDassert(_vl); + HDmemcpy(&s, _vl, sizeof(char *)); +#endif + + FUNC_LEAVE_NOAPI(s) +} /* end H5T_vlen_str_mem_getptr() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_isnull + * + * Purpose: Checks if a memory string is a NULL pointer + * + * Return: TRUE/FALSE on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5T_vlen_str_mem_isnull(const H5F_t H5_ATTR_UNUSED *f, void *_vl) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + char *s=*(char **)_vl; /* Pointer to the user's string information */ +#else + char *s; /* Pointer to the user's string information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + +#ifndef H5_NO_ALIGNMENT_RESTRICTIONS + HDmemcpy(&s, _vl, sizeof(char *)); +#endif + + FUNC_LEAVE_NOAPI(s==NULL ? TRUE : FALSE) +} /* end H5T_vlen_str_mem_isnull() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_read + * + * Purpose: "Reads" the memory based VL string into a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_str_mem_read(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void *buf, size_t len) +{ +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + char *s=*(char **)_vl; /* Pointer to the user's string information */ +#else + char *s; /* Pointer to the user's string information */ +#endif + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(len>0) { + /* check parameters */ + HDassert(buf); +#ifdef H5_NO_ALIGNMENT_RESTRICTIONS + HDassert(s); +#else + HDassert(_vl); + HDmemcpy(&s, _vl, sizeof(char *)); +#endif + + HDmemcpy(buf,s,len); + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5T_vlen_str_mem_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_write + * + * Purpose: "Writes" the memory based VL string from a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_str_mem_write(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, const H5T_vlen_alloc_info_t *vl_alloc_info, void *_vl, void *buf, void H5_ATTR_UNUSED *_bg, size_t seq_len, size_t base_size) +{ + char *t; /* Pointer to temporary buffer allocated */ + size_t len; /* Maximum length of the string to copy */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* check parameters */ + HDassert(buf); + + /* Use the user's memory allocation routine if one is defined */ + if(vl_alloc_info->alloc_func!=NULL) { + if(NULL==(t = (char *)(vl_alloc_info->alloc_func)((seq_len+1)*base_size,vl_alloc_info->alloc_info))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data") + } /* end if */ + else { /* Default to system malloc */ + if(NULL == (t = (char *)HDmalloc((seq_len + 1) * base_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for VL data") + } /* end else */ + + len=(seq_len*base_size); + HDmemcpy(t,buf,len); + t[len]='\0'; + + /* Set pointer in user's buffer with memcpy, to avoid alignment issues */ + HDmemcpy(_vl,&t,sizeof(char *)); + +done: + FUNC_LEAVE_NOAPI(ret_value) /*lint !e429 The pointer in 't' has been copied */ +} /* end H5T_vlen_str_mem_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_str_mem_setnull + * + * Purpose: Sets a VL info object in memory to the "null" value + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_str_mem_setnull(H5F_t H5_ATTR_UNUSED *f, hid_t H5_ATTR_UNUSED dxpl_id, void *_vl, void H5_ATTR_UNUSED *_bg) +{ + char *t=NULL; /* Pointer to temporary buffer allocated */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Set pointer in user's buffer with memcpy, to avoid alignment issues */ + HDmemcpy(_vl,&t,sizeof(char *)); + + FUNC_LEAVE_NOAPI(SUCCEED) /*lint !e429 The pointer in 't' has been copied */ +} /* end H5T_vlen_str_mem_setnull() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_getlen + * + * Purpose: Retrieves the length of a disk based VL element. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static ssize_t +H5T_vlen_disk_getlen(const void *_vl) +{ + const uint8_t *vl=(const uint8_t *)_vl; /* Pointer to the disk VL information */ + size_t seq_len = 0; /* Sequence length */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ + HDassert(vl); + + UINT32DECODE(vl, seq_len); + + FUNC_LEAVE_NOAPI((ssize_t)seq_len) +} /* end H5T_vlen_disk_getlen() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_getptr + * + * Purpose: Retrieves the pointer to a disk based VL element. + * + * Return: Non-NULL on success/NULL on failure + * + * Programmer: Quincey Koziol + * Saturday, June 12, 2004 + * + *------------------------------------------------------------------------- + */ +static void * +H5T_vlen_disk_getptr(void H5_ATTR_UNUSED *vl) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ + HDassert(vl); + + FUNC_LEAVE_NOAPI(NULL) +} /* end H5T_vlen_disk_getptr() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_isnull + * + * Purpose: Checks if a disk VL info object is the "nil" object + * + * Return: TRUE/FALSE on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5T_vlen_disk_isnull(const H5F_t *f, void *_vl) +{ + uint8_t *vl = (uint8_t *)_vl; /* Pointer to the disk VL information */ + haddr_t addr; /* Sequence's heap address */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* check parameters */ + HDassert(vl); + + /* Skip the sequence's length */ + vl += 4; + + /* Get the heap address */ + H5F_addr_decode(f, (const uint8_t **)&vl, &addr); + + FUNC_LEAVE_NOAPI(addr == 0 ? TRUE : FALSE) +} /* end H5T_vlen_disk_isnull() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_read + * + * Purpose: Reads the disk based VL element into a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_disk_read(H5F_t *f, hid_t dxpl_id, void *_vl, void *buf, size_t H5_ATTR_UNUSED len) +{ + uint8_t *vl=(uint8_t *)_vl; /* Pointer to the user's hvl_t information */ + H5HG_t hobjid; + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* check parameters */ + HDassert(vl); + HDassert(buf); + HDassert(f); + + /* Skip the length of the sequence */ + vl += 4; + + /* Get the heap information */ + H5F_addr_decode(f,(const uint8_t **)&vl,&(hobjid.addr)); + UINT32DECODE(vl,hobjid.idx); + + /* Check if this sequence actually has any data */ + if(hobjid.addr>0) { + /* Read the VL information from disk */ + if(H5HG_read(f,dxpl_id,&hobjid,buf, NULL)==NULL) + HGOTO_ERROR(H5E_DATATYPE, H5E_READERROR, FAIL, "Unable to read VL information") + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_disk_read() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_write + * + * Purpose: Writes the disk based VL element from a buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, June 2, 1999 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_disk_write(H5F_t *f, hid_t dxpl_id, const H5T_vlen_alloc_info_t H5_ATTR_UNUSED *vl_alloc_info, + void *_vl, void *buf, void *_bg, size_t seq_len, size_t base_size) +{ + uint8_t *vl = (uint8_t *)_vl; /*Pointer to the user's hvl_t information*/ + uint8_t *bg = (uint8_t *)_bg; /*Pointer to the old data hvl_t */ + H5HG_t hobjid; /* New VL sequence's heap ID */ + size_t len; /* Size of new sequence on disk (in bytes) */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* check parameters */ + HDassert(vl); + HDassert(seq_len == 0 || buf); + HDassert(f); + + /* Free heap object for old data. */ + if(bg!=NULL) { + H5HG_t bg_hobjid; /* "Background" VL info sequence's ID info */ + + /* Skip the length of the sequence and heap object ID from background data. */ + bg += 4; + + /* Get heap information */ + H5F_addr_decode(f, (const uint8_t **)&bg, &(bg_hobjid.addr)); + UINT32DECODE(bg, bg_hobjid.idx); + + /* Free heap object for old data */ + if(bg_hobjid.addr > 0) { + /* Free heap object */ + if(H5HG_remove(f, dxpl_id, &bg_hobjid) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to remove heap object") + } /* end if */ + } /* end if */ + + /* Set the length of the sequence */ + UINT32ENCODE(vl, seq_len); + + /* Write the VL information to disk (allocates space also) */ + len = (seq_len*base_size); + if(H5HG_insert(f, dxpl_id, len, buf, &hobjid) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to write VL information") + + /* Encode the heap information */ + H5F_addr_encode(f, &vl, hobjid.addr); + UINT32ENCODE(vl, hobjid.idx); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_disk_write() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_disk_setnull + * + * Purpose: Sets a VL info object on disk to the "nil" value + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, November 8, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5T_vlen_disk_setnull(H5F_t *f, hid_t dxpl_id, void *_vl, void *_bg) +{ + uint8_t *vl = (uint8_t *)_vl; /*Pointer to the user's hvl_t information*/ + uint8_t *bg = (uint8_t *)_bg; /*Pointer to the old data hvl_t */ + uint32_t seq_len = 0; /* Sequence length */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* check parameters */ + HDassert(f); + HDassert(vl); + + /* Free heap object for old data. */ + if(bg != NULL) { + H5HG_t bg_hobjid; /* "Background" VL info sequence's ID info */ + + /* Skip the length of the sequence and heap object ID from background data. */ + bg += 4; + + /* Get heap information */ + H5F_addr_decode(f, (const uint8_t **)&bg, &(bg_hobjid.addr)); + UINT32DECODE(bg, bg_hobjid.idx); + + /* Free heap object for old data */ + if(bg_hobjid.addr > 0) { + /* Free heap object */ + if(H5HG_remove(f, dxpl_id, &bg_hobjid) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_WRITEERROR, FAIL, "Unable to remove heap object") + } /* end if */ + } /* end if */ + + /* Set the length of the sequence */ + UINT32ENCODE(vl, seq_len); + + /* Encode the "nil" heap pointer information */ + H5F_addr_encode(f, &vl, (haddr_t)0); + UINT32ENCODE(vl, 0); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_disk_setnull() */ + + +/*-------------------------------------------------------------------------- + NAME + H5T_vlen_reclaim_recurse + PURPOSE + Internal recursive routine to free VL datatypes + USAGE + herr_t H5T_vlen_reclaim(elem,dt) + void *elem; IN/OUT: Pointer to the dataset element + H5T_t *dt; IN: Datatype of dataset element + + RETURNS + SUCCEED/FAIL + DESCRIPTION + Frees any dynamic memory used by VL datatypes in the current dataset + element. Performs a recursive depth-first traversal of all compound + datatypes to free all VL datatype information allocated by any field. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5T_vlen_reclaim_recurse(void *elem, const H5T_t *dt, H5MM_free_t free_func, void *free_info) +{ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(elem); + HDassert(dt); + + /* Check the datatype of this element */ + switch(dt->shared->type) { + case H5T_ARRAY: + /* Recurse on each element, if the array's base type is array, VL, enum or compound */ + if(H5T_IS_COMPLEX(dt->shared->parent->shared->type)) { + void *off; /* offset of field */ + + /* Calculate the offset member and recurse on it */ + for(u = 0; u < dt->shared->u.array.nelem; u++) { + off = ((uint8_t *)elem) + u * (dt->shared->parent->shared->size); + if(H5T_vlen_reclaim_recurse(off, dt->shared->parent, free_func, free_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free array element") + } /* end for */ + } /* end if */ + break; + + case H5T_COMPOUND: + /* Check each field and recurse on VL, compound, enum or array ones */ + for(u = 0; u < dt->shared->u.compnd.nmembs; u++) { + /* Recurse if it's VL, compound, enum or array */ + if(H5T_IS_COMPLEX(dt->shared->u.compnd.memb[u].type->shared->type)) { + void *off; /* offset of field */ + + /* Calculate the offset member and recurse on it */ + off = ((uint8_t *)elem) + dt->shared->u.compnd.memb[u].offset; + if(H5T_vlen_reclaim_recurse(off, dt->shared->u.compnd.memb[u].type, free_func, free_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free compound field") + } /* end if */ + } /* end for */ + break; + + case H5T_VLEN: + /* Recurse on the VL information if it's VL, compound, enum or array, then free VL sequence */ + if(dt->shared->u.vlen.type == H5T_VLEN_SEQUENCE) { + hvl_t *vl = (hvl_t *)elem; /* Temp. ptr to the vl info */ + + /* Check if there is anything actually in this sequence */ + if(vl->len!=0) { + /* Recurse if it's VL, array, enum or compound */ + if(H5T_IS_COMPLEX(dt->shared->parent->shared->type)) { + void *off; /* offset of field */ + + /* Calculate the offset of each array element and recurse on it */ + while(vl->len > 0) { + off = ((uint8_t *)vl->p) + (vl->len - 1) * dt->shared->parent->shared->size; + if(H5T_vlen_reclaim_recurse(off, dt->shared->parent, free_func, free_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Unable to free VL element") + vl->len--; + } /* end while */ + } /* end if */ + + /* Free the VL sequence */ + if(free_func != NULL) + (*free_func)(vl->p, free_info); + else + HDfree(vl->p); + } /* end if */ + } else if(dt->shared->u.vlen.type == H5T_VLEN_STRING) { + /* Free the VL string */ + if(free_func != NULL) + (*free_func)(*(char **)elem, free_info); + else + HDfree(*(char **)elem); + } else { + HDassert(0 && "Invalid VL type"); + } /* end else */ + break; + + /* Don't do anything for simple types */ + case H5T_INTEGER: + case H5T_FLOAT: + case H5T_TIME: + case H5T_STRING: + case H5T_BITFIELD: + case H5T_OPAQUE: + case H5T_REFERENCE: + case H5T_ENUM: + break; + + /* Should never have these values */ + case H5T_NO_CLASS: + case H5T_NCLASSES: + default: + HGOTO_ERROR(H5E_DATATYPE, H5E_BADRANGE, FAIL, "invalid VL datatype class") + break; + + } /* end switch */ /*lint !e788 All appropriate cases are covered */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_reclaim_recurse() */ + + +/*-------------------------------------------------------------------------- + NAME + H5T_vlen_reclaim + PURPOSE + Default method to reclaim any VL data for a buffer element + USAGE + herr_t H5T_vlen_reclaim(elem,type_id,ndim,point,op_data) + void *elem; IN/OUT: Pointer to the dataset element + hid_t type_id; IN: Datatype of dataset element + unsigned ndim; IN: Number of dimensions in dataspace + hsize_t *point; IN: Coordinate location of element in dataspace + void *op_data IN: Operator data + + RETURNS + SUCCEED/FAIL + DESCRIPTION + Frees any dynamic memory used by VL datatypes in the current dataset + element. Recursively descends compound datatypes to free all VL datatype + information allocated by any field. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5T_vlen_reclaim(void *elem, hid_t type_id, unsigned H5_ATTR_UNUSED ndim, const hsize_t H5_ATTR_UNUSED *point, void *op_data) +{ + H5T_vlen_alloc_info_t *vl_alloc_info = (H5T_vlen_alloc_info_t *)op_data; /* VL allocation info from iterator */ + H5T_t *dt; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(elem); + HDassert(vl_alloc_info); + HDassert(H5I_DATATYPE == H5I_get_type(type_id)); + + /* Check args */ + if(NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + + /* Pull the free function and free info pointer out of the op_data and call the recurse datatype free function */ + if(H5T_vlen_reclaim_recurse(elem, dt, vl_alloc_info->free_func, vl_alloc_info->free_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't reclaim vlen elements") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_reclaim() */ + + +/*-------------------------------------------------------------------------- + NAME + H5T_vlen_get_alloc_info + PURPOSE + Retrieve allocation info for VL datatypes + USAGE + herr_t H5T_vlen_get_alloc_info(dxpl_id,vl_alloc_info) + hid_t dxpl_id; IN: Data transfer property list to query + H5T_vlen_alloc_info_t *vl_alloc_info; IN/OUT: Pointer to VL allocation information to fill + + RETURNS + SUCCEED/FAIL + DESCRIPTION + Retrieve the VL allocation functions and information from a dataset + transfer property list. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + The VL_ALLOC_INFO pointer should point at already allocated memory to place + non-default property list info. If a default property list is used, the + VL_ALLOC_INFO pointer will be changed to point at the default information. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5T_vlen_get_alloc_info(hid_t dxpl_id, H5T_vlen_alloc_info_t **vl_alloc_info) +{ + H5P_genplist_t *plist; /* DX property list */ + herr_t ret_value=SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(H5I_GENPROP_LST == H5I_get_type(dxpl_id)); + HDassert(vl_alloc_info); + + /* Check for the default DXPL */ + if(dxpl_id==H5P_DATASET_XFER_DEFAULT) + *vl_alloc_info=&H5T_vlen_def_vl_alloc_info; + else { + /* Check args */ + if(NULL == (plist = H5P_object_verify(dxpl_id,H5P_DATASET_XFER))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") + + /* Get the allocation functions & information */ + if (H5P_get(plist,H5D_XFER_VLEN_ALLOC_NAME,&(*vl_alloc_info)->alloc_func) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value") + if (H5P_get(plist,H5D_XFER_VLEN_ALLOC_INFO_NAME,&(*vl_alloc_info)->alloc_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value") + if (H5P_get(plist,H5D_XFER_VLEN_FREE_NAME,&(*vl_alloc_info)->free_func) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value") + if (H5P_get(plist,H5D_XFER_VLEN_FREE_INFO_NAME,&(*vl_alloc_info)->free_info) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "unable to get value") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5T_vlen_get_alloc_info() */ + + +/*------------------------------------------------------------------------- + * Function: H5T_vlen_reclaim_elmt + * + * Purpose: Alternative method to reclaim any VL data for a buffer element. + * + * Use this function when the datatype is already available, but + * the allocation info is needed from the dxpl_id before jumping + * into recursion. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Mike McGreevy + * May 11, 2010 + * + *------------------------------------------------------------------------- + */ +herr_t +H5T_vlen_reclaim_elmt(void *elem, H5T_t *dt, hid_t dxpl_id) +{ + H5T_vlen_alloc_info_t _vl_alloc_info; /* VL allocation info buffer */ + H5T_vlen_alloc_info_t *vl_alloc_info = &_vl_alloc_info; /* VL allocation info */ + herr_t ret_value = SUCCEED; /* return value */ + + HDassert(dt); + HDassert(elem); + + FUNC_ENTER_NOAPI(FAIL) + + /* Get VL allocation info */ + if(H5T_vlen_get_alloc_info(dxpl_id, &vl_alloc_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTGET, FAIL, "unable to retrieve VL allocation info") + + /* Recurse on buffer to free dynamic fields */ + if(H5T_vlen_reclaim_recurse(elem, dt, vl_alloc_info->free_func, vl_alloc_info->free_info) < 0) + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "can't reclaim vlen elements") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5T_vlen_reclaim_elmt */ + |