Coverage Report

Created: 2026-08-31 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Tconv_compound.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 compound 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_compound.h"
30
31
/******************/
32
/* Local Typedefs */
33
/******************/
34
35
/* Private conversion data for compound datatypes */
36
typedef struct H5T_conv_struct_t {
37
    int              *src2dst;     /* mapping from src to dst member num */
38
    H5T_t           **src_memb;    /* source member datatypes            */
39
    H5T_t           **dst_memb;    /* destination member datatypes       */
40
    hid_t            *src_memb_id; /* source member type ID's            */
41
    hid_t            *dst_memb_id; /* destination member type ID's       */
42
    H5T_path_t      **memb_path;   /* conversion path for each member    */
43
    H5T_subset_info_t subset_info; /* info related to compound subsets   */
44
    unsigned          src_nmembs;  /* needed by free function            */
45
} H5T_conv_struct_t;
46
47
/********************/
48
/* Local Prototypes */
49
/********************/
50
51
static herr_t H5T__conv_struct_init(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata,
52
                                    const H5T_conv_ctx_t *conv_ctx);
53
static herr_t H5T__conv_struct_free(H5T_conv_struct_t *priv);
54
55
/*-------------------------------------------------------------------------
56
 * Function:    H5T__conv_struct_subset
57
 *
58
 * Purpose:     A quick way to return a field in a struct private in this
59
 *              file. The `subset` enum field of the `H5T_subset_info_t`
60
 *              structure indicates whether the source members are a subset
61
 *              of the destination or the destination members are a subset
62
 *              of the source, and the order is the same, and no conversion
63
 *              is needed. For example:
64
 *
65
 *                  struct source {            struct destination {
66
 *                      TYPE1 A;      -->          TYPE1 A;
67
 *                      TYPE2 B;      -->          TYPE2 B;
68
 *                      TYPE3 C;      -->          TYPE3 C;
69
 *                  };                             TYPE4 D;
70
 *                                                 TYPE5 E;
71
 *                                             };
72
 *
73
 * Return:      A pointer to the subset info struct in `cdata`. Points
74
 *              directly into the structure.
75
 *
76
 *-------------------------------------------------------------------------
77
 */
78
H5T_subset_info_t *
79
H5T__conv_struct_subset(const H5T_cdata_t *cdata)
80
0
{
81
0
    H5T_conv_struct_t *priv = NULL;
82
83
0
    FUNC_ENTER_PACKAGE_NOERR
84
85
0
    assert(cdata);
86
0
    assert(cdata->priv);
87
88
0
    priv = (H5T_conv_struct_t *)(cdata->priv);
89
90
0
    FUNC_LEAVE_NOAPI((H5T_subset_info_t *)&priv->subset_info)
91
0
} /* end H5T__conv_struct_subset() */
92
93
/*-------------------------------------------------------------------------
94
 * Function:    H5T__conv_struct_init
95
 *
96
 * Purpose:     Initialize the `priv' field of `cdata' with conversion
97
 *              information that is relatively constant. If `priv' is
98
 *              already initialized then the member conversion functions
99
 *              are recalculated.
100
 *
101
 *              Priv fields are indexed by source member number or
102
 *              destination member number depending on whether the field
103
 *              contains information about the source datatype or the
104
 *              destination datatype (fields that contains the same
105
 *              information for both source and destination are indexed by
106
 *              source member number).  The src2dst[] priv array maps
107
 *              source member numbers to destination member numbers, but
108
 *              if the source member doesn't have a corresponding
109
 *              destination member then the src2dst[i] == -1.
110
 *
111
 *              Special optimization case when the source and destination
112
 *              members are a subset of each other, and the order is the
113
 *              same, and no conversion is needed. For example:
114
 *
115
 *                  struct source {            struct destination {
116
 *                      TYPE1 A;      -->          TYPE1 A;
117
 *                      TYPE2 B;      -->          TYPE2 B;
118
 *                      TYPE3 C;      -->          TYPE3 C;
119
 *                  };                             TYPE4 D;
120
 *                                                 TYPE5 E;
121
 *                                             };
122
 *
123
 *              or
124
 *
125
 *                  struct destination {       struct source {
126
 *                      TYPE1 A;      <--          TYPE1 A;
127
 *                      TYPE2 B;      <--          TYPE2 B;
128
 *                      TYPE3 C;      <--          TYPE3 C;
129
 *                  };                             TYPE4 D;
130
 *                                                 TYPE5 E;
131
 *                                             };
132
 *
133
 *              The optimization is simply moving data to the appropriate
134
 *              places in the buffer.
135
 *
136
 * Return:      Non-negative on success/Negative on failure
137
 *
138
 *-------------------------------------------------------------------------
139
 */
140
static herr_t
141
H5T__conv_struct_init(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx)
142
0
{
143
0
    H5T_conv_struct_t *priv    = (H5T_conv_struct_t *)(cdata->priv);
144
0
    int               *src2dst = NULL;
145
0
    unsigned           src_nmembs, dst_nmembs;
146
0
    unsigned           i, j;
147
0
    herr_t             ret_value = SUCCEED; /* Return value */
148
149
0
    FUNC_ENTER_PACKAGE
150
151
0
    src_nmembs = src->shared->u.compnd.nmembs;
152
0
    dst_nmembs = dst->shared->u.compnd.nmembs;
153
154
0
    if (!priv) {
155
        /*
156
         * Allocate private data structure and arrays.
157
         */
158
0
        if (NULL == (priv = (H5T_conv_struct_t *)(cdata->priv = H5MM_calloc(sizeof(H5T_conv_struct_t)))))
159
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "couldn't allocate private conversion data");
160
0
        if (NULL == (priv->src2dst = (int *)H5MM_malloc(src_nmembs * sizeof(int))))
161
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
162
0
                        "couldn't allocate source to destination member mapping array");
