/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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 LICENSE 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:	This file contains inline definitions for "generic" routines
 *          supporting a "shared message interface" (ala Java) for object
 *          header messages that can be shared.  This interface is
 *          dependent on a bunch of macros being defined which define
 *          the name of the interface and "real" methods which need to
 *          be implemented for each message class that supports the
 *          shared message interface.
 */

#ifndef H5Oshared_H
#define H5Oshared_H

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_DECODE
 *
 * Purpose:     Decode an object header message that may be shared.
 *
 * Note:	    The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      Success:    Pointer to the new message in native form
 *              Failure:    NULL
 *-------------------------------------------------------------------------
 */
static inline void *
H5O_SHARED_DECODE(H5F_t *f, H5O_t *open_oh, unsigned mesg_flags, unsigned *ioflags, size_t p_size,
                  const uint8_t *p)
{
    void *ret_value = NULL; /* Return value */

    /* H5O_SHARED_DECODE will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_DECODE
#error "Need to define H5O_SHARED_DECODE macro!"
#endif /* H5O_SHARED_DECODE */
#ifndef H5O_SHARED_DECODE_REAL
#error "Need to define H5O_SHARED_DECODE_REAL macro!"
#endif /* H5O_SHARED_DECODE_REAL */

    /* Check for shared message */
    if (mesg_flags & H5O_MSG_FLAG_SHARED) {
        /* Retrieve native message info indirectly through shared message */
        if (NULL == (ret_value = H5O__shared_decode(f, open_oh, ioflags, p_size, p, H5O_SHARED_TYPE)))
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode shared message");

            /* We currently do not support automatically fixing shared messages */
#ifdef H5_STRICT_FORMAT_CHECKS
        if (*ioflags & H5O_DECODEIO_DIRTY)
            HGOTO_ERROR(H5E_OHDR, H5E_UNSUPPORTED, NULL, "unable to mark shared message dirty");
#else  /* H5_STRICT_FORMAT_CHECKS */
        *ioflags &= ~H5O_DECODEIO_DIRTY;
#endif /* H5_STRICT_FORMAT_CHECKS */
    }  /* end if */
    else {
        /* Decode native message directly */
        if (NULL == (ret_value = H5O_SHARED_DECODE_REAL(f, open_oh, mesg_flags, ioflags, p_size, p)))
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "unable to decode native message");
    } /* end else */

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_ENCODE
 *
 * Purpose:     Encode an object header message that may be shared.
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline herr_t
H5O_SHARED_ENCODE(H5F_t *f, bool disable_shared, size_t H5_ATTR_UNUSED p_size, uint8_t *p, const void *_mesg)
{
    const H5O_shared_t *sh_mesg =
        (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
    herr_t ret_value = SUCCEED;      /* Return value */

    /* H5O_SHARED_ENCODE will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_ENCODE
#error "Need to define H5O_SHARED_ENCODE macro!"
#endif /* H5O_SHARED_ENCODE */
#ifndef H5O_SHARED_ENCODE_REAL
#error "Need to define H5O_SHARED_ENCODE_REAL macro!"
#endif /* H5O_SHARED_ENCODE_REAL */

    /* Sanity check */
    assert(sh_mesg->type == H5O_SHARE_TYPE_UNSHARED || sh_mesg->msg_type_id == H5O_SHARED_TYPE->id);

    /* Check for message stored elsewhere */
    if (H5O_IS_STORED_SHARED(sh_mesg->type) && !disable_shared) {
        /* Encode shared message into buffer */
        if (H5O__shared_encode(f, p, sh_mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode shared message");
    } /* end if */
    else {
        /* Encode native message directly */
        if (H5O_SHARED_ENCODE_REAL(f, p, _mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode native message");
    } /* end else */

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_SIZE
 *
 * Purpose:     Returns the length of an encoded message.
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      Success:    Length
 *              Failure:	0
 *-------------------------------------------------------------------------
 */
static inline size_t
H5O_SHARED_SIZE(const H5F_t *f, bool disable_shared, const void *_mesg)
{
    const H5O_shared_t *sh_mesg =
        (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
    size_t ret_value = 0;            /* Return value */

    /* H5O_SHARED_SIZE will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_SIZE
#error "Need to define H5O_SHARED_SIZE macro!"
#endif /* H5O_SHARED_SIZE */
#ifndef H5O_SHARED_SIZE_REAL
#error "Need to define H5O_SHARED_SIZE_REAL macro!"
#endif /* H5O_SHARED_SIZE_REAL */

    /* Check for message stored elsewhere */
    if (H5O_IS_STORED_SHARED(sh_mesg->type) && !disable_shared) {
        /* Retrieve encoded size of shared message */
        if (0 == (ret_value = H5O__shared_size(f, sh_mesg)))
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, 0, "unable to retrieve encoded size of shared message");
    } /* end if */
    else {
        /* Retrieve size of native message directly */
        if (0 == (ret_value = H5O_SHARED_SIZE_REAL(f, _mesg)))
            HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, 0, "unable to retrieve encoded size of native message");
    } /* end else */

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_DELETE
 *
 * Purpose:     Decrement reference count on any objects referenced by
 *              message
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline herr_t
H5O_SHARED_DELETE(H5F_t *f, H5O_t *open_oh, void *_mesg)
{
    H5O_shared_t *sh_mesg   = (H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
    herr_t        ret_value = SUCCEED;               /* Return value */

    /* H5O_SHARED_DELETE will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_DELETE
#error "Need to define H5O_SHARED_DELETE macro!"
#endif /* H5O_SHARED_DELETE */

    /* Check for message tracked elsewhere */
    if (H5O_IS_TRACKED_SHARED(sh_mesg->type)) {
        /* Decrement the reference count on the shared message/object */
        if (H5O__shared_delete(f, open_oh, H5O_SHARED_TYPE, sh_mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for shared message");
    } /* end if */
#ifdef H5O_SHARED_DELETE_REAL
    else {
        /* Decrement the reference count on the native message directly */
        if (H5O_SHARED_DELETE_REAL(f, open_oh, _mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTDEC, FAIL, "unable to decrement ref count for native message");
    }  /* end else */
#endif /* H5O_SHARED_DELETE_REAL */

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_LINK
 *
 * Purpose:     Increment reference count on any objects referenced by
 *              message
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline herr_t
H5O_SHARED_LINK(H5F_t *f, H5O_t *open_oh, void *_mesg)
{
    H5O_shared_t *sh_mesg   = (H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
    herr_t        ret_value = SUCCEED;               /* Return value */

    /* H5O_SHARED_LINK will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_LINK
#error "Need to define H5O_SHARED_LINK macro!"
#endif /* H5O_SHARED_LINK */

    /* Check for message tracked elsewhere */
    if (H5O_IS_TRACKED_SHARED(sh_mesg->type)) {
        /* Increment the reference count on the shared message/object */
        if (H5O__shared_link(f, open_oh, H5O_SHARED_TYPE, sh_mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "unable to increment ref count for shared message");
    } /* end if */
#ifdef H5O_SHARED_LINK_REAL
    else {
        /* Increment the reference count on the native message directly */
        if (H5O_SHARED_LINK_REAL(f, open_oh, _mesg) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, FAIL, "unable to increment ref count for native message");
    }  /* end else */
#endif /* H5O_SHARED_LINK_REAL */

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_COPY_FILE
 *
 * Purpose:     Copies a message from _SRC to _DEST in file
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline void *
H5O_SHARED_COPY_FILE(H5F_t *file_src, void *_native_src, H5F_t *file_dst, bool *recompute_size,
                     unsigned *mesg_flags, H5O_copy_t *cpy_info, void *udata)
{
    void *dst_mesg  = NULL; /* Destination message */
    void *ret_value = NULL; /* Return value */

    /* H5O_SHARED_COPY_FILE will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_COPY_FILE
#error "Need to define H5O_SHARED_COPY_FILE macro!"
#endif /* H5O_SHARED_COPY_FILE */

#ifdef H5O_SHARED_COPY_FILE_REAL
    /* Call native message's copy file callback to copy the message */
    if (NULL == (dst_mesg = H5O_SHARED_COPY_FILE_REAL(file_src, H5O_SHARED_TYPE, _native_src, file_dst,
                                                      recompute_size, cpy_info, udata)))
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy native message to another file");
#else  /* H5O_SHARED_COPY_FILE_REAL */
    /* No copy file callback defined, just copy the message itself */
    if (NULL == (dst_mesg = (H5O_SHARED_TYPE->copy)(_native_src, NULL)))
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, NULL, "unable to copy native message");
#endif /* H5O_SHARED_COPY_FILE_REAL */

    /* Reset shared message info for new message */
    memset(dst_mesg, 0, sizeof(H5O_shared_t));

    /* Handle sharing destination message */
    if (H5O__shared_copy_file(file_src, file_dst, H5O_SHARED_TYPE, _native_src, dst_mesg, recompute_size,
                              mesg_flags, cpy_info, udata) < 0)
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, NULL, "unable to determine if message should be shared");

    /* Set return value */
    ret_value = dst_mesg;

done:
    if (!ret_value)
        if (dst_mesg)
            H5O_msg_free(H5O_SHARED_TYPE->id, dst_mesg);

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_POST_COPY_FILE
 *
 * Purpose:     Copies a message from _SRC to _DEST in file
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline herr_t
H5O_SHARED_POST_COPY_FILE(const H5O_loc_t H5_ATTR_NDEBUG_UNUSED *oloc_src, const void *mesg_src,
                          H5O_loc_t *oloc_dst, void *mesg_dst, unsigned *mesg_flags, H5O_copy_t *cpy_info)
{
    const H5O_shared_t *shared_src =
        (const H5O_shared_t *)mesg_src;                  /* Alias to shared info in native source */
    H5O_shared_t *shared_dst = (H5O_shared_t *)mesg_dst; /* Alias to shared info in native destination */
    herr_t        ret_value  = SUCCEED;                  /* Return value */

    /* H5O_SHARED_POST_COPY_FILE will be defined as a package function */
    FUNC_ENTER_PACKAGE

    assert(oloc_src->file);
    assert(oloc_dst->file);
    assert(mesg_src);
    assert(mesg_dst);
    assert(cpy_info);

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_POST_COPY_FILE
#error "Need to define H5O_SHARED_POST_COPY_FILE macro!"
#endif /* H5O_SHARED_POST_COPY_FILE */

#ifdef H5O_SHARED_POST_COPY_FILE_REAL
    /* Call native message's post copy file callback to copy the message */
    if (H5O_SHARED_POST_COPY_FILE_REAL(oloc_src, mesg_src, oloc_dst, mesg_dst, cpy_info) < 0)
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to copy native message to another file");
#endif /* H5O_SHARED_POST_COPY_FILE_REAL */

    /* Update shared message after the post copy - will short circuit in
     * production if the DEFER pass determined it will not be shared; debug mode
     * verifies that it is indeed the case */
    if (H5O__shared_post_copy_file(oloc_dst->file, H5O_SHARED_TYPE, shared_src, shared_dst, mesg_flags,
                                   cpy_info) < 0)
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to fix shared message in post copy");

#ifdef H5O_SHARED_POST_COPY_FILE_UPD
    /* Call native message's post copy file update callback to update the
     * message */
    if (H5O_SHARED_POST_COPY_FILE_UPD(oloc_src, mesg_src, oloc_dst, mesg_dst, cpy_info) < 0)
        HGOTO_ERROR(H5E_OHDR, H5E_CANTCOPY, FAIL, "unable to update native message");
#endif /* H5O_SHARED_POST_COPY_FILE_UPD */

    /* Make sure that if the source or destination is committed, both are
     * committed */
    assert((shared_src->type == H5O_SHARE_TYPE_COMMITTED) == (shared_dst->type == H5O_SHARE_TYPE_COMMITTED));

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

/*-------------------------------------------------------------------------
 * Function:    H5O_SHARED_DEBUG
 *
 * Purpose:     Prints debugging info for a potentially shared message.
 *
 * Note:        The actual name of this routine can be different in each source
 *              file that this header file is included in, and must be defined
 *              prior to including this header file.
 *
 * Return:      SUCCEED/FAIL
 *-------------------------------------------------------------------------
 */
static inline herr_t
H5O_SHARED_DEBUG(H5F_t *f, const void *_mesg, FILE *stream, int indent, int fwidth)
{
    const H5O_shared_t *sh_mesg =
        (const H5O_shared_t *)_mesg; /* Pointer to shared message portion of actual message */
    herr_t ret_value = SUCCEED;      /* Return value */

    /* H5O_SHARED_DEBUG will be defined as a package function */
    FUNC_ENTER_PACKAGE

#ifndef H5O_SHARED_TYPE
#error "Need to define H5O_SHARED_TYPE macro!"
#endif /* H5O_SHARED_TYPE */
#ifndef H5O_SHARED_DEBUG
#error "Need to define H5O_SHARED_DEBUG macro!"
#endif /* H5O_SHARED_DEBUG */
#ifndef H5O_SHARED_DEBUG_REAL
#error "Need to define H5O_SHARED_DEBUG_REAL macro!"
#endif /* H5O_SHARED_DEBUG_REAL */

    /* Check for message stored elsewhere */
    if (H5O_IS_STORED_SHARED(sh_mesg->type)) {
        /* Print shared message information */
        if (H5O__shared_debug(sh_mesg, stream, indent, fwidth) < 0)
            HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display shared message info");
    } /* end if */

    /* Call native message's debug callback */
    if (H5O_SHARED_DEBUG_REAL(f, _mesg, stream, indent, fwidth) < 0)
        HGOTO_ERROR(H5E_OHDR, H5E_WRITEERROR, FAIL, "unable to display native message info");

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

#endif /* H5Oshared_H */
