Coverage Report

Created: 2026-02-23 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Tconv_bitfield.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 bitfield 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 "H5Tconv.h"    /* Datatype conversions                 */
28
#include "H5Tconv_bitfield.h"
29
30
/*-------------------------------------------------------------------------
31
 * Function:    H5T__conv_b_b
32
 *
33
 * Purpose:     Convert from one bitfield to any other bitfield.
34
 *
35
 * Return:      Non-negative on success/Negative on failure
36
 *
37
 *-------------------------------------------------------------------------
38
 */
39
herr_t
40
H5T__conv_b_b(const H5T_t *src, const H5T_t *dst, H5T_cdata_t *cdata, const H5T_conv_ctx_t *conv_ctx,
41
              size_t nelmts, size_t buf_stride, size_t H5_ATTR_UNUSED bkg_stride, void *_buf,
42
              void H5_ATTR_UNUSED *background)
43
0
{
44
0
    uint8_t       *buf = (uint8_t *)_buf;
45
0
    ssize_t        direction;       /*direction of traversal    */
46
0
    size_t         elmtno;          /*element number        */
47
0
    size_t         olap;            /*num overlapping elements    */
48
0
    size_t         half_size;       /*1/2 of total size for swapping*/
49
0
    uint8_t       *s, *sp, *d, *dp; /*source and dest traversal ptrs*/
50
0
    uint8_t        dbuf[256] = {0}; /*temp destination buffer    */
51
0
    size_t         msb_pad_offset;  /*offset for dest MSB padding    */
52
0
    size_t         i;
53
0
    uint8_t       *src_rev = NULL;      /*order-reversed source buffer  */
54
0
    H5T_conv_ret_t except_ret;          /*return of callback function   */
55
0
    bool           reverse;             /*if reverse the order of destination        */
56
0
    herr_t         ret_value = SUCCEED; /* Return value */
57
58
0
    FUNC_ENTER_PACKAGE
59
60
0
    switch (cdata->command) {
61
0
        case H5T_CONV_INIT:
62
            /* Capability query */
63
0
            if (NULL == src || NULL == dst)
64
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
65
0
            if (H5T_ORDER_LE != src->shared->u.atomic.order && H5T_ORDER_BE != src->shared->u.atomic.order)
66
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order");
67
0
            if (H5T_ORDER_LE != dst->shared->u.atomic.order && H5T_ORDER_BE != dst->shared->u.atomic.order)
68
0
                HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported byte order");
69
0
            cdata->need_bkg = H5T_BKG_NO;
70
0
            break;
71
72
0
        case H5T_CONV_FREE:
73
0
            break;
74
75
0
        case H5T_CONV_CONV:
76
0
            if (NULL == src || NULL == dst)
77
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype");
78
0
            if (NULL == conv_ctx)
79
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid datatype conversion context pointer");
80
81
            /*
82
             * Do we process the values from beginning to end or vice versa? Also,
83
             * how many of the elements have the source and destination areas
84
             * overlapping?
85
             */
86
0
            if (src->shared->size == dst->shared->size || buf_stride) {
87
0
                sp = dp   = (uint8_t *)buf;
88
0
                direction = 1;
89
0
                olap      = nelmts;
90
0
            }
91
0
            else if (src->shared->size >= dst->shared->size) {
92
0
                double olap_d =
93
0
                    ceil((double)(dst->shared->size) / (double)(src->shared->size - dst->shared->size));
94
95
0
                olap = (size_t)olap_d;
96
0
                sp = dp   = (uint8_t *)buf;
97
0
                direction = 1;
98
0
            }
99
0
            else {
100
0
                double olap_d =
101
0
                    ceil((double)(src->shared->size) / (double)(dst->shared->size - src->shared->size));
102
0
                olap      = (size_t)olap_d;
103
0
                sp        = (uint8_t *)buf + (nelmts - 1) * src->shared->size;
104
0
                dp        = (uint8_t *)buf + (nelmts - 1) * dst->shared->size;
105
0
                direction = -1;
106
0
            }
107
108
            /* Allocate space for order-reversed source buffer */
109
0
            if (conv_ctx->u.conv.cb_struct.func)
110
0
                if (NULL == (src_rev = H5MM_calloc(src->shared->size)))
111
0
                    HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "unable to allocate temporary buffer");
112
113
            /* The conversion loop */
114
0
            H5_CHECK_OVERFLOW(buf_stride, size_t, ssize_t);
115
0
            H5_CHECK_OVERFLOW(src->shared->size, size_t, ssize_t);
116
0
            H5_CHECK_OVERFLOW(dst->shared->size, size_t, ssize_t);
117
0
            for (elmtno = 0; elmtno < nelmts; elmtno++) {
118
119
                /*
120
                 * If the source and destination buffers overlap then use a
121
                 * temporary buffer for the destination.
122
                 */
123
0
                if (direction > 0) {
124
0
                    s = sp;
125
0
                    d = elmtno < olap ? dbuf : dp;
126
0
                } /* end if */
127
0
                else {
128
0
                    s = sp;
129
0
                    d = (elmtno + olap) >= nelmts ? dbuf : dp;
130
0
                } /* end else */
131
#ifndef NDEBUG
132
                /* I don't quite trust the overlap calculations yet  */
133
                if (d == dbuf)
134
                    assert((dp >= sp && dp < sp + src->shared->size) ||
135
                           (sp >= dp && sp < dp + dst->shared->size));
136
                else
137
                    assert((dp < sp && dp + dst->shared->size <= sp) ||
138
                           (sp < dp && sp + src->shared->size <= dp));
139
#endif
140
141
                /*
142
                 * Put the data in little endian order so our loops aren't so
143
                 * complicated.  We'll do all the conversion stuff assuming
144
                 * little endian and then we'll fix the order at the end.
145
                 */
146
0
                if (H5T_ORDER_BE == src->shared->u.atomic.order) {
147
0
                    half_size = src->shared->size / 2;
148
0
                    for (i = 0; i < half_size; i++) {
149
0
                        uint8_t tmp                    = s[src->shared->size - (i + 1)];
150
0
                        s[src->shared->size - (i + 1)] = s[i];
151
0
                        s[i]                           = tmp;
152
0
                    } /* end for */
153
0
                }     /* end if */
154
155
                /* Initiate these variables */
156
0
                except_ret = H5T_CONV_UNHANDLED;
157
0
                reverse    = true;
158
159
                /*
160
                 * Copy the significant part of the value. If the source is larger
161
                 * than the destination then invoke the overflow function or copy
162
                 * as many bits as possible. Zero extra bits in the destination.
163
                 */
164
0
                if (src->shared->u.atomic.prec > dst->shared->u.atomic.prec) {
165
                    /*overflow*/
166
0
                    if (conv_ctx->u.conv.cb_struct.func) { /*If user's exception handler is present, use it*/
167
                        /* Reverse order first */
168
0
                        H5T__reverse_order(src_rev, s, src);
169
170
                        /* Prepare & restore library for user callback */
171
0
                        H5_BEFORE_USER_CB(FAIL)
172
0
                            {
173
0
                                except_ret = (conv_ctx->u.conv.cb_struct.func)(
174
0
                                    H5T_CONV_EXCEPT_RANGE_HI, conv_ctx->u.conv.src_type_id,
175
0
                                    conv_ctx->u.conv.dst_type_id, src_rev, d,
176
0
                                    conv_ctx->u.conv.cb_struct.user_data);
177
0
                            }
178
0
                        H5_AFTER_USER_CB(FAIL)
179
0
                    } /* end if */
180
181
0
                    if (except_ret == H5T_CONV_UNHANDLED) {
182
0
                        H5T__bit_copy(d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
183
0
                                      dst->shared->u.atomic.prec);
184
0
                    }
185
0
                    else if (except_ret == H5T_CONV_ABORT)
186
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCONVERT, FAIL, "can't handle conversion exception");
187
0
                    else if (except_ret == H5T_CONV_HANDLED)
188
                        /*Don't reverse because user handles it*/
189
0
                        reverse = false;
190
0
                }
191
0
                else {
192
0
                    H5T__bit_copy(d, dst->shared->u.atomic.offset, s, src->shared->u.atomic.offset,
193
0
                                  src->shared->u.atomic.prec);
194
0
                    H5T__bit_set(d, dst->shared->u.atomic.offset + src->shared->u.atomic.prec,
195
0
                                 dst->shared->u.atomic.prec - src->shared->u.atomic.prec, false);
196
0
                }
197
198
                /*
199
                 * Fill the destination padding areas.
200
                 */
201
0
                switch (dst->shared->u.atomic.lsb_pad) {
202
0
                    case H5T_PAD_ZERO:
203
0
                        H5T__bit_set(d, (size_t)0, dst->shared->u.atomic.offset, false);
204
0
                        break;
205
206
0
                    case H5T_PAD_ONE:
207
0
                        H5T__bit_set(d, (size_t)0, dst->shared->u.atomic.offset, true);
208
0
                        break;
209
210
0
                    case H5T_PAD_ERROR:
211
0
                    case H5T_PAD_BACKGROUND:
212
0
                    case H5T_NPAD:
213
0
                    default:
214
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported LSB padding");
215
0
                } /* end switch */
216
0
                msb_pad_offset = dst->shared->u.atomic.offset + dst->shared->u.atomic.prec;
217
0
                switch (dst->shared->u.atomic.msb_pad) {
218
0
                    case H5T_PAD_ZERO:
219
0
                        H5T__bit_set(d, msb_pad_offset, 8 * dst->shared->size - msb_pad_offset, false);
220
0
                        break;
221
222
0
                    case H5T_PAD_ONE:
223
0
                        H5T__bit_set(d, msb_pad_offset, 8 * dst->shared->size - msb_pad_offset, true);
224
0
                        break;
225
226
0
                    case H5T_PAD_ERROR:
227
0
                    case H5T_PAD_BACKGROUND:
228
0
                    case H5T_NPAD:
229
0
                    default:
230
0
                        HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unsupported MSB padding");
231
0
                } /* end switch */
232
233
                /*
234
                 * Put the destination in the correct byte order.  See note at
235
                 * beginning of loop.
236
                 */
237
0
                if (H5T_ORDER_BE == dst->shared->u.atomic.order && reverse) {
238
0
                    half_size = dst->shared->size / 2;
239
0
                    for (i = 0; i < half_size; i++) {
240
0
                        uint8_t tmp                    = d[dst->shared->size - (i + 1)];
241
0
                        d[dst->shared->size - (i + 1)] = d[i];
242
0
                        d[i]                           = tmp;
243
0
                    } /* end for */
244
0
                }     /* end if */
245
246
                /*
247
                 * If we had used a temporary buffer for the destination then we
248
                 * should copy the value to the true destination buffer.
249
                 */
250
0
                if (d == dbuf)
251
0
                    H5MM_memcpy(dp, d, dst->shared->size);
252
0
                if (buf_stride) {
253
0
                    sp += direction *
254
0
                          (ssize_t)buf_stride; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
255
0
                    dp += direction *
256
0
                          (ssize_t)buf_stride; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
257
0
                }                              /* end if */
258
0
                else {
259
0
                    sp += direction *
260
0
                          (ssize_t)
261
0
                              src->shared->size; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
262
0
                    dp += direction *
263
0
                          (ssize_t)
264
0
                              dst->shared->size; /* Note that cast is checked with H5_CHECK_OVERFLOW, above */
265
0
                }                                /* end else */
266
0
            }                                    /* end for */
267
268
0
            break;
269
270
0
        default:
271
0
            HGOTO_ERROR(H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unknown conversion command");
272
0
    } /* end switch */
273
274
0
done:
275
0
    if (src_rev)
276
0
        H5MM_free(src_rev);
277
0
    FUNC_LEAVE_NOAPI(ret_value)
278
0
} /* end H5T__conv_b_b() */