163
0
        if (NULL == (priv->src_memb = (H5T_t **)H5MM_malloc(src_nmembs * sizeof(H5T_t *))))
164
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
165
0
                        "couldn't allocate source compound member datatype array");
166
0
        if (NULL == (priv->dst_memb = (H5T_t **)H5MM_malloc(dst_nmembs * sizeof(H5T_t *))))
167
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
168
0
                        "couldn't allocate destination compound member datatype array");
169
170
        /* Allocate and initialize arrays for datatype IDs */
171
0
        if (NULL == (priv->src_memb_id = (hid_t *)H5MM_malloc(src_nmembs * sizeof(hid_t))))
172
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
173
0
                        "couldn't allocate source compound member datatype ID array");
174
0
        for (i = 0; i < src_nmembs; i++)
175
0
            priv->src_memb_id[i] = H5I_INVALID_HID;
176
177
0
        if (NULL == (priv->dst_memb_id = (hid_t *)H5MM_malloc(dst_nmembs * sizeof(hid_t))))
178
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL,
179
0
                        "couldn't allocate destination compound member datatype ID array");
180
0
        for (i = 0; i < dst_nmembs; i++)
181
0
            priv->dst_memb_id[i] = H5I_INVALID_HID;
182
183
0
        src2dst          = priv->src2dst;
184
0
        priv->src_nmembs = src_nmembs;
185
186
        /* The flag of special optimization to indicate if source members and destination
187
         * members are a subset of each other.  Initialize it to false */
188
0
        priv->subset_info.subset    = H5T_SUBSET_FALSE;
189
0
        priv->subset_info.copy_size = 0;
190
191
        /*
192
         * Ensure that members are sorted.
193
         */
194
0
        H5T__sort_value(src, NULL);
195
0
        H5T__sort_value(dst, NULL);
196
197
        /*
198
         * Build a mapping from source member number to destination member
199
         * number. If some source member is not a destination member then that
200
         * mapping element will be negative.  Also create atoms for each
201
         * source and destination member datatype if necessary.
202
         */
203
0
        for (i = 0; i < src_nmembs; i++) {
204
0
            src2dst[i] = -1;
205
0
            for (j = 0; j < dst_nmembs; j++) {
206
0
                if (!strcmp(src->shared->u.compnd.memb[i].name, dst->shared->u.compnd.memb[j].name)) {
207
0
                    H5_CHECKED_ASSIGN(src2dst[i], int, j, unsigned);
208
0
                    break;
209
0
                } /* end if */
210
0
            }     /* end for */
211
0
            if (src2dst[i] >= 0) {
212
0
                H5T_t *type;
213
214
0
                if (NULL == (type = H5T_copy(src->shared->u.compnd.memb[i].type, H5T_COPY_ALL)))
215
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL,
216
0
                                "can't copy source compound member datatype");
217
0
                priv->src_memb[i] = type;
218
219
0
                if (NULL == (type = H5T_copy(dst->shared->u.compnd.memb[src2dst[i]].type, H5T_COPY_ALL)))
220
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL,
221
0
                                "can't copy destination compound member datatype");
222
0
                priv->dst_memb[src2dst[i]] = type;
223
0
            } /* end if */
224
0
        }     /* end for */
225
0
    }         /* end if */
226
0
    else {
227
        /* Restore sorted conditions for the datatypes */
228
        /* (Required for the src2dst array to be valid) */
229
0
        H5T__sort_value(src, NULL);
230
0
        H5T__sort_value(dst, NULL);
231
0
    } /* end else */
232
233
    /*
234
     * (Re)build the cache of member conversion functions and pointers to
235
     * their cdata entries.
236
     */
237
0
    src2dst = priv->src2dst;
238
0
    H5MM_xfree(priv->memb_path);
239
0
    if (NULL ==
240
0
        (priv->memb_path = (H5T_path_t **)H5MM_malloc(src->shared->u.compnd.nmembs * sizeof(H5T_path_t *))))
