/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() */ |