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