241
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
242
243
0
    for (i = 0; i < src_nmembs; i++) {
244
0
        if (src2dst[i] >= 0) {
245
0
            H5T_path_t *tpath;
246
0
            bool        need_ids;
247
248
0
            tpath = H5T_path_find(src->shared->u.compnd.memb[i].type,
249
0
                                  dst->shared->u.compnd.memb[src2dst[i]].type);
250
251
0
            if (NULL == (priv->memb_path[i] = tpath)) {
252
0
                H5T__conv_struct_free(priv);
253
0
                cdata->priv = NULL;
254
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unable to convert member datatype");
255
0
            } /* end if */
256
257
            /* Create IDs for the compound member datatypes if the conversion path uses
258
             * an application conversion function or if a conversion exception function
259
             * was provided.
260
             */
261
0
            need_ids = tpath->conv.is_app ||
262
0
                       (cdata->command == H5T_CONV_INIT && conv_ctx->u.init.cb_struct.func) ||
263
0
                       (cdata->command == H5T_CONV_CONV && conv_ctx->u.conv.cb_struct.func);
264
265
0
            if (need_ids) {
266
0
                hid_t tid;
267
268
                /* Only register new IDs for the source and destination member datatypes
269
                 * if IDs weren't already registered for them. If the cached conversion
270
                 * information has to be recalculated (in the case where the library's
271
                 * table of conversion functions is modified), the same IDs can be reused
272
                 * since the only information that needs to be recalculated is the conversion
273
                 * paths used.
274
                 */
275
0
                if (priv->src_memb_id[i] == H5I_INVALID_HID) {
276
0
                    if ((tid = H5I_register(H5I_DATATYPE, priv->src_memb[i], false)) < 0) {
277
0
                        H5T__conv_struct_free(priv);
278
0
                        cdata->priv = NULL;
279
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL,
280
0
                                    "can't register ID for source compound member datatype");
281
0
                    }
282
0
                    priv->src_memb_id[i] = tid;
283
0
                }
284
285
0
                if (priv->dst_memb_id[src2dst[i]] == H5I_INVALID_HID) {
286
0
                    if ((tid = H5I_register(H5I_DATATYPE, priv->dst_memb[src2dst[i]], false)) < 0) {
287
0
                        H5T__conv_struct_free(priv);
288
0
                        cdata->priv = NULL;
289
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, FAIL,
290
0
                                    "can't register ID for destination compound member datatype");
291
0
                    }
292
0
                    priv->dst_memb_id[src2dst[i]] = tid;
293
0
                }
294
0
            }
295
0
        } /* end if */
296
0
    }     /* end for */
297
298
    /* The compound conversion functions need a background buffer */
299
0
    cdata->need_bkg = H5T_BKG_YES;
300
301
0
    if (src_nmembs < dst_nmembs) {
302
0
        priv->subset_info.subset = H5T_SUBSET_SRC;
303
0
        for (i = 0; i < src_nmembs; i++) {
304
            /* If any of source members doesn't have counterpart in the same
305
             * order or there's conversion between members, don't do the
306
             * optimization.
307
             */
308
0
            if (src2dst[i] != (int)i ||
309
0
                (src->shared->u.compnd.memb[i].offset != dst->shared->u.compnd.memb[i].offset) ||
310
0
                (priv->memb_path[i])->is_noop == false) {
311
0
                priv->subset_info.subset = H5T_SUBSET_FALSE;
312
0
                break;
313
0
            } /* end if */
314
0
        }     /* end for */
315
        /* Compute the size of the data to be copied for each element.  It
316
         * may be smaller than either src or dst if there is extra space at
317
         * the end of src.
318
         */
319
0
        if (priv->subset_info.subset == H5T_SUBSET_SRC)
320
0
            priv->subset_info.copy_size = src->shared->u.compnd.memb[src_nmembs - 1].offset +
321
0
                                          src->shared->u.compnd.memb[src_nmembs - 1].size;
322
0
    }
323
0
    else if (dst_nmembs < src_nmembs) {
324
0
        priv->subset_info.subset = H5T_SUBSET_DST;
325
0
        for (i = 0; i < dst_nmembs; i++) {
326
            /* If any of source members doesn't have counterpart in the same order or
327
             * there's conversion between members, don't do the optimization. */
328
0
            if (src2dst[i] != (int)i ||
329
0
                (src->shared->u.compnd.memb[i].offset != dst->shared->u.compnd.memb[i].offset) ||
330
0
                (priv->memb_path[i])->is_noop == false) {
331
0
                priv->subset_info.subset = H5T_SUBSET_FALSE;
332
0
                break;
333
0
            }
334
0
        } /* end for */
335
        /* Compute the size of the data to be copied for each element.  It
336
         * may be smaller than either src or dst if there is extra space at
337
         * the end of dst.
338
         */
339
0
        if (priv->subset_info.subset == H5T_SUBSET_DST)
340
0
            priv->subset_info.copy_size = dst->shared->u.compnd.memb[dst_nmembs - 1].offset +
341
0
                                          dst->shared->u.compnd.memb[dst_nmembs - 1].size;
342
0
    }
343
0
    else /* If the numbers of source and dest members are equal and no conversion is needed,
344
          * the case should have been handled as noop earlier in H5Dio.c. */
345
0
    {
346
0
    }
347
348
0
    cdata->recalc = false;
349
350
0
done:
351
0
    FUNC_LEAVE_NOAPI(ret_value)
352
0
} /* end H5T__conv_struct_init() */
353
354
/*-------------------------------------------------------------------------
355
 * Function:    H5T__conv_struct_free
356
 *
357
 * Purpose:     Free the private data structure used by the compound
358
 *              conversion functions.
359
 *
360
 * Return:      Non-negative on success/Negative on failure
361
 *
362
 *-------------------------------------------------------------------------
363
 */
