Coverage Report

Created: 2026-03-07 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Tconv_array.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*
14
 * Purpose: Datatype conversion functions for array datatypes
15
 */
16
17
/****************/
18
/* Module Setup */
19
/****************/
20
#include "H5Tmodule.h" /* This source code file is part of the H5T module */
21
22
/***********/
23
/* Headers */
24
/***********/
25
#include "H5private.h"  /* Generic Functions                    */
26
#include "H5Eprivate.h" /* Error handling                       */
27
#include "H5Iprivate.h" /* IDs                                  */
28
#include "H5Tconv.h"    /* Datatype conversions                 */
29
#include "H5Tconv_array.h"
30
31
/******************/
32
/* Local Typedefs */
33
/******************/
34
35
/* Private conversion data for array datatypes */
36
typedef struct H5T_conv_array_t {
37
    H5T_path_t *tpath; /* Conversion path for parent types */
38
} H5T_conv_array_t;
39
40
/*-------------------------------------------------------------------------
41
 * Function:    H5T__conv_array
42
 *
43
 * Purpose:     Converts between array datatypes in memory and on disk.
44
 *              This is a soft conversion function.
45
 *
46
 * Return:      Non-negative on success/Negative on failure
47
 *
48
 *-------------------------------------------------------------------------
49
 */
50
herr_t
51
H5T__conv_array(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata,
52
                const H5T_conv_ctx_t H5_ATTR_UNUSED *conv_ctx, size_t nelmts, size_t buf_stride,
53
                size_t bkg_stride, void *_buf, void *_bkg)
54
0
{
55
0
    H5T_conv_array_t *priv         = NULL;             /* Private conversion data */
56
0
    H5T_conv_ctx_t    tmp_conv_ctx = {0};              /* Temporary conversion context */
57
0
    H5T_t            *tsrc_cpy     = NULL;             /* Temporary copy of source base datatype */
58
0
    H5T_t            *tdst_cpy     = NULL;             /* Temporary copy of destination base datatype */
59
0
    hid_t             tsrc_id      = H5I_INVALID_HID;  /* Temporary type atom */
60
0
    hid_t             tdst_id      = H5I_INVALID_HID;  /* Temporary type atom */
61
0
    uint8_t          *sp, *dp, *bp;                    /* Source, dest, and bkg traversal ptrs */
62
0
    ssize_t           src_delta, dst_delta, bkg_delta; /* Source, dest, and bkg strides */
63
0
    int               direction;                       /* Direction of traversal */
64
0
    herr_t            ret_value = SUCCEED;             /* Return value */
65
66
0
    FUNC_ENTER_PACKAGE
67
68
0
    switch (cdata->command) {
69
0
        case H5T_CONV_INIT:
70
            /*
71
             * First, determine if this conversion function applies to the
72
             * conversion path SRC-->DST.  If not, return failure;
73
             * otherwise initialize the `priv' field of `cdata' with
74
             * information that remains (almost) constant for this
75
             * conversion path.
76
             */
77
0
            if (NULL == src || NULL == dst)
78
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
79
0
            assert(H5T_ARRAY == src->shared->type);
80
0
            assert(H5T_ARRAY == dst->shared->type);
81
82
            /* Check the number and sizes of the dimensions */
83
0
            if (src->shared->u.array.ndims != dst->shared->u.array.ndims)
84
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL,
85
0
                            "array datatypes do not have the same number of dimensions");
86
0
            for (unsigned u = 0; u < src->shared->u.array.ndims; u++)
87
0
                if (src->shared->u.array.dim[u] != dst->shared->u.array.dim[u])
88
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL,
89
0
                                "array datatypes do not have the same sizes of dimensions");
90
91
            /* Initialize parent type conversion if necessary. We need to do this here because we need to
92
             * report whether we need a background buffer or not. */
93
0
            if (!cdata->priv) {
94
                /* Allocate private data */
95
0
                if (NULL == (priv = (H5T_conv_array_t *)(cdata->priv = calloc(1, sizeof(*priv)))))
96
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
97
98
                /* Find conversion path between parent types */
99
0
                if (NULL == (priv->tpath = H5T_path_find(src->shared->parent, dst->shared->parent))) {
100
0
                    free(priv);
101
0
                    cdata->priv = NULL;
102
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL,
103
0
                                "unable to convert between src and dest datatype");
104
0
                }
105
106
                /* Array datatypes don't need a background buffer by themselves, but the parent type might.
107
                 * Pass the need_bkg field through to the upper layer. */
108
0
                cdata->need_bkg = priv->tpath->cdata.need_bkg;
109
0
            }
110
111
0
            break;
112
113
0
        case H5T_CONV_FREE:
114
            /*
115
             * Free private data
116
             */
117
0
            free(cdata->priv);
118
0
            cdata->priv = NULL;
119
120
0
            break;
121
122
0
        case H5T_CONV_CONV:
123
            /*
124
             * Conversion.
125
             */
126
0
            if (NULL == src || NULL == dst)
127
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
128
0
            if (NULL == conv_ctx)
