/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*-------------------------------------------------------------------------
 *
 * Created:		H5Pdcpl.c
 *			February 26 1998
 *			Robb Matzke <matzke@llnl.gov>
 *
 * Purpose:		Dataset creation property list class routines
 *
 *-------------------------------------------------------------------------
 */

/****************/
/* Module Setup */
/****************/
#define H5P_PACKAGE		/*suppress error about including H5Ppkg	  */
#define H5Z_PACKAGE		/*suppress error about including H5Zpkg	  */


/***********/
/* Headers */
/***********/
#include "H5private.h"		/* Generic Functions			*/
#include "H5Dprivate.h"		/* Datasets				*/
#include "H5Eprivate.h"		/* Error handling		  	*/
#include "H5Iprivate.h"		/* IDs			  		*/
#include "H5MMprivate.h"	/* Memory management			*/
#include "H5Ppkg.h"		/* Property lists		  	*/
#include "H5Zpkg.h"		/* Data filters				*/


/****************/
/* Local Macros */
/****************/

/* ========  Dataset creation properties ======== */
/* Definitions for storage layout property */
#define H5D_CRT_LAYOUT_SIZE        sizeof(H5D_layout_t)
#define H5D_CRT_LAYOUT_DEF         H5D_CONTIGUOUS
/* Definitions for chunk dimensionality property */
#define H5D_CRT_CHUNK_DIM_SIZE     sizeof(unsigned)
#define H5D_CRT_CHUNK_DIM_DEF      1
/* Definitions for chunk size */
#define H5D_CRT_CHUNK_SIZE_SIZE    sizeof(size_t[H5O_LAYOUT_NDIMS])
#define H5D_CRT_CHUNK_SIZE_DEF     {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\
                                   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
/* Definitions for fill value.  size=0 means fill value will be 0 as
 * library default; size=-1 means fill value is undefined. */
#define H5D_CRT_FILL_VALUE_SIZE    sizeof(H5O_fill_t)
#define H5D_CRT_FILL_VALUE_DEF     {{0, NULL, H5O_NULL_ID, {{0, HADDR_UNDEF}}}, H5O_FILL_VERSION_2, NULL, 0, NULL, H5D_ALLOC_TIME_LATE, H5D_FILL_TIME_IFSET, FALSE}
#define H5D_CRT_FILL_VALUE_CMP     H5P_fill_value_cmp
/* Definitions for space allocation time state */
#define H5D_CRT_ALLOC_TIME_STATE_SIZE   sizeof(unsigned)
#define H5D_CRT_ALLOC_TIME_STATE_DEF    1
/* Definitions for external file list */
#define H5D_CRT_EXT_FILE_LIST_SIZE sizeof(H5O_efl_t)
#define H5D_CRT_EXT_FILE_LIST_DEF  {HADDR_UNDEF, 0, 0, NULL}
#define H5D_CRT_EXT_FILE_LIST_CMP  H5P_dcrt_ext_file_list_cmp
/* Definitions for data filter pipeline */
#define H5D_CRT_DATA_PIPELINE_SIZE sizeof(H5O_pline_t)
#define H5D_CRT_DATA_PIPELINE_DEF  {{0, NULL, H5O_NULL_ID, {{0, HADDR_UNDEF}}}, H5O_PLINE_VERSION_1, 0, 0, NULL}
#define H5D_CRT_DATA_PIPELINE_CMP  H5P_dcrt_data_pipeline_cmp


/******************/
/* Local Typedefs */
/******************/


/********************/
/* Package Typedefs */
/********************/


/********************/
/* Local Prototypes */
/********************/

/* General routines */
static herr_t H5P_set_layout(H5P_genplist_t *plist, H5D_layout_t layout);

/* Property class callbacks */
static herr_t H5P_dcrt_reg_prop(H5P_genclass_t *pclass);
static herr_t H5P_dcrt_copy(hid_t new_plist_t, hid_t old_plist_t, void *copy_data);
static herr_t H5P_dcrt_close(hid_t dxpl_id, void *close_data);

/* Property callbacks */
static int H5P_dcrt_ext_file_list_cmp(const void *value1, const void *value2, size_t size);
static int H5P_dcrt_data_pipeline_cmp(const void *value1, const void *value2, size_t size);


/*********************/
/* Package Variables */
/*********************/

/* Dataset creation property list class library initialization object */
const H5P_libclass_t H5P_CLS_DCRT[1] = {{
    "dataset create",		/* Class name for debugging     */
    &H5P_CLS_OBJECT_CREATE_g,	/* Parent class ID              */
    &H5P_CLS_DATASET_CREATE_g,	/* Pointer to class ID          */
    &H5P_LST_DATASET_CREATE_g,	/* Pointer to default property list ID */
    H5P_dcrt_reg_prop,		/* Default property registration routine */
    NULL,		        /* Class creation callback      */
    NULL,		        /* Class creation callback info */
    H5P_dcrt_copy,		/* Class copy callback          */
    NULL,		        /* Class copy callback info     */
    H5P_dcrt_close,		/* Class close callback         */
    NULL 		        /* Class close callback info    */
}};


/*****************************/
/* Library Private Variables */
/*****************************/

/* Declare extern the free list to manage blocks of type conversion data */
H5FL_BLK_EXTERN(type_conv);



/*-------------------------------------------------------------------------
 * Function:    H5P_dcrt_reg_prop
 *
 * Purpose:     Register the dataset creation property list class's properties
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Quincey Koziol
 *              October 31, 2006
 *-------------------------------------------------------------------------
 */