364
static herr_t
365
H5T__conv_struct_free(H5T_conv_struct_t *priv)
366
0
{
367
0
    int    *src2dst     = priv->src2dst;
368
0
    H5T_t **src_memb    = priv->src_memb;
369
0
    H5T_t **dst_memb    = priv->dst_memb;
370
0
    hid_t  *src_memb_id = priv->src_memb_id;
371
0
    hid_t  *dst_memb_id = priv->dst_memb_id;
372
0
    herr_t  ret_value   = SUCCEED;
373
374
0
    FUNC_ENTER_PACKAGE_NOERR
375
376
0
    for (unsigned i = 0; i < priv->src_nmembs; i++)
377
0
        if (src2dst[i] >= 0) {
378
0
            if (src_memb_id[i] >= 0) {
379
0
                if (H5I_dec_ref(src_memb_id[i]) < 0)
380
0
                    ret_value = FAIL; /* set return value, but keep going */
381
0
                src_memb_id[i] = H5I_INVALID_HID;
382
0
                src_memb[i]    = NULL;
383
0
            }
384
0
            else {
385
0
                if (H5T_close(src_memb[i]) < 0)
386
0
                    ret_value = FAIL; /* set return value, but keep going */
387
0
                src_memb[i] = NULL;
388
0
            }
389
0
            if (dst_memb_id[src2dst[i]] >= 0) {
390
0
                if (H5I_dec_ref(dst_memb_id[src2dst[i]]) < 0)
391
0
                    ret_value = FAIL; /* set return value, but keep going */
392
0
                dst_memb_id[src2dst[i]] = H5I_INVALID_HID;
393
0
                dst_memb[src2dst[i]]    = NULL;
394
0
            }
395
0
            else {
396
0
                if (H5T_close(dst_memb[src2dst[i]]) < 0)
397
0
                    ret_value = FAIL; /* set return value, but keep going */
398
0
                dst_memb[src2dst[i]] = NULL;
399
0
            }
400
0
        } /* end if */
401
402
0
    H5MM_xfree(src2dst);
403
0
    H5MM_xfree(src_memb);
404
0
    H5MM_xfree(dst_memb);
405
0
    H5MM_xfree(src_memb_id);
406
0
    H5MM_xfree(dst_memb_id);
407
408
0
    H5MM_xfree(priv->memb_path);
409
0
    H5MM_xfree(priv);
410
411
0
    FUNC_LEAVE_NOAPI(ret_value)
412
0
} /* end H5T__conv_struct_free() */
413
414
/*-------------------------------------------------------------------------
415
 * Function:    H5T__conv_struct
416
 *
417
 * Purpose:     Converts between compound datatypes. This is a soft
418
 *              conversion function. The algorithm is basically:
419
 *
420
 *              For each element do
421
 *                For I=1..NELMTS do
422
 *                  If sizeof destination type <= sizeof source type then
423
 *                    Convert member to destination type;
424
 *                  Move member as far left as possible;
425
 *
426
 *              For I=NELMTS..1 do
427
 *                If not destination type then
428
 *                  Convert member to destination type;
429
 *                Move member to correct position in BKG
430
 *
431
 *              Copy BKG to BUF
432
 *
433
 * Return:      Non-negative on success/Negative on failure
434
 *
435
 *-------------------------------------------------------------------------
436
 */
437
herr_t
438
H5T__conv_struct(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx,
439
                 size_t nelmts, size_t buf_stride, size_t bkg_stride, void *_buf, void *_bkg)
