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