static herr_t
H5P_dcrt_reg_prop(H5P_genclass_t *pclass)
{
    H5D_layout_t layout = H5D_CRT_LAYOUT_DEF;           /* Default storage layout */
    unsigned chunk_ndims = H5D_CRT_CHUNK_DIM_DEF;       /* Default rank for chunks */
    size_t chunk_size[H5O_LAYOUT_NDIMS] = H5D_CRT_CHUNK_SIZE_DEF;       /* Default chunk size */
    H5O_fill_t fill = H5D_CRT_FILL_VALUE_DEF;           /* Default fill value */
    unsigned alloc_time_state = H5D_CRT_ALLOC_TIME_STATE_DEF;   /* Default allocation time state */
    H5O_efl_t efl = H5D_CRT_EXT_FILE_LIST_DEF;          /* Default external file list */
    H5O_pline_t pline = H5D_CRT_DATA_PIPELINE_DEF;      /* Default I/O pipeline setting */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5P_dcrt_reg_prop)

    /* Register the storage layout property */
    if(H5P_register(pclass, H5D_CRT_LAYOUT_NAME, H5D_CRT_LAYOUT_SIZE, &layout, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the chunking dimensionality property */
    if(H5P_register(pclass, H5D_CRT_CHUNK_DIM_NAME, H5D_CRT_CHUNK_DIM_SIZE, &chunk_ndims, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the chunking size property */
    if(H5P_register(pclass, H5D_CRT_CHUNK_SIZE_NAME, H5D_CRT_CHUNK_SIZE_SIZE, chunk_size, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the fill value property */
    if(H5P_register(pclass, H5D_CRT_FILL_VALUE_NAME, H5D_CRT_FILL_VALUE_SIZE, &fill, NULL, NULL, NULL, NULL, NULL, H5D_CRT_FILL_VALUE_CMP, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the space allocation time state property */
    if(H5P_register(pclass, H5D_CRT_ALLOC_TIME_STATE_NAME, H5D_CRT_ALLOC_TIME_STATE_SIZE, &alloc_time_state, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the external file list property */
    if(H5P_register(pclass, H5D_CRT_EXT_FILE_LIST_NAME, H5D_CRT_EXT_FILE_LIST_SIZE, &efl, NULL, NULL, NULL, NULL, NULL, H5D_CRT_EXT_FILE_LIST_CMP, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

    /* Register the data pipeline property */
    if(H5P_register(pclass, H5D_CRT_DATA_PIPELINE_NAME, H5D_CRT_DATA_PIPELINE_SIZE, &pline, NULL, NULL, NULL, NULL, NULL, H5D_CRT_DATA_PIPELINE_CMP, NULL) < 0)
       HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_dcrt_reg_prop() */


/*-------------------------------------------------------------------------
 * Function:       H5P_dcrt_copy
 *
 * Purpose:        Callback routine which is called whenever any dataset
 *                 creation property list is copied.  This routine copies
 *                 the properties from the old list to the new list.
 *
 * Return:         Success:        Non-negative
 *                 Failure:        Negative
 *
 * Programmer:     Raymond Lu
 *                 Tuesday, October 2, 2001
 *
 * Modifications:  pvn, April 02, 2007
 *  Reset external file list slots name_offset to a state when created
 *
 *-------------------------------------------------------------------------
 */
/* ARGSUSED */
static herr_t
H5P_dcrt_copy(hid_t dst_plist_id, hid_t src_plist_id, void UNUSED *copy_data)
{
    H5O_fill_t     src_fill, dst_fill;          /* Source & destination fill values */
    H5O_efl_t      src_efl, dst_efl;            /* Source & destination external file lists */
    H5O_pline_t    src_pline, dst_pline;        /* Source & destination I/O pipelines */
    H5P_genplist_t *src_plist;                  /* Pointer to source property list */
    H5P_genplist_t *dst_plist;                  /* Pointer to destination property list */
    herr_t         ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5P_dcrt_copy)

    /* Verify property list IDs */
    if(NULL == (dst_plist = H5I_object(dst_plist_id)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")
    if(NULL == (src_plist = H5I_object(src_plist_id)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")

    /* Get the fill value, external file list, and data pipeline properties
     * from the old property list */
    if(H5P_get(src_plist, H5D_CRT_FILL_VALUE_NAME, &src_fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
    if(H5P_get(src_plist, H5D_CRT_EXT_FILE_LIST_NAME, &src_efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
    if(H5P_get(src_plist, H5D_CRT_DATA_PIPELINE_NAME, &src_pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Make copies of fill value, external file list, and data pipeline */
    if(NULL == H5O_msg_copy(H5O_FILL_ID, &src_fill, &dst_fill))
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't copy fill value")
    HDmemset(&dst_efl, 0, sizeof(H5O_efl_t));
    if(NULL == H5O_msg_copy(H5O_EFL_ID, &src_efl, &dst_efl))
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't copy external file list")

    /* reset efl name_offset and heap_addr, these are the values when the dataset is created */
    if (dst_efl.slot)
    {
        unsigned int i;

        dst_efl.heap_addr = HADDR_UNDEF;
        for ( i = 0; i < dst_efl.nused; i++)
        {
            dst_efl.slot[i].name_offset = 0;
        }
        
    }


    if(NULL == H5O_msg_copy(H5O_PLINE_ID, &src_pline, &dst_pline))
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't copy data pipeline")

    /* Set the fill value, external file list, and data pipeline property
     * for the destination property list */
    if(H5P_set(dst_plist, H5D_CRT_FILL_VALUE_NAME, &dst_fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value")
    if(H5P_set(dst_plist, H5D_CRT_EXT_FILE_LIST_NAME, &dst_efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set external file list")
    if(H5P_set(dst_plist, H5D_CRT_DATA_PIPELINE_NAME, &dst_pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_dcrt_copy() */


/*-------------------------------------------------------------------------
 * Function:	H5P_dcrt_close
 *
 * Purpose:	Callback routine which is called whenever any dataset create
 *              property list is closed.  This routine performs any generic
 *              cleanup needed on the properties the library put into the list.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, July 11, 2001
 *
 *-------------------------------------------------------------------------
 */
/* ARGSUSED */
static herr_t
H5P_dcrt_close(hid_t dcpl_id, void UNUSED *close_data)
{
    H5O_fill_t      fill;               /* Fill value */
    H5O_efl_t       efl;                /* External file list */
    H5O_pline_t     pline;              /* I/O pipeline */
    H5P_genplist_t *plist;              /* Property list */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_NOAPI_NOINIT(H5P_dcrt_close)

    /* Check arguments */
    if(NULL == (plist = H5I_object(dcpl_id)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")

    /* Get the fill value, external file list, and data pipeline properties
     * from the old property list */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
    if(H5P_get(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Clean up any values set for the fill-value, external file-list and
     * data pipeline */
    if(H5O_msg_reset(H5O_FILL_ID, &fill) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release fill info")
    if(H5O_msg_reset(H5O_EFL_ID, &efl) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release external file list info")
    if(H5O_msg_reset(H5O_PLINE_ID, &pline) < 0)
        HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "can't release pipeline info")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_dcrt_close() */


/*-------------------------------------------------------------------------
 * Function:       H5P_fill_value_cmp
 *
 * Purpose:        Callback routine which is called whenever the fill value
 *                 property in the dataset creation property list is compared.
 *
 * Return:         positive if VALUE1 is greater than VALUE2, negative if
 *                      VALUE2 is greater than VALUE1 and zero if VALUE1 and
 *                      VALUE2 are equal.
 *
 * Programmer:     Quincey Koziol
 *                 Wednesday, January 7, 2004
 *
 *-------------------------------------------------------------------------
 */
int
H5P_fill_value_cmp(const void *_fill1, const void *_fill2, size_t UNUSED size)
{
    const H5O_fill_t *fill1 = (const H5O_fill_t *)_fill1,     /* Create local aliases for values */
        *fill2 = (const H5O_fill_t *)_fill2;
    int cmp_value;              /* Value from comparison */
    herr_t ret_value = 0;       /* Return value */

    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_fill_value_cmp)

    /* Sanity check */
    HDassert(fill1);
    HDassert(fill2);
    HDassert(size == sizeof(H5O_fill_t));

    /* Check the size of fill values */
    if(fill1->size < fill2->size) HGOTO_DONE(-1);
    if(fill1->size > fill2->size) HGOTO_DONE(1);

    /* Check the types of the fill values */
    if(fill1->type == NULL && fill2->type != NULL) HGOTO_DONE(-1);
    if(fill1->type != NULL && fill2->type == NULL) HGOTO_DONE(1);
    if(fill1->type != NULL)
        if((cmp_value = H5T_cmp(fill1->type, fill2->type, FALSE)) != 0)
            HGOTO_DONE(cmp_value);

    /* Check the fill values in the buffers */
    if(fill1->buf == NULL && fill2->buf != NULL) HGOTO_DONE(-1);
    if(fill1->buf != NULL && fill2->buf == NULL) HGOTO_DONE(1);
    if(fill1->buf != NULL)
        if((cmp_value = HDmemcmp(fill1->buf, fill2->buf, (size_t)fill1->size)) != 0)
            HGOTO_DONE(cmp_value);

    /* Check the allocation time for the fill values */
    if(fill1->alloc_time < fill2->alloc_time) HGOTO_DONE(-1);
    if(fill1->alloc_time > fill2->alloc_time) HGOTO_DONE(1);

    /* Check the fill time for the fill values */
    if(fill1->fill_time < fill2->fill_time) HGOTO_DONE(-1);
    if(fill1->fill_time > fill2->fill_time) HGOTO_DONE(1);

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_fill_value_cmp() */


/*-------------------------------------------------------------------------
 * Function:       H5P_dcrt_ext_file_list_cmp
 *
 * Purpose:        Callback routine which is called whenever the external file
 *                 list property in the dataset creation property list is
 *                 compared.
 *
 * Return:         positive if VALUE1 is greater than VALUE2, negative if
 *                      VALUE2 is greater than VALUE1 and zero if VALUE1 and
 *                      VALUE2 are equal.
 *
 * Programmer:     Quincey Koziol
 *                 Wednesday, January 7, 2004
 *
 *-------------------------------------------------------------------------
 */
static int
H5P_dcrt_ext_file_list_cmp(const void *_efl1, const void *_efl2, size_t UNUSED size)
{
    const H5O_efl_t *efl1 = (const H5O_efl_t *)_efl1,     /* Create local aliases for values */
        *efl2 = (const H5O_efl_t *)_efl2;
    int cmp_value;              /* Value from comparison */
    herr_t ret_value = 0;       /* Return value */

    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_dcrt_ext_file_list_cmp)

    /* Sanity check */
    HDassert(efl1);
    HDassert(efl2);
    HDassert(size == sizeof(H5O_efl_t));

    /* Check the heap address of external file lists */
    if(H5F_addr_defined(efl1->heap_addr) || H5F_addr_defined(efl2->heap_addr)) {
        if(!H5F_addr_defined(efl1->heap_addr) && H5F_addr_defined(efl2->heap_addr)) HGOTO_DONE(-1);
        if(H5F_addr_defined(efl1->heap_addr) && !H5F_addr_defined(efl2->heap_addr)) HGOTO_DONE(1);
        if((cmp_value = H5F_addr_cmp(efl1->heap_addr, efl2->heap_addr)) != 0)
            HGOTO_DONE(cmp_value);
    } /* end if */

    /* Check the number of allocated efl entries */
    if(efl1->nalloc < efl2->nalloc) HGOTO_DONE(-1);
    if(efl1->nalloc > efl2->nalloc) HGOTO_DONE(1);

    /* Check the number of used efl entries */
    if(efl1->nused < efl2->nused) HGOTO_DONE(-1);
    if(efl1->nused > efl2->nused) HGOTO_DONE(1);

    /* Check the efl entry information */
    if(efl1->slot == NULL && efl2->slot != NULL) HGOTO_DONE(-1);
    if(efl1->slot != NULL && efl2->slot == NULL) HGOTO_DONE(1);
    if(efl1->slot != NULL && efl1->nused > 0) {
        size_t u;       /* Local index variable */

        /* Loop through all entries, comparing them */
        for(u = 0; u < efl1->nused; u++) {
            /* Check the name offset of the efl entry */
            if(efl1->slot[u].name_offset < efl2->slot[u].name_offset) HGOTO_DONE(-1);
            if(efl1->slot[u].name_offset > efl2->slot[u].name_offset) HGOTO_DONE(1);

            /* Check the name of the efl entry */
            if(efl1->slot[u].name == NULL && efl2->slot[u].name != NULL) HGOTO_DONE(-1);
            if(efl1->slot[u].name != NULL && efl2->slot[u].name == NULL) HGOTO_DONE(1);
            if(efl1->slot[u].name != NULL)
                if((cmp_value = HDstrcmp(efl1->slot[u].name, efl2->slot[u].name)) != 0)
                    HGOTO_DONE(cmp_value);

            /* Check the file offset of the efl entry */
            if(efl1->slot[u].offset < efl2->slot[u].offset) HGOTO_DONE(-1);
            if(efl1->slot[u].offset > efl2->slot[u].offset) HGOTO_DONE(1);

            /* Check the file size of the efl entry */
            if(efl1->slot[u].size < efl2->slot[u].size) HGOTO_DONE(-1);
            if(efl1->slot[u].size > efl2->slot[u].size) HGOTO_DONE(1);
        } /* end for */
    } /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_dcrt_ext_file_list_cmp() */


/*-------------------------------------------------------------------------
 * Function:       H5P_dcrt_data_pipeline_cmp
 *
 * Purpose:        Callback routine which is called whenever the filter pipeline
 *                 property in the dataset creation property list is compared.
 *
 * Return:         positive if VALUE1 is greater than VALUE2, negative if
 *                      VALUE2 is greater than VALUE1 and zero if VALUE1 and
 *                      VALUE2 are equal.
 *
 * Programmer:     Quincey Koziol
 *                 Wednesday, January 7, 2004
 *
 *-------------------------------------------------------------------------
 */
static int
H5P_dcrt_data_pipeline_cmp(const void *_pline1, const void *_pline2, size_t UNUSED size)
{
    const H5O_pline_t *pline1 = (const H5O_pline_t *)_pline1,     /* Create local aliases for values */
        *pline2 = (const H5O_pline_t *)_pline2;
    int cmp_value;              /* Value from comparison */
    herr_t ret_value = 0; /* Return value */

    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_dcrt_data_pipeline_cmp)

    /* Sanity check */
    HDassert(pline1);
    HDassert(pline2);
    HDassert(size == sizeof(H5O_pline_t));

    /* Check the number of allocated pipeline entries */
    if(pline1->nalloc < pline2->nalloc) HGOTO_DONE(-1);
    if(pline1->nalloc > pline2->nalloc) HGOTO_DONE(1);

    /* Check the number of used pipeline entries */
    if(pline1->nused < pline2->nused) HGOTO_DONE(-1);
    if(pline1->nused > pline2->nused) HGOTO_DONE(1);

    /* Check the filter entry information */
    if(pline1->filter == NULL && pline2->filter != NULL) HGOTO_DONE(-1);
    if(pline1->filter != NULL && pline2->filter == NULL) HGOTO_DONE(1);
    if(pline1->filter != NULL && pline1->nused > 0) {
        size_t u;       /* Local index variable */

        /* Loop through all filters, comparing them */
        for(u = 0; u < pline1->nused; u++) {
            /* Check the ID of the filter */
            if(pline1->filter[u].id < pline2->filter[u].id) HGOTO_DONE(-1);
            if(pline1->filter[u].id > pline2->filter[u].id) HGOTO_DONE(1);

            /* Check the flags for the filter */
            if(pline1->filter[u].flags < pline2->filter[u].flags) HGOTO_DONE(-1);
            if(pline1->filter[u].flags > pline2->filter[u].flags) HGOTO_DONE(1);

            /* Check the name of the filter */
            if(pline1->filter[u].name == NULL && pline2->filter[u].name != NULL) HGOTO_DONE(-1);
            if(pline1->filter[u].name != NULL && pline2->filter[u].name == NULL) HGOTO_DONE(1);
            if(pline1->filter[u].name != NULL)
                if((cmp_value = HDstrcmp(pline1->filter[u].name, pline2->filter[u].name)) != 0)
                    HGOTO_DONE(cmp_value);

            /* Check the number of parameters for the filter */
            if(pline1->filter[u].cd_nelmts < pline2->filter[u].cd_nelmts) HGOTO_DONE(-1);
            if(pline1->filter[u].cd_nelmts > pline2->filter[u].cd_nelmts) HGOTO_DONE(1);

            /* Check the filter parameter information */
            if(pline1->filter[u].cd_values == NULL && pline2->filter[u].cd_values != NULL) HGOTO_DONE(-1);
            if(pline1->filter[u].cd_values != NULL && pline2->filter[u].cd_values == NULL) HGOTO_DONE(1);
            if(pline1->filter[u].cd_values != NULL && pline1->filter[u].cd_nelmts > 0) {
                size_t v;       /* Local index variable */

                /* Loop through all parameters, comparing them */
                for(v = 0; v < pline1->filter[u].cd_nelmts; v++) {
                    /* Check each parameter for the filter */
                    if(pline1->filter[u].cd_values[v] < pline2->filter[u].cd_values[v]) HGOTO_DONE(-1);
                    if(pline1->filter[u].cd_values[v] > pline2->filter[u].cd_values[v]) HGOTO_DONE(1);
                } /* end for */
            } /* end if */
        } /* end for */
    } /* end if */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_dcrt_data_pipeline_cmp() */


/*-------------------------------------------------------------------------
 * Function:  H5P_set_layout
 *
 * Purpose:   Sets the layout of raw data in the file.
 *
 * Return:    Non-negative on success/Negative on failure
 *
 * Programmer:        Quincey Koziol
 *            Tuesday, November 23, 2004
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P_set_layout(H5P_genplist_t *plist, H5D_layout_t layout)
{
    unsigned alloc_time_state;          /* State of allocation time property */
    herr_t ret_value = SUCCEED;         /* return value */

    FUNC_ENTER_NOAPI_NOINIT(H5P_set_layout)

    /* Get the allocation time state */
    if(H5P_get(plist, H5D_CRT_ALLOC_TIME_STATE_NAME, &alloc_time_state) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get space allocation time state")

    /* If we still have the "default" allocation time, change it according to the new layout */
    if(alloc_time_state) {
        H5O_fill_t fill;            /* Fill value */

        /* Get current fill value info */
        if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

        /* Set the default based on layout */
        switch(layout) {
            case H5D_COMPACT:
                fill.alloc_time = H5D_ALLOC_TIME_EARLY;
                break;

            case H5D_CONTIGUOUS:
                fill.alloc_time = H5D_ALLOC_TIME_LATE;
                break;

            case H5D_CHUNKED:
                fill.alloc_time = H5D_ALLOC_TIME_INCR;
                break;

            default:
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown layou t type")
        } /* end switch */

        /* Set updated fill value info */
        if(H5P_set(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set space allocat ion time")
    } /* end if */

    /* Set layout value */
    if(H5P_set(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set layout")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_set_layout() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_layout
 *
 * Purpose:	Sets the layout of raw data in the file.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *		Tuesday, January  6, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_layout(hid_t plist_id, H5D_layout_t layout)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_layout, FAIL)
    H5TRACE2("e", "iDl", plist_id, layout);

    /* Check arguments */
    if (layout < 0 || layout >= H5D_NLAYOUTS)
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "raw data layout method is not valid")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Set value */
    if(H5P_set_layout (plist, layout) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set layout")

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pget_layout
 *
 * Purpose:	Retrieves layout type of a dataset creation property list.
 *
 * Return:	Success:	The layout type
 *
 *		Failure:	H5D_LAYOUT_ERROR (negative)
 *
 * Programmer:	Robb Matzke
 *		Wednesday, January  7, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and get property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
H5D_layout_t
H5Pget_layout(hid_t plist_id)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    H5D_layout_t   ret_value=H5D_LAYOUT_ERROR;

    FUNC_ENTER_API(H5Pget_layout, H5D_LAYOUT_ERROR)
    H5TRACE1("Dl", "i", plist_id);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5D_LAYOUT_ERROR, "can't find object for ID")

    /* Get value */
    if(H5P_get(plist, H5D_CRT_LAYOUT_NAME, &ret_value) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5D_LAYOUT_ERROR, "can't get layout")

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pset_chunk
 *
 * Purpose:	Sets the number of dimensions and the size of each chunk to
 *		the values specified.  The dimensionality of the chunk should
 *		match the dimensionality of the data space.
 *
 *		As a side effect, the layout method is changed to
 *		H5D_CHUNKED.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *		Tuesday, January  6, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_chunk(hid_t plist_id, int ndims, const hsize_t dim[/*ndims*/])
{
    int			    i;
    size_t real_dims[H5O_LAYOUT_NDIMS]; /* Full-sized array to hold chunk dims */
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_chunk, FAIL)
    H5TRACE3("e", "iIs*[a1]h", plist_id, ndims, dim);

    /* Check arguments */
    if (ndims <= 0)
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk dimensionality must be positive")
    if (ndims > H5S_MAX_RANK)
        HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "chunk dimensionality is too large")
    if (!dim)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no chunk dimensions specified")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Initialize chunk dims to 0s */
    HDmemset(real_dims,0,sizeof(real_dims));
    for (i=0; i<ndims; i++) {
        if (dim[i] == 0)
            HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all chunk dimensions must be positive")
        if (dim[i] != (dim[i]&0xffffffff))
            HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "all chunk dimensions must be less than 2^32")
        real_dims[i]=(size_t)dim[i]; /* Store user's chunk dimensions */
    } /* end for */

    if(H5P_set_layout (plist, H5D_CHUNKED) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set layout")
    if(H5P_set(plist, H5D_CRT_CHUNK_DIM_NAME, &ndims) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set chunk dimensionanlity")
    if(H5P_set(plist, H5D_CRT_CHUNK_SIZE_NAME, real_dims) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set chunk size")

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pget_chunk
 *
 * Purpose:	Retrieves the chunk size of chunked layout.  The chunk
 *		dimensionality is returned and the chunk size in each
 *		dimension is returned through the DIM argument.	 At most
 *		MAX_NDIMS elements of DIM will be initialized.
 *
 * Return:	Success:	Positive Chunk dimensionality.
 *
 *		Failure:	Negative
 *
 * Programmer:	Robb Matzke
 *		Wednesday, January  7, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
int
H5Pget_chunk(hid_t plist_id, int max_ndims, hsize_t dim[]/*out*/)
{
    int                 ndims;
    H5D_layout_t        layout;
    H5P_genplist_t *plist;      /* Property list pointer */
    int                 ret_value;

    FUNC_ENTER_API(H5Pget_chunk, FAIL)
    H5TRACE3("Is", "iIsx", plist_id, max_ndims, dim);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    if(H5P_get(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't get layout")
    if(H5D_CHUNKED != layout)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "not a chunked storage layout")

    if(H5P_get(plist, H5D_CRT_CHUNK_DIM_NAME, &ndims) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get chunk dimensionality")

    if(dim) {
        int		i;
        size_t          chunk_size[H5O_LAYOUT_NDIMS];

        if(H5P_get(plist, H5D_CRT_CHUNK_SIZE_NAME, chunk_size) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get chunk size")

        /* Get the dimension sizes */
        for (i=0; i<ndims && i<max_ndims; i++)
            dim[i] = chunk_size[i];
    } /* end if */

    /* Set the return value */
    ret_value=ndims;

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pset_external
 *
 * Purpose:	Adds an external file to the list of external files. PLIST_ID
 *		should be an object ID for a dataset creation property list.
 *		NAME is the name of an external file, OFFSET is the location
 *		where the data starts in that file, and SIZE is the number of
 *		bytes reserved in the file for the data.
 *
 *		If a dataset is split across multiple files then the files
 *		should be defined in order. The total size of the dataset is
 *		the sum of the SIZE arguments for all the external files.  If
 *		the total size is larger than the size of a dataset then the
 *		dataset can be extended (provided the data space also allows
 *		the extending).
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *		Tuesday, March	3, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_external(hid_t plist_id, const char *name, off_t offset, hsize_t size)
{
    size_t		idx;
    hsize_t		total, tmp;
    H5O_efl_t           efl;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t      ret_value=SUCCEED;       /* Return value */

    FUNC_ENTER_API(H5Pset_external, FAIL)
    H5TRACE4("e", "i*soh", plist_id, name, offset, size);

    /* Check arguments */
    if (!name || !*name)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "no name given")
    if (offset<0)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "negative external file offset")
    if (size<=0)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "zero size")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    if(H5P_get(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")
    if(efl.nused > 0 && H5O_EFL_UNLIMITED==efl.slot[efl.nused-1].size)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "previous file size is unlimited")

    if (H5O_EFL_UNLIMITED!=size) {
        for (idx=0, total=size; idx<efl.nused; idx++, total=tmp) {
            tmp = total + efl.slot[idx].size;
            if (tmp <= total)
                HGOTO_ERROR (H5E_EFL, H5E_OVERFLOW, FAIL, "total external data size overflowed")
        } /* end for */
    } /* end if */


    /* Add to the list */
    if (efl.nused >= efl.nalloc) {
        size_t na = efl.nalloc + H5O_EFL_ALLOC;
        H5O_efl_entry_t *x = H5MM_realloc (efl.slot, na*sizeof(H5O_efl_entry_t));

        if (!x)
            HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
        efl.nalloc = na;
        efl.slot = x;
    }
    idx = efl.nused;
    efl.slot[idx].name_offset = 0; /*not entered into heap yet*/
    efl.slot[idx].name = H5MM_xstrdup (name);
    efl.slot[idx].offset = offset;
    efl.slot[idx].size = size;
    efl.nused++;

    if(H5P_set(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't set external file list")

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pget_external_count
 *
 * Purpose:	Returns the number of external files for this dataset.
 *
 * Return:	Success:	Number of external files
 *
 *		Failure:	Negative
 *
 * Programmer:	Robb Matzke
 *              Tuesday, March  3, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
int
H5Pget_external_count(hid_t plist_id)
{
    H5O_efl_t           efl;
    H5P_genplist_t *plist;      /* Property list pointer */
    int ret_value;              /* return value */

    FUNC_ENTER_API(H5Pget_external_count, FAIL)
    H5TRACE1("Is", "i", plist_id);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get value */
    if(H5P_get(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")

    /* Set return value */
    ret_value=(int)efl.nused;

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pget_external
 *
 * Purpose:	Returns information about an external file.  External files
 *		are numbered from zero to N-1 where N is the value returned
 *		by H5Pget_external_count().  At most NAME_SIZE characters are
 *		copied into the NAME array.  If the external file name is
 *		longer than NAME_SIZE with the null terminator, then the
 *		return value is not null terminated (similar to strncpy()).
 *
 *		If NAME_SIZE is zero or NAME is the null pointer then the
 *		external file name is not returned.  If OFFSET or SIZE are
 *		null pointers then the corresponding information is not
 *		returned.
 *
 * See Also:	H5Pset_external()
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Tuesday, March  3, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and get property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_external(hid_t plist_id, unsigned idx, size_t name_size, char *name/*out*/,
		 off_t *offset/*out*/, hsize_t *size/*out*/)
{
    H5O_efl_t           efl;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pget_external, FAIL)
    H5TRACE6("e", "iIuzxxx", plist_id, idx, name_size, name, offset, size);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get value */
    if(H5P_get(plist, H5D_CRT_EXT_FILE_LIST_NAME, &efl) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get external file list")

    if (idx>=efl.nused)
        HGOTO_ERROR (H5E_ARGS, H5E_BADRANGE, FAIL, "external file index is out of range")

    /* Return values */
    if (name_size>0 && name)
        HDstrncpy (name, efl.slot[idx].name, name_size);
    if (offset)
        *offset = efl.slot[idx].offset;
    if (size)
        *size = efl.slot[idx].size;

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5P_modify_filter
 *
 * Purpose:	Modifies the specified FILTER in the
 *		transient or permanent output filter pipeline
 *		depending on whether PLIST is a dataset creation or dataset
 *		transfer property list.  The FLAGS argument specifies certain
 *		general properties of the filter and is documented below.
 *		The CD_VALUES is an array of CD_NELMTS integers which are
 *		auxiliary data for the filter.  The integer vlues will be
 *		stored in the dataset object header as part of the filter
 *		information.
 *
 * 		The FLAGS argument is a bit vector of the following fields:
 *
 * 		H5Z_FLAG_OPTIONAL(0x0001)
 *		If this bit is set then the filter is optional.  If the
 *		filter fails during an H5Dwrite() operation then the filter
 *		is just excluded from the pipeline for the chunk for which it
 *		failed; the filter will not participate in the pipeline
 *		during an H5Dread() of the chunk.  If this bit is clear and
 *		the filter fails then the entire I/O operation fails.
 *      If this bit is set but encoding is disabled for a filter,
 *      attempting to write will generate an error.
 *
 * Note:	This function currently supports only the permanent filter
 *		pipeline.  That is, PLIST_ID must be a dataset creation
 *		property list.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, October 17, 2007
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5P_modify_filter(H5P_genplist_t *plist, H5Z_filter_t filter, unsigned flags,
    size_t cd_nelmts, const unsigned cd_values[/*cd_nelmts*/])
{
    H5O_pline_t         pline;
    herr_t ret_value = SUCCEED;   /* return value */

    FUNC_ENTER_NOAPI(H5P_modify_filter, FAIL)

    /* Get the pipeline property to append to */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Modify the filter parameters of the I/O pipeline */
    if(H5Z_modify(&pline, filter, flags, cd_nelmts, cd_values) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add filter to pipeline")

    /* Put the I/O pipeline information back into the property list */
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_modify_filter() */


/*-------------------------------------------------------------------------
 * Function:	H5Pmodify_filter
 *
 * Purpose:	Modifies the specified FILTER in the
 *		transient or permanent output filter pipeline
 *		depending on whether PLIST is a dataset creation or dataset
 *		transfer property list.  The FLAGS argument specifies certain
 *		general properties of the filter and is documented below.
 *		The CD_VALUES is an array of CD_NELMTS integers which are
 *		auxiliary data for the filter.  The integer vlues will be
 *		stored in the dataset object header as part of the filter
 *		information.
 *
 * 		The FLAGS argument is a bit vector of the following fields:
 *
 * 		H5Z_FLAG_OPTIONAL(0x0001)
 *		If this bit is set then the filter is optional.  If the
 *		filter fails during an H5Dwrite() operation then the filter
 *		is just excluded from the pipeline for the chunk for which it
 *		failed; the filter will not participate in the pipeline
 *		during an H5Dread() of the chunk.  If this bit is clear and
 *		the filter fails then the entire I/O operation fails.
 *      If this bit is set but encoding is disabled for a filter,
 *      attempting to write will generate an error.
 *
 * Note:	This function currently supports only the permanent filter
 *		pipeline.  That is, PLIST_ID must be a dataset creation
 *		property list.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Friday, April  5, 2003
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pmodify_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int flags,
	       size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
{
    H5P_genplist_t *plist;              /* Property list pointer */
    herr_t ret_value = SUCCEED;         /* return value */

    FUNC_ENTER_API(H5Pmodify_filter, FAIL)
    H5TRACE5("e", "iZfIuz*[a3]Iu", plist_id, filter, flags, cd_nelmts, cd_values);

    /* Check args */
    if (filter<0 || filter>H5Z_FILTER_MAX)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identifier")
    if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
    if (cd_nelmts>0 && !cd_values)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no client data values supplied")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Modify the filter parameters of the I/O pipeline */
    if(H5P_modify_filter(plist, filter, flags, cd_nelmts, cd_values) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTINIT, FAIL, "can't modify filter")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pmodify_filter() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_filter
 *
 * Purpose:	Adds the specified FILTER and corresponding properties to the
 *		end of the transient or permanent output filter pipeline
 *		depending on whether PLIST is a dataset creation or dataset
 *		transfer property list.  The FLAGS argument specifies certain
 *		general properties of the filter and is documented below.
 *		The CD_VALUES is an array of CD_NELMTS integers which are
 *		auxiliary data for the filter.  The integer vlues will be
 *		stored in the dataset object header as part of the filter
 *		information.
 *
 * 		The FLAGS argument is a bit vector of the following fields:
 *
 * 		H5Z_FLAG_OPTIONAL(0x0001)
 *		If this bit is set then the filter is optional.  If the
 *		filter fails during an H5Dwrite() operation then the filter
 *		is just excluded from the pipeline for the chunk for which it
 *		failed; the filter will not participate in the pipeline
 *		during an H5Dread() of the chunk.  If this bit is clear and
 *		the filter fails then the entire I/O operation fails.
 *      If this bit is set but encoding is disabled for a filter,
 *      attempting to write will generate an error.
 *
 * Note:	This function currently supports only the permanent filter
 *		pipeline.  That is, PLIST_ID must be a dataset creation
 *		property list.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Wednesday, April 15, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_filter(hid_t plist_id, H5Z_filter_t filter, unsigned int flags,
	       size_t cd_nelmts, const unsigned int cd_values[/*cd_nelmts*/])
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_filter, FAIL)
    H5TRACE5("e", "iZfIuz*[a3]Iu", plist_id, filter, flags, cd_nelmts, cd_values);

    /* Check args */
    if (filter<0 || filter>H5Z_FILTER_MAX)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid filter identifier")
    if (flags & ~((unsigned)H5Z_FLAG_DEFMASK))
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid flags")
    if (cd_nelmts>0 && !cd_values)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no client data values supplied")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get the pipeline property to append to */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Add the filter to the I/O pipeline */
    if(H5Z_append(&pline, filter, flags, cd_nelmts, cd_values) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add filter to pipeline")

    /* Put the I/O pipeline information back into the property list */
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5Pget_nfilters
 *
 * Purpose:	Returns the number of filters in the permanent or transient
 *		pipeline depending on whether PLIST_ID is a dataset creation
 *		or dataset transfer property list.  In each pipeline the
 *		filters are numbered from zero through N-1 where N is the
 *		value returned by this function.  During output to the file
 *		the filters of a pipeline are applied in increasing order
 *		(the inverse is true for input).
 *
 * Note:	Only permanent filters are supported at this time.
 *
 * Return:	Success:	Number of filters or zero if there are none.
 *
 *		Failure:	Negative
 *
 * Programmer:	Robb Matzke
 *              Tuesday, August  4, 1998
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
int
H5Pget_nfilters(hid_t plist_id)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    int ret_value;              /* return value */

    FUNC_ENTER_API(H5Pget_nfilters, FAIL)
    H5TRACE1("Is", "i", plist_id);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get value */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Set return value */
    ret_value=(int)(pline.nused);

done:
    FUNC_LEAVE_API(ret_value)
}


/*-------------------------------------------------------------------------
 * Function:	H5P_get_filter
 *
 * Purpose:	Internal component of H5Pget_filter & H5Pget_filter_id
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Monday, October 23, 2006
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5P_get_filter(const H5Z_filter_info_t *filter, unsigned int *flags/*out*/,
    size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
    size_t namelen, char name[]/*out*/,
    unsigned *filter_config /*out*/)
{
    FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5P_get_filter)

    /* Check arguments */
    HDassert(filter);

    /* Filter flags */
    if(flags)
        *flags = filter->flags;

    /* Filter parameters */
    if(cd_values) {
        size_t	i;                      /* Local index variable */

        for(i = 0; i < filter->cd_nelmts && i < *cd_nelmts; i++)
            cd_values[i] = filter->cd_values[i];
    } /* end if */

    /* Number of filter parameters */
    if(cd_nelmts)
        *cd_nelmts = filter->cd_nelmts;

    /* Filter name */
    if(namelen > 0 && name) {
        const char *s = filter->name;

        /* If there's no name on the filter, use the class's filter name */
        if(!s) {
            H5Z_class_t *cls = H5Z_find(filter->id);

            if(cls)
                s = cls->name;
        } /* end if */

        /* Check for actual name */
        if(s) {
            HDstrncpy(name, s, namelen);
            name[namelen - 1] = '\0';
        } /* end if */
        else {
            /* Check for unknown library filter */
            /* (probably from a future version of the library) */
            if(filter->id < 256) {
                HDstrncpy(name, "Unknown library filter", namelen);
                name[namelen - 1] = '\0';
            } /* end if */
            else
                name[0] = '\0';
        } /* end if */
    } /* end if */

    /* Filter configuration (assume filter ID has already been checked) */
    if(filter_config)
        H5Zget_filter_info(filter->id, filter_config);

    FUNC_LEAVE_NOAPI(SUCCEED)
} /* end H5P_get_filter() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_filter2
 *
 * Purpose:	This is the query counterpart of H5Pset_filter() and returns
 *		information about a particular filter number in a permanent
 *		or transient pipeline depending on whether PLIST_ID is a
 *		dataset creation or transfer property list.  On input,
 *		CD_NELMTS indicates the number of entries in the CD_VALUES
 *		array allocated by the caller while on exit it contains the
 *		number of values defined by the filter.  FILTER_CONFIG is a bit
 *      field contaning encode/decode flags from H5Zpublic.h.  The IDX
 *      should be a value between zero and N-1 as described for
 *      H5Pget_nfilters() and the function will return failure if the
 *      filter number is out of range.
 *
 * Return:	Success:	Filter identification number.
 *
 *		Failure:	H5Z_FILTER_ERROR (Negative)
 *
 * Programmer:	Robb Matzke
 *              Wednesday, April 15, 1998
 *
 *-------------------------------------------------------------------------
 */
H5Z_filter_t
H5Pget_filter2(hid_t plist_id, unsigned idx, unsigned int *flags/*out*/,
	       size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
	       size_t namelen, char name[]/*out*/,
               unsigned *filter_config /*out*/)
{
    H5O_pline_t         pline;  /* Filter pipeline */
    const H5Z_filter_info_t *filter;  /* Pointer to filter information */
    H5P_genplist_t *plist;      /* Property list pointer */
    H5Z_filter_t ret_value;     /* return value */

    FUNC_ENTER_API(H5Pget_filter2, H5Z_FILTER_ERROR)
    H5TRACE8("Zf", "iIux*zxzxx", plist_id, idx, flags, cd_nelmts, cd_values,
             namelen, name, filter_config);

    /* Check args */
    if(cd_nelmts || cd_values) {
        /*
         * It's likely that users forget to initialize this on input, so
         * we'll check that it has a reasonable value.  The actual number
         * is unimportant because the H5O layer will detect when a message
         * is too large.
         */
        if(cd_nelmts && *cd_nelmts > 256)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "probable uninitialized *cd_nelmts argument")
        if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "client data values not supplied")

        /*
         * If cd_nelmts is null but cd_values is non-null then just ignore
         * cd_values
         */
        if(!cd_nelmts)
            cd_values = NULL;
    } /* end if */

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5Z_FILTER_ERROR, "can't find object for ID")

    /* Get pipeline info */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get pipeline")

    /* Check more args */
    if(idx >= pline.nused)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "filter number is invalid")

    /* Set pointer to particular filter to query */
    filter = &pline.filter[idx];

    /* Get filter information */
    if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, filter_config) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")

    /* Set return value */
    ret_value = filter->id;

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_filter2() */


/*-------------------------------------------------------------------------
 * Function:	H5P_get_filter_by_id
 *
 * Purpose:	This is an additional query counterpart of H5Pset_filter() and
 *              returns information about a particular filter in a permanent
 *		or transient pipeline depending on whether PLIST_ID is a
 *		dataset creation or transfer property list.  On input,
 *		CD_NELMTS indicates the number of entries in the CD_VALUES
 *		array allocated by the caller while on exit it contains the
 *		number of values defined by the filter.  FILTER_CONFIG is a bit
 *      field contaning encode/decode flags from H5Zpublic.h.  The ID
 *      should be the filter ID to retrieve the parameters for.  If the
 *      filter is not set for the property list, an error will be returned.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, October 17, 2007
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5P_get_filter_by_id(H5P_genplist_t *plist, H5Z_filter_t id, unsigned int *flags/*out*/,
    size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
    size_t namelen, char name[]/*out*/, unsigned *filter_config)
{
    H5O_pline_t         pline;  /* Filter pipeline */
    H5Z_filter_info_t *filter;  /* Pointer to filter information */
    herr_t ret_value = SUCCEED;   /* Return value */

    FUNC_ENTER_NOAPI(H5P_get_filter_by_id, FAIL)

    /* Get pipeline info */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")

    /* Get pointer to filter in pipeline */
    if(NULL == (filter = H5Z_filter_info(&pline, id)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "filter ID is invalid")

    /* Get filter information */
    if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, filter_config) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_get_filter_by_id() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_filter_by_id2
 *
 * Purpose:	This is an additional query counterpart of H5Pset_filter() and
 *              returns information about a particular filter in a permanent
 *		or transient pipeline depending on whether PLIST_ID is a
 *		dataset creation or transfer property list.  On input,
 *		CD_NELMTS indicates the number of entries in the CD_VALUES
 *		array allocated by the caller while on exit it contains the
 *		number of values defined by the filter.  FILTER_CONFIG is a bit
 *      field contaning encode/decode flags from H5Zpublic.h.  The ID
 *      should be the filter ID to retrieve the parameters for.  If the
 *      filter is not set for the property list, an error will be returned.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 * Programmer:	Quincey Koziol
 *              Friday, April  5, 2003
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_filter_by_id2(hid_t plist_id, H5Z_filter_t id, unsigned int *flags/*out*/,
    size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
    size_t namelen, char name[]/*out*/, unsigned *filter_config)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED;   /* Return value */

    FUNC_ENTER_API(H5Pget_filter_by_id2, FAIL)
    H5TRACE8("e", "iZfx*zxzx*Iu", plist_id, id, flags, cd_nelmts, cd_values,
             namelen, name, filter_config);

    /* Check args */
    if(cd_nelmts || cd_values) {
        /*
         * It's likely that users forget to initialize this on input, so
         * we'll check that it has a reasonable value.  The actual number
         * is unimportant because the H5O layer will detect when a message
         * is too large.
         */
        if(cd_nelmts && *cd_nelmts > 256)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "probable uninitialized *cd_nelmts argument")
        if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "client data values not supplied")

        /*
         * If cd_nelmts is null but cd_values is non-null then just ignore
         * cd_values
         */
        if(!cd_nelmts)
            cd_values = NULL;
    } /* end if */

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get filter info */
    if(H5P_get_filter_by_id(plist, id, flags, cd_nelmts, cd_values, namelen, name, filter_config) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_filter_by_id2() */


/*-------------------------------------------------------------------------
 * Function:	H5Pall_filters_avail
 *
 * Purpose:	This is a query routine to verify that all the filters set
 *              in the dataset creation property list are available currently.
 *
 * Return:	Success:	TRUE if all filters available, FALSE if one or
 *                              more filters not currently available.
 *		Failure:	FAIL on error
 *
 * Programmer:	Quincey Koziol
 *              Tuesday, April  8, 2003
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
htri_t
H5Pall_filters_avail(hid_t plist_id)
{
    H5O_pline_t         pline;  /* Filter pipeline */
    H5P_genplist_t *plist;      /* Property list pointer */
    hbool_t ret_value = TRUE;   /* return value */

    FUNC_ENTER_API(H5Pall_filters_avail, UFAIL)
    H5TRACE1("t", "i", plist_id);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, UFAIL, "can't find object for ID")

    /* Get pipeline info */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, UFAIL, "can't get pipeline")

    /* Set return value */
    if(UFAIL == (ret_value = H5Z_all_filters_avail(&pline)))
        HGOTO_ERROR(H5E_PLIST, H5E_NOTFOUND, UFAIL, "can't check pipeline information")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pall_filters_avail() */


/*-------------------------------------------------------------------------
 * Function: H5Premove_filter
 *
 * Purpose: Deletes a filter from the dataset creation property list;
 *  deletes all filters if FILTER is H5Z_FILTER_NONE
 *
 * Return: Non-negative on success/Negative on failure
 *
 * Programmer: Pedro Vicente
 *             January 26, 2004
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Premove_filter(hid_t plist_id, H5Z_filter_t filter)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    H5O_pline_t pline;          /* Filter pipeline */
    herr_t ret_value = SUCCEED; /* return value          */

    FUNC_ENTER_API(H5Premove_filter, FAIL)
    H5TRACE2("e", "iZf", plist_id, filter);

    /* Get the property list structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get pipeline info */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get pipeline")

    /* Check if there are any filters */
    if (pline.filter) {
        /* Delete filter */
        if(H5Z_delete(&pline, filter) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't delete filter")

        /* Put the I/O pipeline information back into the property list */
        if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set pipeline")
    } /* end if */

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Premove_filter() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_deflate
 *
 * Purpose:	Sets the compression method for a permanent or transient
 *		filter pipeline (depending on whether PLIST_ID is a dataset
 *		creation or transfer property list) to H5Z_FILTER_DEFLATE
 *		and the compression level to LEVEL which should be a value
 *		between zero and nine, inclusive.  Lower compression levels
 *		are faster but result in less compression.  This is the same
 *		algorithm as used by the GNU gzip program.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Wednesday, April 15, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_deflate(hid_t plist_id, unsigned level)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_deflate, FAIL)
    H5TRACE2("e", "iIu", plist_id, level);

    /* Check arguments */
    if(level>9)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "invalid deflate level")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Add the filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_DEFLATE, H5Z_FLAG_OPTIONAL, (size_t)1, &level) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add deflate filter to pipeline")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_deflate() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_szip
 *
 * Purpose:	Sets the compression method for a permanent or transient
 *		filter pipeline (depending on whether PLIST_ID is a dataset
 *		creation or transfer property list) to H5Z_FILTER_SZIP
 *		Szip is a special compression package that is said to be good
 *              for scientific data.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Kent Yang
 *              Tuesday, April 1, 2003
 *
 * Modifications:
 *
 *          Nat Furrer and James Laird
 *          June 30, 2004
 *          Now ensures that SZIP encoding is enabled
 *          SZIP defaults to k13 compression
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_szip(hid_t plist_id, unsigned options_mask, unsigned pixels_per_block)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    unsigned cd_values[2];      /* Filter parameters */
    unsigned int config_flags;
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_szip, FAIL)
    H5TRACE3("e", "iIuIu", plist_id, options_mask, pixels_per_block);

    if(H5Zget_filter_info(H5Z_FILTER_SZIP, &config_flags) < 0)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't get filter info")

    if(! (config_flags & H5Z_FILTER_CONFIG_ENCODE_ENABLED))
        HGOTO_ERROR(H5E_PLINE, H5E_NOENCODER, FAIL, "Filter present but encoding is disabled.")

    /* Check arguments */
    if ((pixels_per_block%2)==1)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "pixels_per_block is not even")
    if (pixels_per_block>H5_SZIP_MAX_PIXELS_PER_BLOCK)
        HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "pixels_per_block is too large")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Always set K13 compression (and un-set CHIP compression) */
    options_mask &= (~H5_SZIP_CHIP_OPTION_MASK);
    options_mask |= H5_SZIP_ALLOW_K13_OPTION_MASK;

    /* Always set "raw" (no szip header) flag for data */
    options_mask |= H5_SZIP_RAW_OPTION_MASK;

    /* Mask off the LSB and MSB options, if they were given */
    /* (The HDF5 library sets them internally, as needed) */
    options_mask &= ~(H5_SZIP_LSB_OPTION_MASK|H5_SZIP_MSB_OPTION_MASK);

    /* Set the parameters for the filter */
    cd_values[0]=options_mask;
    cd_values[1]=pixels_per_block;

    /* Add the filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_SZIP, H5Z_FLAG_OPTIONAL, (size_t)2, cd_values) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add szip filter to pipeline")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_szip() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_shuffle
 *
 * Purpose:	Sets the shuffling method for a permanent
 *		filter to H5Z_FILTER_SHUFFLE
 *		and bytes of the datatype of the array to be shuffled
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Kent Yang
 *              Wednesday, November 13, 2002
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_shuffle(hid_t plist_id)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_shuffle, FAIL)
    H5TRACE1("e", "i", plist_id);

    /* Check arguments */
    if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
        HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")

    /* Get the plist structure */
    if(NULL == (plist = H5I_object(plist_id)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Add the filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_SHUFFLE, H5Z_FLAG_OPTIONAL, (size_t)0, NULL) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to shuffle the data")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_shuffle() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_nbit
 *
 * Purpose:     Sets nbit filter for a dataset creation property list
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Xiaowen Wu
 *              Wednesday, December 22, 2004
 *
 * Modifications:
 *
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_nbit(hid_t plist_id)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_nbit, FAIL)
    H5TRACE1("e", "i", plist_id);

    /* Check arguments */
    if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
        HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")

    /* Get the plist structure */
    if(NULL == (plist = H5I_object(plist_id)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Add the nbit filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_NBIT, H5Z_FLAG_OPTIONAL, (size_t)0, NULL) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add nbit filter to pipeline")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_nbit() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_scaleoffset
 *
 * Purpose:     Sets scaleoffset filter for a dataset creation property list
 *              and user-supplied parameters
 *
 * Parameters:  scale_factor:
                              for integer datatype,
                              this parameter will be
                              minimum-bits, if this value is set to 0,
                              scaleoffset filter will calculate the minimum-bits.

                              For floating-point datatype,
                              For variable-minimum-bits method, this will be
                              the decimal precision of the filter,
                              For fixed-minimum-bits method, this will be
                              the minimum-bit of the filter.
                scale_type:   0 for floating-point variable-minimum-bits,
                              1 for floating-point fixed-minimum-bits,
                              other values, for integer datatype

 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Xiaowen Wu
 *              Thursday, April 14, 2005
 *
 * Modifications:
 *
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_scaleoffset(hid_t plist_id, H5Z_SO_scale_type_t scale_type, int scale_factor)
{
    H5O_pline_t         pline;
    H5P_genplist_t *plist;      /* Property list pointer */
    unsigned cd_values[2];      /* Filter parameters */
    herr_t ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_scaleoffset, FAIL)
    H5TRACE3("e", "iZaIs", plist_id, scale_type, scale_factor);

    /* Check arguments */
    if(TRUE != H5P_isa_class(plist_id, H5P_DATASET_CREATE))
        HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset creation property list")

    if(scale_type!=H5Z_SO_FLOAT_DSCALE && scale_type!=H5Z_SO_FLOAT_ESCALE && scale_type!=H5Z_SO_INT)
       HGOTO_ERROR (H5E_ARGS, H5E_BADTYPE, FAIL, "invalid scale type")

    /* Get the plist structure */
    if(NULL == (plist = H5I_object(plist_id)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Set parameters for the filter
     * scale_type = 0:     floating-point type, filter uses variable-minimum-bits method,
     *                     scale_factor is decimal scale factor
     * scale_type = 1:     floating-point type, filter uses fixed-minimum-bits method,
     *                     scale_factor is the fixed minimum number of bits
     * scale type = other: integer type, scale_factor is minimum number of bits
     *                     if scale_factor = 0, then filter calculates minimum number of bits
     */
    cd_values[0] = scale_type;
    cd_values[1] = scale_factor;

    /* Add the scaleoffset filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_SCALEOFFSET, H5Z_FLAG_OPTIONAL, (size_t)2, cd_values) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add scaleoffset filter to pipeline")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_scaleoffset() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_fletcher32
 *
 * Purpose:	Sets Fletcher32 checksum of EDC for a dataset creation
 *              property list.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Raymond Lu
 *              Dec 19, 2002
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_fletcher32(hid_t plist_id)
{
    H5O_pline_t         pline;
    H5P_genplist_t      *plist;      /* Property list pointer */
    herr_t              ret_value=SUCCEED;   /* return value */

    FUNC_ENTER_API(H5Pset_fletcher32, FAIL)
    H5TRACE1("e", "i", plist_id);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Add the Fletcher32 checksum as a filter */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get pipeline")
    if(H5Z_append(&pline, H5Z_FILTER_FLETCHER32, H5Z_FLAG_MANDATORY, (size_t)0, NULL) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to add deflate filter to pipeline")
    if(H5P_set(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTINIT, FAIL, "unable to set pipeline")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_fletcher32() */


/*-------------------------------------------------------------------------
 * Function:	H5Pset_fill_value
 *
 * Purpose:	Set the fill value for a dataset creation property list. The
 *		VALUE is interpretted as being of type TYPE, which need not
 *		be the same type as the dataset but the library must be able
 *		to convert VALUE to the dataset type when the dataset is
 *		created.  If VALUE is NULL, it will be interpreted as
 *		undefining fill value.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Thursday, October  1, 1998
 *
 * Modifications:
 *
 *              Raymond Lu
 *              Tuesday, October 2, 2001
 *              Changed the way to check parameter and set property for
 *              generic property list.
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_fill_value(hid_t plist_id, hid_t type_id, const void *value)
{
    H5P_genplist_t *plist;              /* Property list pointer */
    H5O_fill_t fill;                    /* Fill value to modify */
    herr_t ret_value = SUCCEED;         /* Return value */

    FUNC_ENTER_API(H5Pset_fill_value, FAIL)
    H5TRACE3("e", "ii*x", plist_id, type_id, value);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get the current fill value */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

    /* Release the dynamic fill value components */
    H5O_fill_reset_dyn(&fill);

    if(value) {
        H5T_t *type;            /* Datatype for fill value */
        H5T_path_t *tpath;      /* Conversion information */

        /* Retrieve pointer to datatype */
	if(NULL == (type = H5I_object_verify(type_id, H5I_DATATYPE)))
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")

	/* Set the fill value */
        if(NULL == (fill.type = H5T_copy(type, H5T_COPY_TRANSIENT)))
            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy datatype")
        fill.size = H5T_get_size(type);
        if(NULL == (fill.buf = H5MM_malloc((size_t)fill.size)))
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "memory allocation failed for fill value")
        HDmemcpy(fill.buf, value, (size_t)fill.size);

        /* Set up type conversion function */
        if(NULL == (tpath = H5T_path_find(type, type, NULL, NULL, H5AC_ind_dxpl_id, FALSE)))
            HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert between src and dest data types")

        /* If necessary, convert fill value datatypes (which copies VL components, etc.) */
        if(!H5T_path_noop(tpath)) {
            uint8_t *bkg_buf = NULL;    /* Background conversion buffer */

            /* Allocate a background buffer */
            if(H5T_path_bkg(tpath) && NULL == (bkg_buf = H5FL_BLK_CALLOC(type_conv, (size_t)fill.size)))
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")

            /* Convert the fill value */
            if(H5T_convert(tpath, type_id, type_id, (size_t)1, (size_t)0, (size_t)0, fill.buf, bkg_buf, H5AC_ind_dxpl_id) < 0) {
                if(bkg_buf)
                    H5FL_BLK_FREE(type_conv, bkg_buf);
                HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
            } /* end if */

            /* Release the background buffer */
            if(bkg_buf)
                H5FL_BLK_FREE(type_conv, bkg_buf);
        } /* end if */
    }  /* end if */
    else
        fill.size = (-1);

    /* Update fill value in property list */
    if(H5P_set(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't set fill value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_fill_value() */


/*-------------------------------------------------------------------------
 * Function:	H5P_get_fill_value
 *
 * Purpose:	Queries the fill value property of a dataset creation
 *		property list.  The fill value is returned through the VALUE
 *		pointer and the memory is allocated by the caller.  The fill
 *		value will be converted from its current datatype to the
 *		specified TYPE.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Quincey Koziol
 *              Wednesday, October 17, 2007
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5P_get_fill_value(H5P_genplist_t *plist, const H5T_t *type, void *value/*out*/,
    hid_t dxpl_id)
{
    H5O_fill_t          fill;                   /* Fill value to retrieve */
    H5T_path_t		*tpath;		        /*type conversion info	*/
    void		*buf = NULL;		/*conversion buffer	*/
    void		*bkg = NULL;		/*conversion buffer	*/
    hid_t		src_id = -1;		/*source datatype id	*/
    hid_t		dst_id = -1;		/*destination datatype id	*/
    herr_t              ret_value = SUCCEED;    /* Return value */

    FUNC_ENTER_NOAPI(H5P_get_fill_value, FAIL)

    /*
     * If no fill value is defined then return an error.  We can't even
     * return zero because we don't know the datatype of the dataset and
     * datatype conversion might not have resulted in zero.  If fill value
     * is undefined, also return error.
     */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")
    if(fill.size == -1)
	HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "fill value is undefined")

    /* Check for "default" fill value */
    if(fill.size == 0) {
	HDmemset(value, 0, H5T_get_size(type));
   	HGOTO_DONE(SUCCEED);
    } /* end if */

     /*
     * Can we convert between the source and destination datatypes?
     */
    if(NULL == (tpath = H5T_path_find(fill.type, type, NULL, NULL, dxpl_id, FALSE)))
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to convert between src and dst datatypes")
    if((src_id = H5I_register(H5I_DATATYPE, H5T_copy(fill.type, H5T_COPY_TRANSIENT))) < 0)
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy/register datatype")

    /*
     * Data type conversions are always done in place, so we need a buffer
     * other than the fill value buffer that is large enough for both source
     * and destination.  The app-supplied buffer might do okay.
     */
    if(H5T_get_size(type) >= H5T_get_size(fill.type)) {
        buf = value;
        if(H5T_path_bkg(tpath) && NULL == (bkg = H5MM_malloc(H5T_get_size(type))))
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
    } /* end if */
    else {
        if(NULL == (buf = H5MM_malloc(H5T_get_size(fill.type))))
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for type conversion")
        if(H5T_path_bkg(tpath))
            bkg = value;
    } /* end else */
    HDmemcpy(buf, fill.buf, H5T_get_size(fill.type));

    /* Do the conversion */
    if((dst_id = H5I_register(H5I_DATATYPE, H5T_copy(type, H5T_COPY_TRANSIENT))) < 0)
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy/register datatype")
    if(H5T_convert(tpath, src_id, dst_id, (size_t)1, (size_t)0, (size_t)0, buf, bkg, dxpl_id) < 0)
        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "datatype conversion failed")
    if(buf != value)
        HDmemcpy(value, buf, H5T_get_size(type));

done:
    if(buf != value)
        H5MM_xfree(buf);
    if(bkg != value)
        H5MM_xfree(bkg);
    if(src_id >= 0)
        H5I_dec_ref(src_id);
    if(dst_id >= 0)
        H5I_dec_ref(dst_id);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_get_fill_value() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_fill_value
 *
 * Purpose:	Queries the fill value property of a dataset creation
 *		property list.  The fill value is returned through the VALUE
 *		pointer and the memory is allocated by the caller.  The fill
 *		value will be converted from its current datatype to the
 *		specified TYPE.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Robb Matzke
 *              Thursday, October  1, 1998
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_fill_value(hid_t plist_id, hid_t type_id, void *value/*out*/)
{
    H5P_genplist_t      *plist;                 /* Property list pointer */
    H5T_t		*type;		        /* Datatype		*/
    herr_t              ret_value = SUCCEED;    /* Return value */

    FUNC_ENTER_API(H5Pget_fill_value, FAIL)
    H5TRACE3("e", "iix", plist_id, type_id, value);

    /* Check arguments */
    if(NULL == (type = H5I_object_verify(type_id, H5I_DATATYPE)))
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
    if(!value)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,"no fill value output buffer")

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get the fill value */
    if(H5P_get_fill_value(plist, type, value, H5AC_ind_dxpl_id) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_fill_value() */


/*-------------------------------------------------------------------------
 * Function:    H5P_is_fill_value_defined
 *
 * Purpose:	Check if fill value is defined.  Internal version of function
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:  Raymond Lu
 *              Wednesday, January 16, 2002
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5P_is_fill_value_defined(const H5O_fill_t *fill, H5D_fill_value_t *status)
{
    herr_t ret_value = SUCCEED;

    FUNC_ENTER_NOAPI(H5P_is_fill_value_defined, FAIL)

    HDassert(fill);
    HDassert(status);

    /* Check if the fill value was "unset" */
    if(fill->size == -1 && !fill->buf)
	*status = H5D_FILL_VALUE_UNDEFINED;
    /* Check if the fill value was set to the default fill value by the library */
    else if(fill->size == 0 && !fill->buf)
	*status = H5D_FILL_VALUE_DEFAULT;
    /* Check if the fill value was set by the application */
    else if(fill->size > 0 && fill->buf)
	*status = H5D_FILL_VALUE_USER_DEFINED;
    else {
	*status = H5D_FILL_VALUE_ERROR;
        HGOTO_ERROR(H5E_PLIST, H5E_BADRANGE, FAIL, "invalid combination of fill-value info")
    } /* end else */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_is_fill_value_defined() */


/*-------------------------------------------------------------------------
 * Function:    H5P_fill_value_defined
 *
 * Purpose:	Check if fill value is defined.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:  Quincey Koziol
 *              Wednesday, October 17, 2007
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5P_fill_value_defined(H5P_genplist_t *plist, H5D_fill_value_t *status)
{
    H5O_fill_t	        fill;                   /* Fill value to query */
    herr_t		ret_value = SUCCEED;

    FUNC_ENTER_NOAPI(H5P_fill_value_defined, FAIL)

    HDassert(status);

    /* Get the fill value struct */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

    /* Get the fill-value status */
    if(H5P_is_fill_value_defined(&fill, status) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't check fill value status")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5P_fill_value_defined() */


/*-------------------------------------------------------------------------
 * Function:    H5Pfill_value_defined
 *
 * Purpose:	Check if fill value is defined.
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:  Raymond Lu
 *              Wednesday, January 16, 2002
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pfill_value_defined(hid_t plist_id, H5D_fill_value_t *status)
{
    H5P_genplist_t 	*plist;                 /* Property list to query */
    herr_t		ret_value = SUCCEED;

    FUNC_ENTER_API(H5Pfill_value_defined, FAIL)
    H5TRACE2("e", "i*DF", plist_id, status);

    HDassert(status);

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get the fill-value status */
    if(H5P_fill_value_defined(plist, status) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_BADVALUE, FAIL, "can't check fill value status")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pfill_value_defined() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_alloc_time
 *
 * Purpose:     Set space allocation time for dataset during creation.
 *		Valid values are H5D_ALLOC_TIME_DEFAULT, H5D_ALLOC_TIME_EARLY,
 *			H5D_ALLOC_TIME_LATE, H5D_ALLOC_TIME_INCR
 *
 * Return:	Non-negative on success/Negative on failure
 *
 * Programmer:	Raymond Lu
 * 		Wednesday, January 16, 2002
 *
 * Modifications:
 *
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_alloc_time(hid_t plist_id, H5D_alloc_time_t alloc_time)
{
    H5P_genplist_t *plist; 	/* Property list pointer */
    H5O_fill_t fill;            /* Fill value property to modify */
    unsigned alloc_time_state;  /* State of allocation time property */
    herr_t ret_value = SUCCEED; /* return value 	 */

    FUNC_ENTER_API(H5Pset_alloc_time, FAIL)
    H5TRACE2("e", "iDa", plist_id, alloc_time);

    /* Check arguments */
    if(alloc_time < H5D_ALLOC_TIME_DEFAULT || alloc_time > H5D_ALLOC_TIME_INCR)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid allocation time setting")

    /* Get the property list structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
	HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Check for resetting to default for layout type */
    if(alloc_time == H5D_ALLOC_TIME_DEFAULT) {
        H5D_layout_t layout;            /* Type of storage layout */

        /* Retrieve the storage layout */
        if(H5P_get(plist, H5D_CRT_LAYOUT_NAME, &layout) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get layout")

        /* Set the default based on layout */
        switch(layout) {
            case H5D_COMPACT:
                alloc_time = H5D_ALLOC_TIME_EARLY;
                break;

            case H5D_CONTIGUOUS:
                alloc_time = H5D_ALLOC_TIME_LATE;
                break;

            case H5D_CHUNKED:
                alloc_time = H5D_ALLOC_TIME_INCR;
                break;

            default:
                HGOTO_ERROR(H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unknown layout type")
        } /* end switch */

        /* Reset the "state" of the allocation time property back to the "default" */
        alloc_time_state = 1;
    } /* end if */
    else
        /* Set the "state" of the allocation time property to indicate the user modified it */
        alloc_time_state = 0;

    /* Retrieve previous fill value settings */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

    /* Update property value */
    fill.alloc_time = alloc_time;

    /* Set values */
    if(H5P_set(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value")
    if(H5P_set(plist, H5D_CRT_ALLOC_TIME_STATE_NAME, &alloc_time_state) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set space allocation time")

done:
    FUNC_LEAVE_API(ret_value)
} /* H5Pset_alloc_time() */


/*-------------------------------------------------------------------------
 * Function:    H5Pget_alloc_time
 *
 * Purpose:     Get space allocation time for dataset creation.
 *		Valid values are H5D_ALLOC_TIME_DEFAULT, H5D_ALLOC_TIME_EARLY,
 *			H5D_ALLOC_TIME_LATE, H5D_ALLOC_TIME_INCR
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Raymond Lu
 *              Wednesday, January 16, 2002
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_alloc_time(hid_t plist_id, H5D_alloc_time_t *alloc_time/*out*/)
{
    herr_t ret_value = SUCCEED; /* return value          */

    FUNC_ENTER_API(H5Pget_alloc_time, FAIL)
    H5TRACE2("e", "ix", plist_id, alloc_time);

    /* Get values */
    if(alloc_time) {
        H5P_genplist_t *plist;  /* Property list pointer */
        H5O_fill_t fill;        /* Fill value property to query */

        /* Get the property list structure */
        if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
            HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

        /* Retrieve fill value settings */
        if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

        /* Set user's value */
        *alloc_time = fill.alloc_time;
    } /* end if */

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_alloc_time() */


/*-------------------------------------------------------------------------
 * Function:    H5Pset_fill_time
 *
 * Purpose:	Set fill value writing time for dataset.  Valid values are
 *		H5D_FILL_TIME_ALLOC and H5D_FILL_TIME_NEVER.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Raymond Lu
 *              Wednesday, January 16, 2002
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pset_fill_time(hid_t plist_id, H5D_fill_time_t fill_time)
{
    H5P_genplist_t *plist;      /* Property list pointer */
    H5O_fill_t fill;            /* Fill value property to modify */
    herr_t ret_value = SUCCEED; /* return value          */

    FUNC_ENTER_API(H5Pset_fill_time, FAIL)
    H5TRACE2("e", "iDf", plist_id, fill_time);

    /* Check arguments */
    if(fill_time < H5D_FILL_TIME_ALLOC || fill_time > H5D_FILL_TIME_IFSET)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fill time setting")

    /* Get the property list structure */
    if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Retrieve previous fill value settings */
    if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

    /* Update property value */
    fill.fill_time = fill_time;

    /* Set values */
    if(H5P_set(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set fill value")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pset_fill_time() */


/*-------------------------------------------------------------------------
 * Function:    H5Pget_fill_time
 *
 * Purpose:	Get fill value writing time.  Valid values are H5D_NEVER
 *		and H5D_ALLOC.
 *
 * Return:      Non-negative on success/Negative on failure
 *
 * Programmer:  Raymond Lu
 *              Wednesday, January 16, 2002
 *
 * Modifications:
 *
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_fill_time(hid_t plist_id, H5D_fill_time_t *fill_time/*out*/)
{
    herr_t ret_value = SUCCEED; /* return value          */

    FUNC_ENTER_API(H5Pget_fill_time, FAIL)
    H5TRACE2("e", "ix", plist_id, fill_time);

    /* Set values */
    if(fill_time) {
        H5P_genplist_t *plist;  /* Property list pointer */
        H5O_fill_t fill;        /* Fill value property to query */

        /* Get the property list structure */
        if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_CREATE)))
            HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

        /* Retrieve fill value settings */
        if(H5P_get(plist, H5D_CRT_FILL_VALUE_NAME, &fill) < 0)
            HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get fill value")

        /* Set user's value */
        *fill_time = fill.fill_time;
    } /* end if */

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_fill_time() */

#ifndef H5_NO_DEPRECATED_SYMBOLS

/*-------------------------------------------------------------------------
 * Function:	H5Pget_filter1
 *
 * Purpose:	This is the query counterpart of H5Pset_filter() and returns
 *		information about a particular filter number in a permanent
 *		or transient pipeline depending on whether PLIST_ID is a
 *		dataset creation or transfer property list.  On input,
 *		CD_NELMTS indicates the number of entries in the CD_VALUES
 *		array allocated by the caller while on exit it contains the
 *		number of values defined by the filter.  The IDX
 *      should be a value between zero and N-1 as described for
 *      H5Pget_nfilters() and the function will return failure if the
 *      filter number is out of range.
 *
 * Return:	Success:	Filter identification number.
 *
 *		Failure:	H5Z_FILTER_ERROR (Negative)
 *
 * Programmer:	Robb Matzke
 *              Wednesday, April 15, 1998
 *
 *-------------------------------------------------------------------------
 */
H5Z_filter_t
H5Pget_filter1(hid_t plist_id, unsigned idx, unsigned int *flags/*out*/,
	       size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
	       size_t namelen, char name[]/*out*/)
{
    H5O_pline_t         pline;  /* Filter pipeline */
    const H5Z_filter_info_t *filter;  /* Pointer to filter information */
    H5P_genplist_t *plist;      /* Property list pointer */
    H5Z_filter_t ret_value;     /* return value */

    FUNC_ENTER_API(H5Pget_filter1, H5Z_FILTER_ERROR)
    H5TRACE7("Zf", "iIux*zxzx", plist_id, idx, flags, cd_nelmts, cd_values, namelen,
             name);

    /* Check args */
    if(cd_nelmts || cd_values) {
        /*
         * It's likely that users forget to initialize this on input, so
         * we'll check that it has a reasonable value.  The actual number
         * is unimportant because the H5O layer will detect when a message
         * is too large.
         */
        if(cd_nelmts && *cd_nelmts > 256)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "probable uninitialized *cd_nelmts argument")
        if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "client data values not supplied")

        /*
         * If cd_nelmts is null but cd_values is non-null then just ignore
         * cd_values
         */
        if(!cd_nelmts)
            cd_values = NULL;
    } /* end if */

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, H5Z_FILTER_ERROR, "can't find object for ID")

    /* Get pipeline info */
    if(H5P_get(plist, H5D_CRT_DATA_PIPELINE_NAME, &pline) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get pipeline")

    /* Check more args */
    if(idx >= pline.nused)
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5Z_FILTER_ERROR, "filter number is invalid")

    /* Set pointer to particular filter to query */
    filter = &pline.filter[idx];

    /* Get filter information */
    if(H5P_get_filter(filter, flags, cd_nelmts, cd_values, namelen, name, NULL) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")

    /* Set return value */
    ret_value = filter->id;

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_filter1() */


/*-------------------------------------------------------------------------
 * Function:	H5Pget_filter_by_id1
 *
 * Purpose:	This is an additional query counterpart of H5Pset_filter() and
 *              returns information about a particular filter in a permanent
 *		or transient pipeline depending on whether PLIST_ID is a
 *		dataset creation or transfer property list.  On input,
 *		CD_NELMTS indicates the number of entries in the CD_VALUES
 *		array allocated by the caller while on exit it contains the
 *		number of values defined by the filter.  The ID
 *      should be the filter ID to retrieve the parameters for.  If the
 *      filter is not set for the property list, an error will be returned.
 *
 * Return:	Success:	Non-negative
 *		Failure:	Negative
 *
 * Programmer:	Quincey Koziol
 *              Friday, April  5, 2003
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5Pget_filter_by_id1(hid_t plist_id, H5Z_filter_t id, unsigned int *flags/*out*/,
    size_t *cd_nelmts/*in_out*/, unsigned cd_values[]/*out*/,
    size_t namelen, char name[]/*out*/)
{
    H5O_pline_t         pline;  /* Filter pipeline */
    H5Z_filter_info_t *filter;  /* Pointer to filter information */
    H5P_genplist_t *plist;      /* Property list pointer */
    herr_t ret_value = SUCCEED;   /* Return value */

    FUNC_ENTER_API(H5Pget_filter_by_id1, FAIL)
    H5TRACE7("e", "iZfx*zxzx", plist_id, id, flags, cd_nelmts, cd_values, namelen,
             name);

    /* Check args */
    if(cd_nelmts || cd_values) {
        /*
         * It's likely that users forget to initialize this on input, so
         * we'll check that it has a reasonable value.  The actual number
         * is unimportant because the H5O layer will detect when a message
         * is too large.
         */
        if(cd_nelmts && *cd_nelmts > 256)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "probable uninitialized *cd_nelmts argument")
        if(cd_nelmts && *cd_nelmts > 0 && !cd_values)
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "client data values not supplied")

        /*
         * If cd_nelmts is null but cd_values is non-null then just ignore
         * cd_values
         */
        if(!cd_nelmts)
            cd_values = NULL;
    } /* end if */

    /* Get the plist structure */
    if(NULL == (plist = H5P_object_verify(plist_id, H5P_DATASET_CREATE)))
        HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID")

    /* Get filter info */
    if(H5P_get_filter_by_id(plist, id, flags, cd_nelmts, cd_values, namelen, name, NULL) < 0)
        HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, H5Z_FILTER_ERROR, "can't get filter info")

done:
    FUNC_LEAVE_API(ret_value)
} /* end H5Pget_filter_by_id1() */

#endif /* H5_NO_DEPRECATED_SYMBOLS */