440
0
{
441
0
    uint8_t           *buf  = (uint8_t *)_buf;  /*cast for pointer arithmetic    */
442
0
    uint8_t           *bkg  = (uint8_t *)_bkg;  /*background pointer arithmetic    */
443
0
    uint8_t           *xbuf = buf, *xbkg = bkg; /*temp pointers into buf and bkg*/
444
0
    int               *src2dst  = NULL;         /*maps src member to dst member    */
445
0
    H5T_cmemb_t       *src_memb = NULL;         /*source struct member descript.*/
446
0
    H5T_cmemb_t       *dst_memb = NULL;         /*destination struct memb desc.    */
447
0
    size_t             offset;                  /*byte offset wrt struct    */
448
0
    ssize_t            src_delta;               /*source stride    */
449
0
    ssize_t            bkg_delta;               /*background stride    */
450
0
    size_t             elmtno;
451
0
    unsigned           u; /*counters */
452
0
    H5T_conv_struct_t *priv         = (H5T_conv_struct_t *)(cdata->priv);
453
0
    H5T_conv_ctx_t     tmp_conv_ctx = {0};
454
0
    herr_t             ret_value    = SUCCEED; /* Return value */
455
456
0
    FUNC_ENTER_PACKAGE
457
458
0
    switch (cdata->command) {
459
0
        case H5T_CONV_INIT:
460
            /*
461
             * First, determine if this conversion function applies to the
462
             * conversion path SRC-->DST.  If not, return failure;
463
             * otherwise initialize the `priv' field of `cdata' with information
464
             * that remains (almost) constant for this conversion path.
465
             */
466
0
            if (NULL == src || NULL == dst)
467
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype");
468
0
            if (H5T_COMPOUND != src->shared->type)
469
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype");
470
0
            if (H5T_COMPOUND != dst->shared->type)
471
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype");
472
473
0
            if (H5T__conv_struct_init(src, dst, cdata, conv_ctx) < 0)
474
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data");
475
0
            break;
476
477
0
        case H5T_CONV_FREE: {
478
            /*
479
             * Free the private conversion data.
480
             */
481
0
            herr_t status = H5T__conv_struct_free(priv);
482
0
            cdata->priv   = NULL;
483
0
            if (status < 0)
484
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free private conversion data");
485
486
0
            break;
487
0
        }
488
489
0
        case H5T_CONV_CONV:
490
            /*
491
             * Conversion.
492
             */
493
0
            if (NULL == src || NULL == dst)
494
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a datatype");
495
0
            if (NULL == conv_ctx)
496
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid datatype conversion context pointer");
497
0
            assert(priv);
498
0
            assert(bkg && cdata->need_bkg);
499
500
            /* Initialize temporary conversion context */
501
0
            tmp_conv_ctx = *conv_ctx;
502
503
0
            if (cdata->recalc && H5T__conv_struct_init(src, dst, cdata, conv_ctx) < 0)
504
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data");
505
506
            /*
507
             * Insure that members are sorted.
508
             */
509
0
            H5T__sort_value(src, NULL);
510
0
            H5T__sort_value(dst, NULL);
511
0
            src2dst = priv->src2dst;
512
513
            /*
514
             * Direction of conversion and striding through background.
515
             */
516
0
            if (buf_stride) {
517
0
                H5_CHECKED_ASSIGN(src_delta, ssize_t, buf_stride, size_t);
518
0
                if (!bkg_stride) {
519
0
                    H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
520
0
                } /* end if */
521
0
                else
522
0
                    H5_CHECKED_ASSIGN(bkg_delta, ssize_t, bkg_stride, size_t);
523
0
            } /* end if */
524
0
            else if (dst->shared->size <= src->shared->size) {
525
0
                H5_CHECKED_ASSIGN(src_delta, ssize_t, src->shared->size, size_t);
526
0
                H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
527
0
            } /* end else-if */
528
0
            else {
529
0
                H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
530
0
                src_delta = -(ssize_t)src->shared->size;
531
0
                H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
532
0
                bkg_delta = -(ssize_t)dst->shared->size;
533
0
                xbuf += (nelmts - 1) * src->shared->size;
534
0
                xbkg += (nelmts - 1) * dst->shared->size;
535
0
            } /* end else */
536
537
            /* Conversion loop... */
538
0
            for (elmtno = 0; elmtno < nelmts; elmtno++) {
539
                /*
540
                 * For each source member which will be present in the
541
                 * destination, convert the member to the destination type unless
542
                 * it is larger than the source type.  Then move the member to the
543
                 * left-most unoccupied position in the buffer.  This makes the
544
                 * data point as small as possible with all the free space on the
545
                 * right side.
546
                 */
547
0
                tmp_conv_ctx.u.conv.recursive = true;
548
0
                for (u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
549
0
                    if (src2dst[u] < 0)
550
0
                        continue; /*subsetting*/
551
0
                    src_memb = src->shared->u.compnd.memb + u;
552
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[u];
553
554
0
                    if (dst_memb->size <= src_memb->size) {
555
                        /* Update IDs in conversion context */
556
0
                        tmp_conv_ctx.u.conv.src_type_id = priv->src_memb_id[u];
557
0
                        tmp_conv_ctx.u.conv.dst_type_id = priv->dst_memb_id[src2dst[u]];
558
559
0
                        if (H5T_convert_with_ctx(priv->memb_path[u], priv->src_memb[u],
560
0
                                                 priv->dst_memb[src2dst[u]], &tmp_conv_ctx, (size_t)1,
561
0
                                                 (size_t)0, (size_t)0, /*no striding (packed array)*/
562
0
                                                 xbuf + src_memb->offset, xbkg + dst_memb->offset) < 0)
563
0
                            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL,
564
0
                                        "unable to convert compound datatype member");
565
566
0
                        memmove(xbuf + offset, xbuf + src_memb->offset, dst_memb->size);
567
0
                        offset += dst_memb->size;
568
0
                    } /* end if */
569
0
                    else {
570
0
                        memmove(xbuf + offset, xbuf + src_memb->offset, src_memb->size);
571
0
                        offset += src_memb->size;
572
0
                    } /* end else */
573
0
                }     /* end for */
574
0
                tmp_conv_ctx.u.conv.recursive = false;
575
576
                /*
577
                 * For each source member which will be present in the
578
                 * destination, convert the member to the destination type if it
579
                 * is larger than the source type (that is, has not been converted
580
                 * yet).  Then copy the member to the destination offset in the
581
                 * background buffer.
582
                 */
583
0
                tmp_conv_ctx.u.conv.recursive = true;
584
0
                H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
585
0
                for (int i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
586
0
                    if (src2dst[i] < 0)
587
0
                        continue; /*subsetting*/
588
0
                    src_memb = src->shared->u.compnd.memb + i;
589
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[i];
590
591
0
                    if (dst_memb->size > src_memb->size) {
592
                        /* Update IDs in conversion context */
593
0
                        tmp_conv_ctx.u.conv.src_type_id = priv->src_memb_id[i];
594
0
                        tmp_conv_ctx.u.conv.dst_type_id = priv->dst_memb_id[src2dst[i]];
595
596
0
                        offset -= src_memb->size;
597
0
                        if (H5T_convert_with_ctx(priv->memb_path[i], priv->src_memb[i],
598
0
                                                 priv->dst_memb[src2dst[i]], &tmp_conv_ctx, (size_t)1,
599
0
                                                 (size_t)0, (size_t)0, /*no striding (packed array)*/
600
0
                                                 xbuf + offset, xbkg + dst_memb->offset) < 0)
601
0
                            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL,
602
0
                                        "unable to convert compound datatype member");
603
0
                    } /* end if */
604
0
                    else
605
0
                        offset -= dst_memb->size;
606
0
                    memcpy(xbkg + dst_memb->offset, xbuf + offset, dst_memb->size);
607
0
                } /* end for */
608
0
                tmp_conv_ctx.u.conv.recursive = false;
609
610
0
                assert(0 == offset);
611
612
                /*
613
                 * Update pointers
614
                 */
615
0
                xbuf += src_delta;
616
0
                xbkg += bkg_delta;
617
0
            } /* end for */
