/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Purpose:     Blob callbacks for the native VOL connector
 */

/***********/
/* Headers */
/***********/
#include "H5private.h"          /* Generic Functions                    */
#include "H5Eprivate.h"         /* Error handling                       */
#include "H5Fprivate.h"         /* File access				*/
#include "H5HGprivate.h"        /* Global Heaps				*/
#include "H5VLnative_private.h" /* Native VOL connector                 */

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

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

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

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

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

/*******************/
/* Local Variables */
/*******************/

/*-------------------------------------------------------------------------
 * Function:    H5VL__native_blob_put
 *
 * Purpose:     Handles the blob 'put' callback
 *
 * Return:      SUCCEED / FAIL
 *
 * Programmer:	Quincey Koziol
 *		Friday, August 15, 2019
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL__native_blob_put(void *obj, const void *buf, size_t size, void *blob_id, void H5_ATTR_UNUSED *ctx)
{
    H5F_t *  f  = (H5F_t *)obj;       /* Retrieve file pointer */
    uint8_t *id = (uint8_t *)blob_id; /* Pointer to blob ID */
    H5HG_t   hobjid;                  /* New VL sequence's heap ID */
    herr_t   ret_value = SUCCEED;     /* Return value */

    FUNC_ENTER_PACKAGE

    /* Check parameters */
    HDassert(f);
    HDassert(size == 0 || buf);
    HDassert(id);

    /* Write the VL information to disk (allocates space also) */
    if (H5HG_insert(f, size, buf, &hobjid) < 0)
        HGOTO_ERROR(H5E_VOL, H5E_WRITEERROR, FAIL, "unable to write blob information")

    /* Encode the heap information */
    H5F_addr_encode(f, &id, hobjid.addr);
    UINT32ENCODE(id, hobjid.idx);

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

/*-------------------------------------------------------------------------
 * Function:    H5VL__native_blob_get
 *
 * Purpose:     Handles the blob 'get' callback
 *
 * Return:      SUCCEED / FAIL
 *
 * Programmer:	Quincey Koziol
 *		Friday, August 15, 2019
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL__native_blob_get(void *obj, const void *blob_id, void *buf, size_t size, void H5_ATTR_UNUSED *ctx)
{
    H5F_t *        f  = (H5F_t *)obj;             /* Retrieve file pointer */
    const uint8_t *id = (const uint8_t *)blob_id; /* Pointer to the disk blob ID */
    H5HG_t         hobjid;                        /* Global heap ID for sequence */
    size_t         hobj_size = 0;                 /* Global heap object size returned from H5HG_read() */
    herr_t         ret_value = SUCCEED;           /* Return value */

    FUNC_ENTER_PACKAGE

    /* Sanity check */
    HDassert(f);
    HDassert(id);
    HDassert(buf);

    /* Get the heap information */
    H5F_addr_decode(f, &id, &hobjid.addr);
    UINT32DECODE(id, hobjid.idx);

    /* Check if this sequence actually has any data */
    if (hobjid.addr > 0)
        /* Read the VL information from disk */
        if (NULL == H5HG_read(f, &hobjid, buf, &hobj_size))
            HGOTO_ERROR(H5E_VOL, H5E_READERROR, FAIL, "unable to read VL information")

    /* Verify the size is correct */
    if (hobj_size != size)
        HGOTO_ERROR(H5E_VOL, H5E_CANTDECODE, FAIL, "Expected global heap object size does not match")

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

/*-------------------------------------------------------------------------
 * Function:    H5VL__native_blob_specific
 *
 * Purpose:     Handles the blob 'specific' callback
 *
 * Return:      SUCCEED / FAIL
 *
 * Programmer:	Quincey Koziol
 *		Friday, August 15, 2019
 *
 *-------------------------------------------------------------------------
 */
herr_t
H5VL__native_blob_specific(void *obj, void *blob_id, H5VL_blob_specific_t specific_type, va_list arguments)
{
    H5F_t *f         = (H5F_t *)obj; /* Retrieve file pointer */
    herr_t ret_value = SUCCEED;      /* Return value */

    FUNC_ENTER_PACKAGE

    /* Sanity check */
    HDassert(f);
    HDassert(blob_id);

    switch (specific_type) {
        case H5VL_BLOB_GETSIZE: {
            const uint8_t *id   = (const uint8_t *)blob_id; /* Pointer to the blob ID */
            size_t *       size = HDva_arg(arguments, size_t *);
            H5HG_t         hobjid; /* blob's heap ID */

            /* Get heap information */
            H5F_addr_decode(f, &id, &(hobjid.addr));
            UINT32DECODE(id, hobjid.idx);

            /* Get heap object's size */
            if (hobjid.addr > 0) {
                if (H5HG_get_obj_size(f, &hobjid, size) < 0)
                    HGOTO_ERROR(H5E_VOL, H5E_CANTREMOVE, FAIL, "unable to remove heap object")
            } /* end if */
            else
                *size = 0; /* Return '0' size for 'nil' blob ID */

            break;
        }

        case H5VL_BLOB_ISNULL: {
            const uint8_t *id     = (const uint8_t *)blob_id; /* Pointer to the blob ID */
            hbool_t *      isnull = HDva_arg(arguments, hbool_t *);
            haddr_t        addr; /* Sequence's heap address */

            /* Get the heap address */
            H5F_addr_decode(f, &id, &addr);

            /* Check if heap address is 'nil' */
            *isnull = (addr == 0 ? TRUE : FALSE);

            break;
        }

        case H5VL_BLOB_SETNULL: {
            uint8_t *id = (uint8_t *)blob_id; /* Pointer to the blob ID */
            /* Encode the "nil" heap pointer information */
            H5F_addr_encode(f, &id, (haddr_t)0);
            UINT32ENCODE(id, 0);

            break;
        }

        case H5VL_BLOB_DELETE: {
            const uint8_t *id = (const uint8_t *)blob_id; /* Pointer to the blob ID */
            H5HG_t         hobjid;                        /* VL sequence's heap ID */

            /* Get heap information */
            H5F_addr_decode(f, &id, &hobjid.addr);
            UINT32DECODE(id, hobjid.idx);

            /* Free heap object */
            if (hobjid.addr > 0)
                if (H5HG_remove(f, &hobjid) < 0)
                    HGOTO_ERROR(H5E_VOL, H5E_CANTREMOVE, FAIL, "unable to remove heap object")

            break;
        }

        default:
            HGOTO_ERROR(H5E_VOL, H5E_UNSUPPORTED, FAIL, "invalid specific operation")
    } /* end switch */

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