129
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid datatype conversion context pointer");
130
0
            priv = (H5T_conv_array_t *)cdata->priv;
131
132
            /* Initialize temporary conversion context */
133
0
            tmp_conv_ctx = *conv_ctx;
134
135
            /*
136
             * Do we process the values from beginning to end or vice
137
             * versa? Also, how many of the elements have the source and
138
             * destination areas overlapping?
139
             */
140
0
            if (src->shared->size >= dst->shared->size || buf_stride > 0) {
141
0
                sp = dp   = (uint8_t *)_buf;
142
0
                bp        = _bkg;
143
0
                direction = 1;
144
0
            }
145
0
            else {
146
0
                sp = (uint8_t *)_buf + (nelmts - 1) * (buf_stride ? buf_stride : src->shared->size);
147
0
                dp = (uint8_t *)_buf + (nelmts - 1) * (buf_stride ? buf_stride : dst->shared->size);
148
0
                bp = _bkg ? (uint8_t *)_bkg + (nelmts - 1) * (bkg_stride ? bkg_stride : dst->shared->size)
149
0
                          : NULL;
150
0
                direction = -1;
151
0
            }
152
153
            /*
154
             * Direction & size of buffer traversal.
155
             */
156
0
            H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
157
0
            H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
158
0
            H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
159
0
            src_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : src->shared->size);
160
0
            dst_delta = (ssize_t)direction * (ssize_t)(buf_stride ? buf_stride : dst->shared->size);
161
0
            bkg_delta = (ssize_t)direction * (ssize_t)(bkg_stride ? bkg_stride : dst->shared->size);
162
163
            /* Set up conversion path for base elements */
164
0
            if (!H5T_path_noop(priv->tpath)) {
165
0
                if (NULL == (tsrc_cpy = H5T_copy(src->shared->parent, H5T_COPY_ALL)))
166
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL,
167
0
                                "unable to copy src base type for conversion");
168
169
0
                if (NULL == (tdst_cpy = H5T_copy(dst->shared->parent, H5T_COPY_ALL)))
170
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL,
171
0
                                "unable to copy dst base type for conversion");
172
173
                /* Create IDs for the array base datatypes if the conversion path uses an
174
                 * application conversion function or if a conversion exception function
175
                 * was provided.
176
                 */
177
0
                if (priv->tpath->conv.is_app || conv_ctx->u.conv.cb_struct.func) {
178
0
                    if ((tsrc_id = H5I_register(H5I_DATATYPE, tsrc_cpy, false)) < 0)
179
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL,
180
0
                                    "unable to register ID for source base datatype");
181
0
                    if ((tdst_id = H5I_register(H5I_DATATYPE, tdst_cpy, false)) < 0)
182
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL,
183
0
                                    "unable to register ID for destination base datatype");
184
0
                }
185
186
                /* Update IDs in conversion context */
187
0
                tmp_conv_ctx.u.conv.src_type_id = tsrc_id;
188
0
                tmp_conv_ctx.u.conv.dst_type_id = tdst_id;
189
0
            }
190
191
            /* Perform the actual conversion */
192
0
            tmp_conv_ctx.u.conv.recursive = true;
193
0
            for (size_t elmtno = 0; elmtno < nelmts; elmtno++) {
194
                /* Copy the source array into the correct location for the destination */
195
0
                memmove(dp, sp, src->shared->size);
196
197
                /* Convert array */
198
0
                if (H5T_convert_with_ctx(priv->tpath, tsrc_cpy, tdst_cpy, &tmp_conv_ctx,
199
0
                                         src->shared->u.array.nelem, (size_t)0, (size_t)0, dp, bp) < 0)
200
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "datatype conversion failed");
201
202
                /* Advance the source, destination, and background pointers */
203
0
                sp += src_delta;
204
0
                dp += dst_delta;
205
0
                if (bp)
206
0
                    bp += bkg_delta;
207
0
            } /* end for */
208
0
            tmp_conv_ctx.u.conv.recursive = false;
209
210
0
            break;
211
212
0
        default: /* Some other command we don't know about yet.*/
213
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command");
214
0
    } /* end switch */
215
216
0
done:
217
0
    if (tsrc_id >= 0) {
218
0
        if (H5I_dec_ref(tsrc_id) < 0)
219
0
            HDONE_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "can't decrement reference on temporary ID");
220
0
    }
221
0
    else if (tsrc_cpy) {
222
0
        if (H5T_close(tsrc_cpy) < 0)
223
0
            HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype");
224
0
    }
225
0
    if (tdst_id >= 0) {
226
0
        if (H5I_dec_ref(tdst_id) < 0)
227
0
            HDONE_ERROR(H5E_DATATYPE, H5E_CANTDEC, FAIL, "can't decrement reference on temporary ID");
228
0
    }
229
0
    else if (tdst_cpy) {
230
0
        if (H5T_close(tdst_cpy) < 0)
231
0
            HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "can't close temporary datatype");
232
0
    }
233
234
0
    FUNC_LEAVE_NOAPI(ret_value)
235
0
} /* end H5T__conv_array() */