618
619
            /* If the bkg_delta was set to -(dst->shared->size), make it positive now */
620
0
            if (buf_stride == 0 && dst->shared->size > src->shared->size)
621
0
                H5_CHECKED_ASSIGN(bkg_delta, ssize_t, dst->shared->size, size_t);
622
623
            /*
624
             * Copy the background buffer back into the in-place conversion
625
             * buffer.
626
             */
627
0
            for (xbuf = buf, xbkg = bkg, elmtno = 0; elmtno < nelmts; elmtno++) {
628
0
                memcpy(xbuf, xbkg, dst->shared->size);
629
0
                xbuf += buf_stride ? buf_stride : dst->shared->size;
630
0
                xbkg += bkg_delta;
631
0
            } /* end for */
632
0
            break;
633
634
0
        default:
635
            /* Some other command we don't know about yet.*/
636
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command");
637
0
    } /* end switch */
638
639
0
done:
640
0
    FUNC_LEAVE_NOAPI(ret_value)
641
0
} /* end H5T__conv_struct() */
642
643
/*-------------------------------------------------------------------------
644
 * Function:    H5T__conv_struct_opt
645
 *
646
 * Purpose:     Converts between compound datatypes in a manner more
647
 *              efficient than the general-purpose H5T__conv_struct()
648
 *              function. This function isn't applicable if the destination
649
 *              is larger than the source type. This is a soft conversion
650
 *              function. The algorithm is basically:
651
 *
652
 *              For each member of the struct
653
 *                If sizeof destination type <= sizeof source type then
654
 *                  Convert member to destination type for all elements
655
 *                  Move memb to BKG buffer for all elements
656
 *                Else
657
 *                  Move member as far left as possible for all elements
658
 *
659
 *              For each member of the struct (in reverse order)
660
 *                If not destination type then
661
 *                  Convert member to destination type for all elements
662
 *                  Move member to correct position in BKG for all elements
663
 *
664
 *              Copy BKG to BUF for all elements
665
 *
666
 *              Special case when the source and destination members
667
 *              are a subset of each other, and the order is the same, and
668
 *              no conversion is needed. For example:
669
 *
670
 *                  struct source {            struct destination {
671
 *                      TYPE1 A;      -->          TYPE1 A;
672
 *                      TYPE2 B;      -->          TYPE2 B;
673
 *                      TYPE3 C;      -->          TYPE3 C;
674
 *                  };                             TYPE4 D;
675
 *                                                 TYPE5 E;
676
 *                                             };
677
 *
678
 *              The optimization is simply moving data to the appropriate
679
 *              places in the buffer.
680
 *
681
 * Return:      Non-negative on success/Negative on failure
682
 *
683
 *-------------------------------------------------------------------------
684
 */
685
herr_t
686
H5T__conv_struct_opt(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx,
687
                     size_t nelmts, size_t buf_stride, size_t bkg_stride, void *_buf, void *_bkg)
688
0
{
689
0
    uint8_t           *buf      = (uint8_t *)_buf; /*cast for pointer arithmetic    */
690
0
    uint8_t           *bkg      = (uint8_t *)_bkg; /*background pointer arithmetic    */
691
0
    uint8_t           *xbuf     = NULL;            /*temporary pointer into `buf'    */
692
0
    uint8_t           *xbkg     = NULL;            /*temporary pointer into `bkg'    */
693
0
    int               *src2dst  = NULL;            /*maps src member to dst member    */
694
0
    H5T_cmemb_t       *src_memb = NULL;            /*source struct member descript.*/
695
0
    H5T_cmemb_t       *dst_memb = NULL;            /*destination struct memb desc.    */
696
0
    size_t             offset;                     /*byte offset wrt struct    */
697
0
    size_t             elmtno;                     /*element counter        */
698
0
    size_t             copy_size;                  /*size of element for copying   */
699
0
    H5T_conv_struct_t *priv         = NULL;        /*private data            */
700
0
    H5T_conv_ctx_t     tmp_conv_ctx = {0};         /*temporary conversion context */
701
0
    bool               no_stride    = false;       /*flag to indicate no stride    */
702
0
    unsigned           u;                          /*counters */
703
0
    herr_t             ret_value = SUCCEED;        /* Return value */
704
705
0
    FUNC_ENTER_PACKAGE
706
707
0
    switch (cdata->command) {
708
0
        case H5T_CONV_INIT:
709
            /*
710
             * First, determine if this conversion function applies to the
711
             * conversion path SRC-->DST.  If not, return failure;
712
             * otherwise initialize the `priv' field of `cdata' with information
713
             * that remains (almost) constant for this conversion path.
714
             */
715
0
            if (NULL == src || NULL == dst)
716
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
717
0
            if (H5T_COMPOUND != src->shared->type)
718
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype");
719
0
            if (H5T_COMPOUND != dst->shared->type)
720
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADTYPE, FAIL, "not a H5T_COMPOUND datatype");
721
722
            /* Initialize data which is relatively constant */
723
0
            if (H5T__conv_struct_init(src, dst, cdata, conv_ctx) < 0)
724
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data");
725
0
            priv    = (H5T_conv_struct_t *)(cdata->priv);
726
0
            src2dst = priv->src2dst;
727
728
            /*
729
             * If the destination type is not larger than the source type then
730
             * this conversion function is guaranteed to work (provided all
731
             * members can be converted also). Otherwise the determination is
732
             * quite a bit more complicated. Essentially we have to make sure
733
             * that there is always room in the source buffer to do the
734
             * conversion of a member in place. This is basically the same pair
735
             * of loops as in the actual conversion except it checks that there
736
             * is room for each conversion instead of actually doing anything.
737
             */
738
0
            if (dst->shared->size > src->shared->size) {
739
0
                for (u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
740
0
                    if (src2dst[u] < 0)
741
0
                        continue;
742
0
                    src_memb = src->shared->u.compnd.memb + u;
743
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[u];
744
0
                    if (dst_memb->size > src_memb->size)
745
0
                        offset += src_memb->size;
746
0
                } /* end for */
747
0
                H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
748
0
                for (int i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
749
0
                    if (src2dst[i] < 0)
750
0
                        continue;
751
0
                    src_memb = src->shared->u.compnd.memb + i;
752
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[i];
753
0
                    if (dst_memb->size > src_memb->size) {
754
0
                        offset -= src_memb->size;
755
0
                        if (dst_memb->size > src->shared->size - offset) {
756
0
                            H5T__conv_struct_free(priv);
757
0
                            cdata->priv = NULL;
758
0
                            HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL,
759
0
                                        "conversion is unsupported by this function");
760
0
                        } /* end if */
761
0
                    }     /* end if */
762
0
                }         /* end for */
763
0
            }             /* end if */
764
0
            break;
765
766
0
        case H5T_CONV_FREE: {
767
            /*
768
             * Free the private conversion data.
769
             */
770
0
            herr_t status = H5T__conv_struct_free((H5T_conv_struct_t *)(cdata->priv));
771
0
            cdata->priv   = NULL;
772
0
            if (status < 0)
773
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "unable to free private conversion data");
774
775
0
            break;
776
0
        }
777
778
0
        case H5T_CONV_CONV:
779
            /*
780
             * Conversion.
781
             */
782
0
            if (NULL == src || NULL == dst)
783
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
784
0
            if (NULL == conv_ctx)
785
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid datatype conversion context pointer");
786
0
            if (!bkg)
787
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_BADVALUE, FAIL, "invalid background buffer pointer");
788
789
            /* Initialize temporary conversion context */
790
0
            tmp_conv_ctx = *conv_ctx;
791
792
            /* Update cached data if necessary */
793
0
            if (cdata->recalc && H5T__conv_struct_init(src, dst, cdata, conv_ctx) < 0)
794
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to initialize conversion data");
795
0
            priv = (H5T_conv_struct_t *)(cdata->priv);
796
0
            assert(priv);
797
0
            src2dst = priv->src2dst;
798
0
            assert(cdata->need_bkg);
799
800
            /*
801
             * Insure that members are sorted.
802
             */
803
0
            H5T__sort_value(src, NULL);
804
0
            H5T__sort_value(dst, NULL);
805
806
            /*
807
             * Calculate strides. If BUF_STRIDE is non-zero then convert one
808
             * data element at every BUF_STRIDE bytes through the main buffer
809
             * (BUF), leaving the result of each conversion at the same
810
             * location; otherwise assume the source and destination data are
811
             * packed tightly based on src->shared->size and dst->shared->size.  Also, if
812
             * BUF_STRIDE and BKG_STRIDE are both non-zero then place
813
             * background data into the BKG buffer at multiples of BKG_STRIDE;
814
             * otherwise assume BKG buffer is the packed destination datatype.
815
             */
816
0
            if (!buf_stride || !bkg_stride)
817
0
                bkg_stride = dst->shared->size;
818
0
            if (!buf_stride) {
819
0
                no_stride  = true;
820
0
                buf_stride = src->shared->size;
821
0
            } /* end if */
822
823
0
            if (priv->subset_info.subset == H5T_SUBSET_SRC || priv->subset_info.subset == H5T_SUBSET_DST) {
824
                /* If the optimization flag is set to indicate source members are a subset and
825
                 * in the top of the destination, simply copy the source members to background buffer.
826
                 */
827
0
                xbuf      = buf;
828
0
                xbkg      = bkg;
829
0
                copy_size = priv->subset_info.copy_size;
830
831
0
                for (elmtno = 0; elmtno < nelmts; elmtno++) {
832
0
                    memcpy(xbkg, xbuf, copy_size);
833
834
                    /* Update pointers */
835
0
                    xbuf += buf_stride;
836
0
                    xbkg += bkg_stride;
837
0
                } /* end for */
838
0
            }     /* end if */
839
0
            else {
840
                /*
841
                 * For each member where the destination is not larger than the
842
                 * source, stride through all the elements converting only that member
843
                 * in each element and then copying the element to its final
844
                 * destination in the bkg buffer. Otherwise move the element as far
845
                 * left as possible in the buffer.
846
                 */
847
0
                tmp_conv_ctx.u.conv.recursive = true;
848
0
                for (u = 0, offset = 0; u < src->shared->u.compnd.nmembs; u++) {
849
0
                    if (src2dst[u] < 0)
850
0
                        continue; /*subsetting*/
851
0
                    src_memb = src->shared->u.compnd.memb + u;
852
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[u];
853
854
0
                    if (dst_memb->size <= src_memb->size) {
855
                        /* Update IDs in conversion context */
856
0
                        tmp_conv_ctx.u.conv.src_type_id = priv->src_memb_id[u];
857
0
                        tmp_conv_ctx.u.conv.dst_type_id = priv->dst_memb_id[src2dst[u]];
858
859
0
                        xbuf = buf + src_memb->offset;
860
0
                        xbkg = bkg + dst_memb->offset;
861
0
                        if (H5T_convert_with_ctx(priv->memb_path[u], priv->src_memb[u],
862
0
                                                 priv->dst_memb[src2dst[u]], &tmp_conv_ctx, nelmts,
863
0
                                                 buf_stride, bkg_stride, xbuf, xbkg) < 0)
864
0
                            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL,
865
0
                                        "unable to convert compound datatype member");
866
867
0
                        for (elmtno = 0; elmtno < nelmts; elmtno++) {
868
0
                            memcpy(xbkg, xbuf, dst_memb->size);
869
0
                            xbuf += buf_stride;
870
0
                            xbkg += bkg_stride;
871
0
                        } /* end for */
872
0
                    }     /* end if */
873
0
                    else {
874
0
                        for (xbuf = buf, elmtno = 0; elmtno < nelmts; elmtno++) {
875
0
                            memmove(xbuf + offset, xbuf + src_memb->offset, src_memb->size);
876
0
                            xbuf += buf_stride;
877
0
                        } /* end for */
878
0
                        offset += src_memb->size;
879
0
                    } /* end else */
880
0
                }     /* end else */
881
0
                tmp_conv_ctx.u.conv.recursive = false;
882
883
                /*
884
                 * Work from right to left, converting those members that weren't
885
                 * converted in the previous loop (those members where the destination
886
                 * is larger than the source) and them to their final position in the
887
                 * bkg buffer.
888
                 */
889
0
                tmp_conv_ctx.u.conv.recursive = true;
890
0
                H5_CHECK_OVERFLOW(src->shared->u.compnd.nmembs, size_t, int);
891
0
                for (int i = (int)src->shared->u.compnd.nmembs - 1; i >= 0; --i) {
892
0
                    if (src2dst[i] < 0)
893
0
                        continue;
894
0
                    src_memb = src->shared->u.compnd.memb + i;
895
0
                    dst_memb = dst->shared->u.compnd.memb + src2dst[i];
896
897
0
                    if (dst_memb->size > src_memb->size) {
898
                        /* Update IDs in conversion context */
899
0
                        tmp_conv_ctx.u.conv.src_type_id = priv->src_memb_id[i];
900
0
                        tmp_conv_ctx.u.conv.dst_type_id = priv->dst_memb_id[src2dst[i]];
901
902
0
                        offset -= src_memb->size;
903
0
                        xbuf = buf + offset;
904
0
                        xbkg = bkg + dst_memb->offset;
905
0
                        if (H5T_convert_with_ctx(priv->memb_path[i], priv->src_memb[i],
906
0
                                                 priv->dst_memb[src2dst[i]], &tmp_conv_ctx, nelmts,
907
0
                                                 buf_stride, bkg_stride, xbuf, xbkg) < 0)
908
0
                            HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL,
909
0
                                        "unable to convert compound datatype member");
910
0
                        for (elmtno = 0; elmtno < nelmts; elmtno++) {
911
0
                            memcpy(xbkg, xbuf, dst_memb->size);
912
0
                            xbuf += buf_stride;
913
0
                            xbkg += bkg_stride;
914
0
                        } /* end for */
915
0
                    }     /* end if */
916
0
                }         /* end for */
917
0
                tmp_conv_ctx.u.conv.recursive = false;
918
0
            } /* end else */
919
920
0
            if (no_stride)
921
0
                buf_stride = dst->shared->size;
922
923
            /* Move background buffer into result buffer */
924
0
            for (xbuf = buf, xbkg = bkg, elmtno = 0; elmtno < nelmts; elmtno++) {
925
0
                memcpy(xbuf, xbkg, dst->shared->size);
926
0
                xbuf += buf_stride;
927
0
                xbkg += bkg_stride;
928
0
            } /* end for */
929
0
            break;
930
931
0
        default:
932
            /* Some other command we don't know about yet.*/
933
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command");
934
0
    } /* end switch */
935
936
0
done:
937
0
    FUNC_LEAVE_NOAPI(ret_value)
938
0
} /* end H5T__conv_struct_opt() */