/src/hdf5/src/H5Zscaleoffset.c
Line | Count | Source (jump to first uncovered line) |
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 COPYING 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 | | #include "H5Zmodule.h" /* This source code file is part of the H5Z module */ |
14 | | |
15 | | #include "H5private.h" /* Generic Functions */ |
16 | | #include "H5Eprivate.h" /* Error handling */ |
17 | | #include "H5Iprivate.h" /* IDs */ |
18 | | #include "H5MMprivate.h" /* Memory management */ |
19 | | #include "H5Pprivate.h" /* Property lists */ |
20 | | #include "H5Oprivate.h" /* Object headers */ |
21 | | #include "H5Sprivate.h" /* Dataspaces */ |
22 | | #include "H5Tprivate.h" /* Datatypes */ |
23 | | #include "H5Zpkg.h" /* Data filters */ |
24 | | |
25 | | /* Struct of parameters needed for compressing/decompressing one atomic datatype */ |
26 | | typedef struct { |
27 | | unsigned size; /* datatype size */ |
28 | | uint32_t minbits; /* minimum bits to compress one value of such datatype */ |
29 | | unsigned mem_order; /* current memory endianness order */ |
30 | | } parms_atomic; |
31 | | |
32 | | enum H5Z_scaleoffset_t { |
33 | | t_bad = 0, |
34 | | t_uchar = 1, |
35 | | t_ushort, |
36 | | t_uint, |
37 | | t_ulong, |
38 | | t_ulong_long, |
39 | | t_schar, |
40 | | t_short, |
41 | | t_int, |
42 | | t_long, |
43 | | t_long_long, |
44 | | t_float, |
45 | | t_double |
46 | | }; |
47 | | |
48 | | /* Local function prototypes */ |
49 | | static htri_t H5Z__can_apply_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id); |
50 | | static enum H5Z_scaleoffset_t H5Z__scaleoffset_get_type(unsigned dtype_class, unsigned dtype_size, |
51 | | unsigned dtype_sign); |
52 | | static herr_t H5Z__scaleoffset_set_parms_fillval(H5P_genplist_t *dcpl_plist, H5T_t *type, |
53 | | enum H5Z_scaleoffset_t scale_type, unsigned cd_values[], |
54 | | int need_convert); |
55 | | static herr_t H5Z__set_local_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id); |
56 | | static size_t H5Z__filter_scaleoffset(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], |
57 | | size_t nbytes, size_t *buf_size, void **buf); |
58 | | static void H5Z__scaleoffset_convert(void *buf, unsigned d_nelmts, unsigned dtype_size); |
59 | | static H5_ATTR_CONST unsigned H5Z__scaleoffset_log2(unsigned long long num); |
60 | | static void H5Z__scaleoffset_precompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
61 | | unsigned filavail, const unsigned cd_values[], uint32_t *minbits, |
62 | | unsigned long long *minval); |
63 | | static void H5Z__scaleoffset_postdecompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
64 | | unsigned filavail, const unsigned cd_values[], uint32_t minbits, |
65 | | unsigned long long minval); |
66 | | static herr_t H5Z__scaleoffset_precompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
67 | | unsigned filavail, const unsigned cd_values[], |
68 | | uint32_t *minbits, unsigned long long *minval, double D_val); |
69 | | static herr_t H5Z__scaleoffset_postdecompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
70 | | unsigned filavail, const unsigned cd_values[], |
71 | | uint32_t minbits, unsigned long long minval, double D_val); |
72 | | static void H5Z__scaleoffset_next_byte(size_t *j, unsigned *buf_len); |
73 | | static void H5Z__scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, |
74 | | unsigned begin_i, const unsigned char *buffer, size_t *j, |
75 | | unsigned *buf_len, parms_atomic p, unsigned dtype_len); |
76 | | static void H5Z__scaleoffset_compress_one_byte(const unsigned char *data, size_t data_offset, unsigned k, |
77 | | unsigned begin_i, unsigned char *buffer, size_t *j, |
78 | | unsigned *buf_len, parms_atomic p, unsigned dtype_len); |
79 | | static void H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, |
80 | | unsigned char *buffer, size_t *j, unsigned *buf_len, |
81 | | parms_atomic p); |
82 | | static void H5Z__scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset, |
83 | | unsigned char *buffer, size_t *j, unsigned *buf_len, |
84 | | parms_atomic p); |
85 | | static void H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, |
86 | | parms_atomic p); |
87 | | static void H5Z__scaleoffset_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, |
88 | | size_t buffer_size, parms_atomic p); |
89 | | |
90 | | /* This message derives from H5Z */ |
91 | | H5Z_class2_t H5Z_SCALEOFFSET[1] = {{ |
92 | | H5Z_CLASS_T_VERS, /* H5Z_class_t version */ |
93 | | H5Z_FILTER_SCALEOFFSET, /* Filter id number */ |
94 | | 1, /* Assume encoder present: check before registering */ |
95 | | 1, /* decoder_present flag (set to true) */ |
96 | | "scaleoffset", /* Filter name for debugging */ |
97 | | H5Z__can_apply_scaleoffset, /* The "can apply" callback */ |
98 | | H5Z__set_local_scaleoffset, /* The "set local" callback */ |
99 | | H5Z__filter_scaleoffset, /* The actual filter function */ |
100 | | }}; |
101 | | |
102 | | /* Local macros */ |
103 | 0 | #define H5Z_SCALEOFFSET_TOTAL_NPARMS 20 /* Total number of parameters for filter */ |
104 | 0 | #define H5Z_SCALEOFFSET_PARM_SCALETYPE 0 /* "User" parameter for scale type */ |
105 | 0 | #define H5Z_SCALEOFFSET_PARM_SCALEFACTOR 1 /* "User" parameter for scale factor */ |
106 | 0 | #define H5Z_SCALEOFFSET_PARM_NELMTS 2 /* "Local" parameter for number of elements in the chunk */ |
107 | 0 | #define H5Z_SCALEOFFSET_PARM_CLASS 3 /* "Local" parameter for datatype class */ |
108 | 0 | #define H5Z_SCALEOFFSET_PARM_SIZE 4 /* "Local" parameter for datatype size */ |
109 | 0 | #define H5Z_SCALEOFFSET_PARM_SIGN 5 /* "Local" parameter for integer datatype sign */ |
110 | 0 | #define H5Z_SCALEOFFSET_PARM_ORDER 6 /* "Local" parameter for datatype byte order */ |
111 | 0 | #define H5Z_SCALEOFFSET_PARM_FILAVAIL 7 /* "Local" parameter for dataset fill value existence */ |
112 | 0 | #define H5Z_SCALEOFFSET_PARM_FILVAL 8 /* "Local" parameter for start location to store dataset fill value */ |
113 | | |
114 | 0 | #define H5Z_SCALEOFFSET_CLS_INTEGER 0 /* Integer (datatype class) */ |
115 | 0 | #define H5Z_SCALEOFFSET_CLS_FLOAT 1 /* Floatig-point (datatype class) */ |
116 | | |
117 | 0 | #define H5Z_SCALEOFFSET_SGN_NONE 0 /* Unsigned integer type */ |
118 | 0 | #define H5Z_SCALEOFFSET_SGN_2 1 /* Two's complement signed integer type */ |
119 | | |
120 | 0 | #define H5Z_SCALEOFFSET_ORDER_LE 0 /* Little endian (datatype byte order) */ |
121 | 0 | #define H5Z_SCALEOFFSET_ORDER_BE 1 /* Big endian (datatype byte order) */ |
122 | | |
123 | 0 | #define H5Z_SCALEOFFSET_FILL_UNDEFINED 0 /* Fill value is not defined */ |
124 | 0 | #define H5Z_SCALEOFFSET_FILL_DEFINED 1 /* Fill value is defined */ |
125 | | |
126 | | /* Store fill value in cd_values[] */ |
127 | | #define H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \ |
128 | 0 | { \ |
129 | 0 | unsigned _i = H5Z_SCALEOFFSET_PARM_FILVAL; /* index into cd_values */ \ |
130 | 0 | uint32_t _cd_value; /* Current cd_value */ \ |
131 | 0 | char *_fv_p; /* Pointer to current byte in fill_val */ \ |
132 | 0 | size_t _copy_size = 4; /* # of bytes to copy this iteration */ \ |
133 | 0 | size_t _size_rem = sizeof(type); /* # of bytes left to copy to cd_values */ \ |
134 | 0 | \ |
135 | 0 | /* Store the fill value as the last entry in cd_values[] \ |
136 | 0 | * Store byte by byte from least significant byte to most significant byte \ |
137 | 0 | * Plenty of space left for the fill value (from index 8 to 19) \ |
138 | 0 | * H5O_pline_encode will byte-swap each individual cd value, but we still \ |
139 | 0 | * need to swap the cd values as a whole if we are on a BE machine. Note \ |
140 | 0 | * that we need to make sure to put the data only in the lowest 4 bytes of \ |
141 | 0 | * each, if sizeof(unsigned) > 4. \ |
142 | 0 | */ \ |
143 | 0 | if (H5T_native_order_g == H5T_ORDER_LE) { \ |
144 | 0 | _fv_p = (char *)&(fill_val); \ |
145 | 0 | /* Copy 4 bytes at a time to each cd value */ \ |
146 | 0 | do { \ |
147 | 0 | if (_size_rem < 4) { \ |
148 | 0 | /* Amount left to copy is smaller than a cd_value, adjust copy \ |
149 | 0 | * size and initialize cd_value as it will not be fully \ |
150 | 0 | * overwritten */ \ |
151 | 0 | _copy_size = _size_rem; \ |
152 | 0 | _cd_value = (uint32_t)0; \ |
153 | 0 | } /* end if */ \ |
154 | 0 | \ |
155 | 0 | /* Copy the value */ \ |
156 | 0 | H5MM_memcpy(&_cd_value, _fv_p, _copy_size); \ |
157 | 0 | (cd_values)[_i] = (unsigned)_cd_value; \ |
158 | 0 | \ |
159 | 0 | /* Next field */ \ |
160 | 0 | _i++; \ |
161 | 0 | _fv_p += _copy_size; \ |
162 | 0 | _size_rem -= _copy_size; \ |
163 | 0 | } while (_size_rem); \ |
164 | 0 | } /* end if */ \ |
165 | 0 | else { \ |
166 | 0 | assert(H5T_native_order_g == H5T_ORDER_BE); \ |
167 | 0 | \ |
168 | 0 | /* Copy 4 bytes at a time to each cd value, but start at the end \ |
169 | 0 | * (highest address) of fill_val */ \ |
170 | 0 | _fv_p = ((char *)&(fill_val)) + sizeof(type) - MIN(4, _size_rem); \ |
171 | 0 | while (_size_rem >= 4) { \ |
172 | 0 | /* Copy the value */ \ |
173 | 0 | H5MM_memcpy(&_cd_value, _fv_p, _copy_size); \ |
174 | 0 | (cd_values)[_i] = (unsigned)_cd_value; \ |
175 | 0 | \ |
176 | 0 | /* Next field */ \ |
177 | 0 | _i++; \ |
178 | 0 | _size_rem -= 4; \ |
179 | 0 | if (_size_rem >= 4) \ |
180 | 0 | _fv_p -= 4; \ |
181 | 0 | else \ |
182 | 0 | _fv_p -= _size_rem; \ |
183 | 0 | } /* end while */ \ |
184 | 0 | \ |
185 | 0 | assert(_fv_p == (char *)&(fill_val)); \ |
186 | 0 | if (_size_rem) { \ |
187 | 0 | /* Amount left to copy is smaller than a cd_value, initialize \ |
188 | 0 | * _cd_value as it will not be fully overwritten and copy to the end \ |
189 | 0 | * of _cd value as it is BE. */ \ |
190 | 0 | _cd_value = (uint32_t)0; \ |
191 | 0 | H5MM_memcpy((char *)&_cd_value + 4 - _size_rem, _fv_p, _size_rem); \ |
192 | 0 | (cd_values)[_i] = (unsigned)_cd_value; \ |
193 | 0 | } /* end if */ \ |
194 | 0 | } /* end else */ \ |
195 | 0 | } |
196 | | |
197 | | /* Set the fill value parameter in cd_values[] for unsigned integer type */ |
198 | | #define H5Z_scaleoffset_set_filval_1(type, dcpl_plist, dt, cd_values, need_convert) \ |
199 | 0 | do { \ |
200 | 0 | type fill_val; \ |
201 | 0 | \ |
202 | 0 | /* Get dataset fill value */ \ |
203 | 0 | if (H5P_get_fill_value(dcpl_plist, dt, &fill_val) < 0) \ |
204 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value"); \ |
205 | 0 | \ |
206 | 0 | if (need_convert) \ |
207 | 0 | H5Z__scaleoffset_convert(&fill_val, 1, sizeof(type)); \ |
208 | 0 | \ |
209 | 0 | H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \ |
210 | 0 | } while (0) |
211 | | |
212 | | /* Set the fill value parameter in cd_values[] for signed integer type */ |
213 | | #define H5Z_scaleoffset_set_filval_2(type, dcpl_plist, dt, cd_values, need_convert) \ |
214 | 0 | do { \ |
215 | 0 | type fill_val; \ |
216 | 0 | \ |
217 | 0 | /* Get dataset fill value */ \ |
218 | 0 | if (H5P_get_fill_value(dcpl_plist, dt, &fill_val) < 0) \ |
219 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value"); \ |
220 | 0 | \ |
221 | 0 | if (need_convert) \ |
222 | 0 | H5Z__scaleoffset_convert(&fill_val, 1, sizeof(type)); \ |
223 | 0 | \ |
224 | 0 | H5Z_scaleoffset_save_filval(unsigned type, cd_values, fill_val) \ |
225 | 0 | } while (0) |
226 | | |
227 | | /* Set the fill value parameter in cd_values[] for character integer type */ |
228 | | #define H5Z_scaleoffset_set_filval_3(type, dcpl_plist, dt, cd_values, need_convert) \ |
229 | 0 | do { \ |
230 | 0 | type fill_val; \ |
231 | 0 | \ |
232 | 0 | /* Get dataset fill value */ \ |
233 | 0 | if (H5P_get_fill_value(dcpl_plist, dt, &fill_val) < 0) \ |
234 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value"); \ |
235 | 0 | \ |
236 | 0 | /* Store the fill value as the last entry in cd_values[] */ \ |
237 | 0 | (cd_values)[H5Z_SCALEOFFSET_PARM_FILVAL] = (unsigned)((unsigned char)fill_val); \ |
238 | 0 | } while (0) |
239 | | |
240 | | /* Set the fill value parameter in cd_values[] for floating-point type */ |
241 | | #define H5Z_scaleoffset_set_filval_4(type, dcpl_plist, dt, cd_values, need_convert) \ |
242 | 0 | do { \ |
243 | 0 | type fill_val; \ |
244 | 0 | \ |
245 | 0 | /* Get dataset fill value */ \ |
246 | 0 | if (H5P_get_fill_value(dcpl_plist, dt, &fill_val) < 0) \ |
247 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get fill value"); \ |
248 | 0 | \ |
249 | 0 | if (need_convert) \ |
250 | 0 | H5Z__scaleoffset_convert(&fill_val, 1, sizeof(type)); \ |
251 | 0 | \ |
252 | 0 | H5Z_scaleoffset_save_filval(type, cd_values, fill_val) \ |
253 | 0 | } while (0) |
254 | | |
255 | | /* Get the fill value for integer type */ |
256 | | #define H5Z_scaleoffset_get_filval_1(type, cd_values, fill_val) \ |
257 | 0 | do { \ |
258 | 0 | unsigned _i = H5Z_SCALEOFFSET_PARM_FILVAL; /* index into cd_values */ \ |
259 | 0 | uint32_t _cd_value; /* Current cd_value */ \ |
260 | 0 | char *_fv_p; /* Pointer to current byte in fill_val */ \ |
261 | 0 | size_t _copy_size = 4; /* # of bytes to copy this iteration */ \ |
262 | 0 | size_t _size_rem = sizeof(type); /* # of bytes left to copy to filval */ \ |
263 | 0 | \ |
264 | 0 | /* Retrieve the fill value from the last entry in cd_values[] \ |
265 | 0 | * Store byte by byte from least significant byte to most significant byte \ |
266 | 0 | * Plenty of space left for the fill value (from index 8 to 19) \ |
267 | 0 | * H5O_pline_encode will byte-swap each individual cd value, but we still \ |
268 | 0 | * need to swap the cd values as a whole if we are on a BE machine. Note \ |
269 | 0 | * that we need to make sure to put the data only in the lowest 4 bytes of \ |
270 | 0 | * each, if sizeof(unsigned) > 4. \ |
271 | 0 | */ \ |
272 | 0 | if (H5T_native_order_g == H5T_ORDER_LE) { \ |
273 | 0 | _fv_p = (char *)&(fill_val); \ |
274 | 0 | /* Copy 4 bytes at a time to each cd value */ \ |
275 | 0 | do { \ |
276 | 0 | if (_size_rem < 4) \ |
277 | 0 | /* Amount left to copy is smaller than a cd_value, adjust copy \ |
278 | 0 | * size and initialize cd_value as it will not be fully \ |
279 | 0 | * overwritten */ \ |
280 | 0 | _copy_size = _size_rem; \ |
281 | 0 | \ |
282 | 0 | /* Copy the value */ \ |
283 | 0 | _cd_value = (uint32_t)(cd_values)[_i]; \ |
284 | 0 | H5MM_memcpy(_fv_p, &_cd_value, _copy_size); \ |
285 | 0 | \ |
286 | 0 | /* Next field */ \ |
287 | 0 | _i++; \ |
288 | 0 | _fv_p += _copy_size; \ |
289 | 0 | _size_rem -= _copy_size; \ |
290 | 0 | } while (_size_rem); \ |
291 | 0 | } /* end if */ \ |
292 | 0 | else { \ |
293 | 0 | assert(H5T_native_order_g == H5T_ORDER_BE); \ |
294 | 0 | \ |
295 | 0 | /* Copy 4 bytes at a time to each cd value, but start at the end \ |
296 | 0 | * (highest address) of fill_val */ \ |
297 | 0 | _fv_p = ((char *)&(fill_val)) + sizeof(type) - MIN(4, _size_rem); \ |
298 | 0 | while (_size_rem >= 4) { \ |
299 | 0 | /* Copy the value */ \ |
300 | 0 | _cd_value = (uint32_t)(cd_values)[_i]; \ |
301 | 0 | H5MM_memcpy(_fv_p, &_cd_value, _copy_size); \ |
302 | 0 | \ |
303 | 0 | /* Next field */ \ |
304 | 0 | _i++; \ |
305 | 0 | _size_rem -= 4; \ |
306 | 0 | if (_size_rem >= 4) \ |
307 | 0 | _fv_p -= 4; \ |
308 | 0 | else \ |
309 | 0 | _fv_p -= _size_rem; \ |
310 | 0 | } /* end while */ \ |
311 | 0 | \ |
312 | 0 | assert(_fv_p == (char *)&(fill_val)); \ |
313 | 0 | if (_size_rem) { \ |
314 | 0 | /* Amount left to copy is smaller than a cd_value, initialize \ |
315 | 0 | * _cd_value as it will not be fully overwritten and copy to the end \ |
316 | 0 | * of _cd value as it is BE. */ \ |
317 | 0 | _cd_value = (uint32_t)(cd_values)[_i]; \ |
318 | 0 | H5MM_memcpy(_fv_p, (char *)&_cd_value + 4 - _size_rem, _size_rem); \ |
319 | 0 | } /* end if */ \ |
320 | 0 | } /* end else */ \ |
321 | 0 | } while (0) |
322 | | |
323 | | /* Get the fill value for floating-point type */ |
324 | | #define H5Z_scaleoffset_get_filval_2(type, cd_values, filval) \ |
325 | 0 | do { \ |
326 | 0 | if (sizeof(type) <= sizeof(long long)) \ |
327 | 0 | H5Z_scaleoffset_get_filval_1(type, cd_values, filval); \ |
328 | 0 | else \ |
329 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
330 | 0 | } while (0) |
331 | | |
332 | | /* Find maximum and minimum values of a buffer with fill value defined for integer type */ |
333 | | #define H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min) \ |
334 | 0 | { \ |
335 | 0 | i = 0; \ |
336 | 0 | while (i < d_nelmts && buf[i] == filval) \ |
337 | 0 | i++; \ |
338 | 0 | if (i < d_nelmts) \ |
339 | 0 | min = max = buf[i]; \ |
340 | 0 | for (; i < d_nelmts; i++) { \ |
341 | 0 | if (buf[i] == filval) \ |
342 | 0 | continue; /* ignore fill value */ \ |
343 | 0 | if (buf[i] > max) \ |
344 | 0 | max = buf[i]; \ |
345 | 0 | if (buf[i] < min) \ |
346 | 0 | min = buf[i]; \ |
347 | 0 | } \ |
348 | 0 | } |
349 | | |
350 | | /* Find maximum and minimum values of a buffer with fill value undefined */ |
351 | | #define H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min) \ |
352 | 0 | { \ |
353 | 0 | min = max = buf[0]; \ |
354 | 0 | for (i = 0; i < d_nelmts; i++) { \ |
355 | 0 | if (buf[i] > max) \ |
356 | 0 | max = buf[i]; \ |
357 | 0 | if (buf[i] < min) \ |
358 | 0 | min = buf[i]; \ |
359 | 0 | } \ |
360 | 0 | } |
361 | | |
362 | | /* Find maximum and minimum values of a buffer with fill value defined for floating-point type */ |
363 | | #define H5Z_scaleoffset_max_min_3(i, d_nelmts, buf, filval, max, min, D_val) \ |
364 | 0 | { \ |
365 | 0 | i = 0; \ |
366 | 0 | while (i < d_nelmts && fabs((double)(buf[i] - filval)) < pow(10.0, -D_val)) \ |
367 | 0 | i++; \ |
368 | 0 | if (i < d_nelmts) \ |
369 | 0 | min = max = buf[i]; \ |
370 | 0 | for (; i < d_nelmts; i++) { \ |
371 | 0 | if (fabs((double)(buf[i] - filval)) < pow(10.0, -D_val)) \ |
372 | 0 | continue; /* ignore fill value */ \ |
373 | 0 | if (buf[i] > max) \ |
374 | 0 | max = buf[i]; \ |
375 | 0 | if (buf[i] < min) \ |
376 | 0 | min = buf[i]; \ |
377 | 0 | } \ |
378 | 0 | } |
379 | | |
380 | | /* Find minimum value of a buffer with fill value defined for integer type */ |
381 | | #define H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min) \ |
382 | 0 | { \ |
383 | 0 | i = 0; \ |
384 | 0 | while (i < d_nelmts && buf[i] == filval) \ |
385 | 0 | i++; \ |
386 | 0 | if (i < d_nelmts) \ |
387 | 0 | min = buf[i]; \ |
388 | 0 | for (; i < d_nelmts; i++) { \ |
389 | 0 | if (buf[i] == filval) \ |
390 | 0 | continue; /* ignore fill value */ \ |
391 | 0 | if (buf[i] < min) \ |
392 | 0 | min = buf[i]; \ |
393 | 0 | } \ |
394 | 0 | } |
395 | | |
396 | | /* Find minimum value of a buffer with fill value undefined */ |
397 | | #define H5Z_scaleoffset_min_2(i, d_nelmts, buf, min) \ |
398 | 0 | { \ |
399 | 0 | min = buf[0]; \ |
400 | 0 | for (i = 0; i < d_nelmts; i++) \ |
401 | 0 | if (buf[i] < min) \ |
402 | 0 | min = buf[i]; \ |
403 | 0 | } |
404 | | |
405 | | /* Check and handle special situation for unsigned integer type */ |
406 | | #define H5Z_scaleoffset_check_1(type, max, min, minbits) \ |
407 | 0 | { \ |
408 | 0 | if (max - min > (type)(~(type)0 - 2)) { \ |
409 | 0 | *minbits = sizeof(type) * 8; \ |
410 | 0 | return; \ |
411 | 0 | } \ |
412 | 0 | } |
413 | | |
414 | | /* Check and handle special situation for signed integer type */ |
415 | | #define H5Z_scaleoffset_check_2(type, max, min, minbits) \ |
416 | 0 | { \ |
417 | 0 | if ((unsigned type)(max - min) > (unsigned type)(~(unsigned type)0 - 2)) { \ |
418 | 0 | *minbits = sizeof(type) * 8; \ |
419 | 0 | return; \ |
420 | 0 | } \ |
421 | 0 | } |
422 | | |
423 | | /* Check and handle special situation for floating-point type */ |
424 | | #define H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val) \ |
425 | 0 | { \ |
426 | 0 | if (sizeof(type) == sizeof(int)) { \ |
427 | 0 | if (round_fun(max * pow_fun((type)10, (type)D_val) - min * pow_fun((type)10, (type)D_val)) > \ |
428 | 0 | pow_fun((type)2, (type)(sizeof(int) * 8 - 1))) { \ |
429 | 0 | *minbits = sizeof(int) * 8; \ |
430 | 0 | goto done; \ |
431 | 0 | } \ |
432 | 0 | } \ |
433 | 0 | else if (sizeof(type) == sizeof(long)) { \ |
434 | 0 | if (round_fun(max * pow_fun((type)10, (type)D_val) - min * pow_fun((type)10, (type)D_val)) > \ |
435 | 0 | pow_fun((type)2, (type)(sizeof(long) * 8 - 1))) { \ |
436 | 0 | *minbits = sizeof(long) * 8; \ |
437 | 0 | goto done; \ |
438 | 0 | } \ |
439 | 0 | } \ |
440 | 0 | else if (sizeof(type) == sizeof(long long)) { \ |
441 | 0 | if (round_fun(max * pow_fun((type)10, (type)D_val) - min * pow_fun((type)10, (type)D_val)) > \ |
442 | 0 | pow_fun((type)2, (type)(sizeof(long long) * 8 - 1))) { \ |
443 | 0 | *minbits = sizeof(long long) * 8; \ |
444 | 0 | goto done; \ |
445 | 0 | } \ |
446 | 0 | } \ |
447 | 0 | else \ |
448 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
449 | 0 | } |
450 | | |
451 | | /* Precompress for unsigned integer type */ |
452 | | #define H5Z_scaleoffset_precompress_1(type, data, d_nelmts, filavail, cd_values, minbits, minval) \ |
453 | 0 | do { \ |
454 | 0 | type *buf = (type *)data, min = 0, max = 0, span, filval = 0; \ |
455 | 0 | unsigned i; \ |
456 | 0 | \ |
457 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
458 | 0 | H5Z_scaleoffset_get_filval_1(type, cd_values, filval); \ |
459 | 0 | if (*minbits == \ |
460 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \ |
461 | 0 | H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min) \ |
462 | 0 | H5Z_scaleoffset_check_1(type, max, min, minbits) span = (type)(max - min + 1); \ |
463 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)(span + 1)); \ |
464 | 0 | } \ |
465 | 0 | else /* minbits already set, only calculate min */ \ |
466 | 0 | H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min); \ |
467 | 0 | if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
468 | 0 | for (i = 0; i < d_nelmts; i++) \ |
469 | 0 | buf[i] = (type)((buf[i] == filval) ? (((type)1 << *minbits) - 1) : (buf[i] - min)); \ |
470 | 0 | } \ |
471 | 0 | else { /* fill value undefined */ \ |
472 | 0 | if (*minbits == \ |
473 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \ |
474 | 0 | H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min); \ |
475 | 0 | H5Z_scaleoffset_check_1(type, max, min, minbits); \ |
476 | 0 | span = (type)(max - min + 1); \ |
477 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)span); \ |
478 | 0 | } \ |
479 | 0 | else /* minbits already set, only calculate min */ \ |
480 | 0 | H5Z_scaleoffset_min_2(i, d_nelmts, buf, min); \ |
481 | 0 | if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
482 | 0 | for (i = 0; i < d_nelmts; i++) \ |
483 | 0 | buf[i] = (type)(buf[i] - min); \ |
484 | 0 | } \ |
485 | 0 | *minval = min; \ |
486 | 0 | } while (0) |
487 | | |
488 | | /* Precompress for signed integer type */ |
489 | | #define H5Z_scaleoffset_precompress_2(type, data, d_nelmts, filavail, cd_values, minbits, minval) \ |
490 | 0 | do { \ |
491 | 0 | type *buf = (type *)data, min = 0, max = 0, filval = 0; \ |
492 | 0 | unsigned type span; \ |
493 | 0 | unsigned i; \ |
494 | 0 | \ |
495 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
496 | 0 | H5Z_scaleoffset_get_filval_1(type, cd_values, filval); \ |
497 | 0 | if (*minbits == \ |
498 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \ |
499 | 0 | H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, min) \ |
500 | 0 | H5Z_scaleoffset_check_2(type, max, min, minbits) span = (unsigned type)(max - min + 1); \ |
501 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)(span + 1)); \ |
502 | 0 | } \ |
503 | 0 | else /* minbits already set, only calculate min */ \ |
504 | 0 | H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, min); \ |
505 | 0 | if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
506 | 0 | for (i = 0; i < d_nelmts; i++) \ |
507 | 0 | buf[i] = (type)((buf[i] == filval) ? (type)(((unsigned type)1 << *minbits) - 1) \ |
508 | 0 | : (buf[i] - min)); \ |
509 | 0 | } \ |
510 | 0 | else { /* fill value undefined */ \ |
511 | 0 | if (*minbits == \ |
512 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ \ |
513 | 0 | H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min) \ |
514 | 0 | H5Z_scaleoffset_check_2(type, max, min, minbits) span = (unsigned type)(max - min + 1); \ |
515 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)span); \ |
516 | 0 | } \ |
517 | 0 | else /* minbits already set, only calculate min */ \ |
518 | 0 | H5Z_scaleoffset_min_2( \ |
519 | 0 | i, d_nelmts, buf, \ |
520 | 0 | min) if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
521 | 0 | for (i = 0; i < d_nelmts; i++) buf[i] = (type)(buf[i] - min); \ |
522 | 0 | } \ |
523 | 0 | *minval = (unsigned long long)min; \ |
524 | 0 | } while (0) |
525 | | |
526 | | /* Modify values of data in precompression if fill value defined for floating-point type */ |
527 | | #define H5Z_scaleoffset_modify_1(i, type, pow_fun, abs_fun, lround_fun, llround_fun, buf, d_nelmts, filval, \ |
528 | | minbits, min, D_val) \ |
529 | 0 | { \ |
530 | 0 | if (sizeof(type) == sizeof(int)) \ |
531 | 0 | for (i = 0; i < d_nelmts; i++) { \ |
532 | 0 | if (abs_fun(buf[i] - filval) < pow_fun((type)10, (type)-D_val)) \ |
533 | 0 | *(int *)((void *)&buf[i]) = (int)(((unsigned int)1 << *minbits) - 1); \ |
534 | 0 | else \ |
535 | 0 | *(int *)((void *)&buf[i]) = (int)lround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
536 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
537 | 0 | } \ |
538 | 0 | else if (sizeof(type) == sizeof(long)) \ |
539 | 0 | for (i = 0; i < d_nelmts; i++) { \ |
540 | 0 | if (abs_fun(buf[i] - filval) < pow_fun((type)10, (type)-D_val)) \ |
541 | 0 | *(long *)((void *)&buf[i]) = (long)(((unsigned long)1 << *minbits) - 1); \ |
542 | 0 | else \ |
543 | 0 | *(long *)((void *)&buf[i]) = lround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
544 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
545 | 0 | } \ |
546 | 0 | else if (sizeof(type) == sizeof(long long)) \ |
547 | 0 | for (i = 0; i < d_nelmts; i++) { \ |
548 | 0 | if (abs_fun(buf[i] - filval) < pow_fun((type)10, (type)-D_val)) \ |
549 | 0 | *(long long *)((void *)&buf[i]) = (long long)(((unsigned long long)1 << *minbits) - 1); \ |
550 | 0 | else \ |
551 | 0 | *(long long *)((void *)&buf[i]) = llround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
552 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
553 | 0 | } \ |
554 | 0 | else \ |
555 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
556 | 0 | } |
557 | | |
558 | | /* Modify values of data in precompression if fill value undefined for floating-point type */ |
559 | | #define H5Z_scaleoffset_modify_2(i, type, pow_fun, lround_fun, llround_fun, buf, d_nelmts, min, D_val) \ |
560 | 0 | { \ |
561 | 0 | if (sizeof(type) == sizeof(int)) \ |
562 | 0 | for (i = 0; i < d_nelmts; i++) \ |
563 | 0 | *(int *)((void *)&buf[i]) = (int)lround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
564 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
565 | 0 | else if (sizeof(type) == sizeof(long)) \ |
566 | 0 | for (i = 0; i < d_nelmts; i++) \ |
567 | 0 | *(long *)((void *)&buf[i]) = lround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
568 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
569 | 0 | else if (sizeof(type) == sizeof(long long)) \ |
570 | 0 | for (i = 0; i < d_nelmts; i++) \ |
571 | 0 | *(long long *)((void *)&buf[i]) = llround_fun(buf[i] * pow_fun((type)10, (type)D_val) - \ |
572 | 0 | min * pow_fun((type)10, (type)D_val)); \ |
573 | 0 | else \ |
574 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
575 | 0 | } |
576 | | |
577 | | /* Save the minimum value for floating-point type */ |
578 | | #define H5Z_scaleoffset_save_min(i, type, minval, min) \ |
579 | 0 | { \ |
580 | 0 | if (sizeof(type) <= sizeof(long long)) \ |
581 | 0 | /* Save min value to corresponding position \ |
582 | 0 | * byte-order will be swapped as appropriate, but be sure to \ |
583 | 0 | * account for offset in BE if sizes differ \ |
584 | 0 | */ \ |
585 | 0 | if (H5T_native_order_g == H5T_ORDER_LE) \ |
586 | 0 | H5MM_memcpy(minval, &min, sizeof(type)); \ |
587 | 0 | else { \ |
588 | 0 | assert(H5T_native_order_g == H5T_ORDER_BE); \ |
589 | 0 | H5MM_memcpy(((char *)minval) + (sizeof(long long) - sizeof(type)), &min, sizeof(type)); \ |
590 | 0 | } /* end else */ \ |
591 | 0 | else \ |
592 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
593 | 0 | } |
594 | | |
595 | | /* Precompress for floating-point type using variable-minimum-bits method */ |
596 | | #define H5Z_scaleoffset_precompress_3(type, pow_fun, abs_fun, round_fun, lround_fun, llround_fun, data, \ |
597 | | d_nelmts, filavail, cd_values, minbits, minval, D_val) \ |
598 | 0 | do { \ |
599 | 0 | type *buf = (type *)data, min = 0, max = 0, filval = 0; \ |
600 | 0 | unsigned long long span; \ |
601 | 0 | unsigned i; \ |
602 | 0 | \ |
603 | 0 | *minval = 0; \ |
604 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
605 | 0 | H5Z_scaleoffset_get_filval_2(type, cd_values, filval); \ |
606 | 0 | H5Z_scaleoffset_max_min_3(i, d_nelmts, buf, filval, max, min, D_val); \ |
607 | 0 | H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val); \ |
608 | 0 | span = (unsigned long long)(llround_fun(max * pow_fun((type)10, (type)D_val) - \ |
609 | 0 | min * pow_fun((type)10, (type)D_val)) + \ |
610 | 0 | 1); \ |
611 | 0 | *minbits = H5Z__scaleoffset_log2(span + 1); \ |
612 | 0 | if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
613 | 0 | H5Z_scaleoffset_modify_1(i, type, pow_fun, abs_fun, lround_fun, llround_fun, buf, d_nelmts, \ |
614 | 0 | filval, minbits, min, D_val); \ |
615 | 0 | } \ |
616 | 0 | else { /* fill value undefined */ \ |
617 | 0 | H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, min); \ |
618 | 0 | H5Z_scaleoffset_check_3(i, type, pow_fun, round_fun, max, min, minbits, D_val); \ |
619 | 0 | span = (unsigned long long)(llround_fun(max * pow_fun((type)10, (type)D_val) - \ |
620 | 0 | min * pow_fun((type)10, (type)D_val)) + \ |
621 | 0 | 1); \ |
622 | 0 | *minbits = H5Z__scaleoffset_log2(span); \ |
623 | 0 | if (*minbits != sizeof(type) * 8) /* change values if minbits != full precision */ \ |
624 | 0 | H5Z_scaleoffset_modify_2(i, type, pow_fun, lround_fun, llround_fun, buf, d_nelmts, min, \ |
625 | 0 | D_val); \ |
626 | 0 | } \ |
627 | 0 | H5Z_scaleoffset_save_min(i, type, minval, min); \ |
628 | 0 | } while (0) |
629 | | |
630 | | /* Postdecompress for unsigned integer type */ |
631 | | #define H5Z_scaleoffset_postdecompress_1(type, data, d_nelmts, filavail, cd_values, minbits, minval) \ |
632 | 0 | do { \ |
633 | 0 | type *buf = (type *)data, filval = 0; \ |
634 | 0 | unsigned i; \ |
635 | 0 | \ |
636 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
637 | 0 | H5Z_scaleoffset_get_filval_1(type, cd_values, filval); \ |
638 | 0 | for (i = 0; i < d_nelmts; i++) \ |
639 | 0 | buf[i] = (type)((buf[i] == (((type)1 << minbits) - 1)) ? filval : (buf[i] + minval)); \ |
640 | 0 | } \ |
641 | 0 | else /* fill value undefined */ \ |
642 | 0 | for (i = 0; i < d_nelmts; i++) \ |
643 | 0 | buf[i] = (type)(buf[i] + (type)(minval)); \ |
644 | 0 | } while (0) |
645 | | |
646 | | /* Postdecompress for signed integer type */ |
647 | | #define H5Z_scaleoffset_postdecompress_2(type, data, d_nelmts, filavail, cd_values, minbits, minval) \ |
648 | 0 | do { \ |
649 | 0 | type *buf = (type *)data, filval = 0; \ |
650 | 0 | unsigned i; \ |
651 | 0 | \ |
652 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
653 | 0 | H5Z_scaleoffset_get_filval_1(type, cd_values, filval); \ |
654 | 0 | for (i = 0; i < d_nelmts; i++) \ |
655 | 0 | buf[i] = (type)(((unsigned type)buf[i] == (((unsigned type)1 << minbits) - 1)) \ |
656 | 0 | ? filval \ |
657 | 0 | : (buf[i] + minval)); \ |
658 | 0 | } \ |
659 | 0 | else /* fill value undefined */ \ |
660 | 0 | for (i = 0; i < d_nelmts; i++) \ |
661 | 0 | buf[i] = (type)(buf[i] + (type)(minval)); \ |
662 | 0 | } while (0) |
663 | | |
664 | | /* Retrieve minimum value of floating-point type */ |
665 | | #define H5Z_scaleoffset_get_min(type, minval, min) \ |
666 | 0 | do { \ |
667 | 0 | if (sizeof(type) <= sizeof(long long)) \ |
668 | 0 | /* retrieve min value from corresponding position \ |
669 | 0 | * byte-order has already been swapped as appropriate, but be sure to \ |
670 | 0 | * account for offset in BE if sizes differ \ |
671 | 0 | */ \ |
672 | 0 | if (H5T_native_order_g == H5T_ORDER_LE) \ |
673 | 0 | H5MM_memcpy(&min, &minval, sizeof(type)); \ |
674 | 0 | else { \ |
675 | 0 | assert(H5T_native_order_g == H5T_ORDER_BE); \ |
676 | 0 | H5MM_memcpy(&min, ((char *)&minval) + (sizeof(long long) - sizeof(type)), sizeof(type)); \ |
677 | 0 | } /* end else */ \ |
678 | 0 | else \ |
679 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
680 | 0 | } while (0) |
681 | | |
682 | | /* Modify values of data in postdecompression if fill value defined for floating-point type */ |
683 | | #define H5Z_scaleoffset_modify_3(i, type, pow_fun, buf, d_nelmts, filval, minbits, min, D_val) \ |
684 | 0 | do { \ |
685 | 0 | if (sizeof(type) == sizeof(int)) \ |
686 | 0 | for (i = 0; i < d_nelmts; i++) \ |
687 | 0 | buf[i] = \ |
688 | 0 | (type)((*(int *)((void *)&buf[i]) == (int)(((unsigned int)1 << minbits) - 1)) \ |
689 | 0 | ? filval \ |
690 | 0 | : (type)(*(int *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + min); \ |
691 | 0 | else if (sizeof(type) == sizeof(long)) \ |
692 | 0 | for (i = 0; i < d_nelmts; i++) \ |
693 | 0 | buf[i] = \ |
694 | 0 | (type)((*(long *)((void *)&buf[i]) == (long)(((unsigned long)1 << minbits) - 1)) \ |
695 | 0 | ? filval \ |
696 | 0 | : (type)(*(long *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + min); \ |
697 | 0 | else if (sizeof(type) == sizeof(long long)) \ |
698 | 0 | for (i = 0; i < d_nelmts; i++) \ |
699 | 0 | buf[i] = \ |
700 | 0 | (type)((*(long long *)((void *)&buf[i]) == \ |
701 | 0 | (long long)(((unsigned long long)1 << minbits) - 1)) \ |
702 | 0 | ? filval \ |
703 | 0 | : (type)(*(long long *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + \ |
704 | 0 | min); \ |
705 | 0 | else \ |
706 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
707 | 0 | } while (0) |
708 | | |
709 | | /* Modify values of data in postdecompression if fill value undefined for floating-point type */ |
710 | | #define H5Z_scaleoffset_modify_4(i, type, pow_fun, buf, d_nelmts, min, D_val) \ |
711 | 0 | do { \ |
712 | 0 | if (sizeof(type) == sizeof(int)) \ |
713 | 0 | for (i = 0; i < d_nelmts; i++) \ |
714 | 0 | buf[i] = ((type)(*(int *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + min); \ |
715 | 0 | else if (sizeof(type) == sizeof(long)) \ |
716 | 0 | for (i = 0; i < d_nelmts; i++) \ |
717 | 0 | buf[i] = ((type)(*(long *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + min); \ |
718 | 0 | else if (sizeof(type) == sizeof(long long)) \ |
719 | 0 | for (i = 0; i < d_nelmts; i++) \ |
720 | 0 | buf[i] = ((type)(*(long long *)((void *)&buf[i])) / pow_fun((type)10, (type)D_val) + min); \ |
721 | 0 | else \ |
722 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot find matched integer datatype"); \ |
723 | 0 | } while (0) |
724 | | |
725 | | /* Postdecompress for floating-point type using variable-minimum-bits method */ |
726 | | #define H5Z_scaleoffset_postdecompress_3(type, pow_fun, data, d_nelmts, filavail, cd_values, minbits, \ |
727 | | minval, D_val) \ |
728 | 0 | do { \ |
729 | 0 | type *buf = (type *)data, filval = 0, min = 0; \ |
730 | 0 | unsigned i; \ |
731 | 0 | \ |
732 | 0 | H5Z_scaleoffset_get_min(type, minval, min); \ |
733 | 0 | \ |
734 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ \ |
735 | 0 | H5Z_scaleoffset_get_filval_2(type, cd_values, filval); \ |
736 | 0 | H5Z_scaleoffset_modify_3(i, type, pow_fun, buf, d_nelmts, filval, minbits, min, D_val); \ |
737 | 0 | } \ |
738 | 0 | else /* fill value undefined */ \ |
739 | 0 | H5Z_scaleoffset_modify_4(i, type, pow_fun, buf, d_nelmts, min, D_val); \ |
740 | 0 | } while (0) |
741 | | |
742 | | /*------------------------------------------------------------------------- |
743 | | * Function: H5Z__can_apply_scaleoffset |
744 | | * |
745 | | * Purpose: Check the parameters for scaleoffset compression for |
746 | | * validity and whether they fit a particular dataset. |
747 | | * |
748 | | * Return: Success: Non-negative |
749 | | * Failure: Negative |
750 | | * |
751 | | *------------------------------------------------------------------------- |
752 | | */ |
753 | | static htri_t |
754 | | H5Z__can_apply_scaleoffset(hid_t H5_ATTR_UNUSED dcpl_id, hid_t type_id, hid_t H5_ATTR_UNUSED space_id) |
755 | 0 | { |
756 | 0 | const H5T_t *type; /* Datatype */ |
757 | 0 | H5T_class_t dtype_class; /* Datatype's class */ |
758 | 0 | H5T_order_t dtype_order; /* Datatype's endianness order */ |
759 | 0 | htri_t ret_value = true; /* Return value */ |
760 | |
|
761 | 0 | FUNC_ENTER_PACKAGE |
762 | | |
763 | | /* Get datatype */ |
764 | 0 | if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) |
765 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); |
766 | | |
767 | | /* Get datatype's class, for checking the "datatype class" */ |
768 | 0 | if ((dtype_class = H5T_get_class(type, true)) == H5T_NO_CLASS) |
769 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class"); |
770 | | |
771 | | /* Get datatype's size, for checking the "datatype size" */ |
772 | 0 | if (H5T_get_size(type) == 0) |
773 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size"); |
774 | | |
775 | 0 | if (dtype_class == H5T_INTEGER || dtype_class == H5T_FLOAT) { |
776 | | /* Get datatype's endianness order */ |
777 | 0 | if ((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR) |
778 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "can't retrieve datatype endianness order"); |
779 | | |
780 | | /* Range check datatype's endianness order */ |
781 | 0 | if (dtype_order != H5T_ORDER_LE && dtype_order != H5T_ORDER_BE) |
782 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, false, "bad datatype endianness order"); |
783 | 0 | } |
784 | 0 | else |
785 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, false, "datatype class not supported by scaleoffset"); |
786 | | |
787 | 0 | done: |
788 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
789 | 0 | } /* end H5Z__can_apply_scaleoffset() */ |
790 | | |
791 | | /*------------------------------------------------------------------------- |
792 | | * Function: H5Z__scaleoffset_get_type |
793 | | * |
794 | | * Purpose: Get the specific integer type based on datatype size and sign |
795 | | * or floating-point type based on size |
796 | | * |
797 | | * Return: Success: id number of integer type |
798 | | * Failure: 0 |
799 | | * |
800 | | *------------------------------------------------------------------------- |
801 | | */ |
802 | | static enum H5Z_scaleoffset_t |
803 | | H5Z__scaleoffset_get_type(unsigned dtype_class, unsigned dtype_size, unsigned dtype_sign) |
804 | 0 | { |
805 | 0 | enum H5Z_scaleoffset_t type = t_bad; /* integer type */ |
806 | 0 | enum H5Z_scaleoffset_t ret_value = t_bad; /* Return value */ |
807 | |
|
808 | 0 | FUNC_ENTER_PACKAGE |
809 | |
|
810 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_INTEGER) { |
811 | 0 | if (dtype_sign == H5Z_SCALEOFFSET_SGN_NONE) { /* unsigned integer */ |
812 | 0 | if (dtype_size == sizeof(unsigned char)) |
813 | 0 | type = t_uchar; |
814 | 0 | else if (dtype_size == sizeof(unsigned short)) |
815 | 0 | type = t_ushort; |
816 | 0 | else if (dtype_size == sizeof(unsigned int)) |
817 | 0 | type = t_uint; |
818 | 0 | else if (dtype_size == sizeof(unsigned long)) |
819 | 0 | type = t_ulong; |
820 | | #if H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG |
821 | | else if (dtype_size == sizeof(unsigned long long)) |
822 | | type = t_ulong_long; |
823 | | #endif /* H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG */ |
824 | 0 | else |
825 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory datatype"); |
826 | 0 | } |
827 | | |
828 | 0 | if (dtype_sign == H5Z_SCALEOFFSET_SGN_2) { /* signed integer */ |
829 | 0 | if (dtype_size == sizeof(signed char)) |
830 | 0 | type = t_schar; |
831 | 0 | else if (dtype_size == sizeof(short)) |
832 | 0 | type = t_short; |
833 | 0 | else if (dtype_size == sizeof(int)) |
834 | 0 | type = t_int; |
835 | 0 | else if (dtype_size == sizeof(long)) |
836 | 0 | type = t_long; |
837 | | #if H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG |
838 | | else if (dtype_size == sizeof(long long)) |
839 | | type = t_long_long; |
840 | | #endif /* H5_SIZEOF_LONG != H5_SIZEOF_LONG_LONG */ |
841 | 0 | else |
842 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory datatype"); |
843 | 0 | } |
844 | 0 | } |
845 | | |
846 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_FLOAT) { |
847 | 0 | if (dtype_size == sizeof(float)) |
848 | 0 | type = t_float; |
849 | 0 | else if (dtype_size == sizeof(double)) |
850 | 0 | type = t_double; |
851 | 0 | else |
852 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, t_bad, "cannot find matched memory datatype"); |
853 | 0 | } |
854 | | |
855 | | /* Set return value */ |
856 | 0 | ret_value = type; |
857 | |
|
858 | 0 | done: |
859 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
860 | 0 | } |
861 | | |
862 | | /*------------------------------------------------------------------------- |
863 | | * Function: H5Z__scaleoffset_set_parms_fillval |
864 | | * |
865 | | * Purpose: Get the fill value of the dataset and store in cd_values[] |
866 | | * |
867 | | * Return: Success: Non-negative |
868 | | * Failure: Negative |
869 | | * |
870 | | *------------------------------------------------------------------------- |
871 | | */ |
872 | | static herr_t |
873 | | H5Z__scaleoffset_set_parms_fillval(H5P_genplist_t *dcpl_plist, H5T_t *type, enum H5Z_scaleoffset_t scale_type, |
874 | | unsigned cd_values[], int need_convert) |
875 | 0 | { |
876 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
877 | |
|
878 | 0 | FUNC_ENTER_PACKAGE |
879 | |
|
880 | 0 | if (scale_type == t_uchar) |
881 | 0 | H5Z_scaleoffset_set_filval_3(unsigned char, dcpl_plist, type, cd_values, need_convert); |
882 | 0 | else if (scale_type == t_ushort) |
883 | 0 | H5Z_scaleoffset_set_filval_1(unsigned short, dcpl_plist, type, cd_values, need_convert); |
884 | 0 | else if (scale_type == t_uint) |
885 | 0 | H5Z_scaleoffset_set_filval_1(unsigned int, dcpl_plist, type, cd_values, need_convert); |
886 | 0 | else if (scale_type == t_ulong) |
887 | 0 | H5Z_scaleoffset_set_filval_1(unsigned long, dcpl_plist, type, cd_values, need_convert); |
888 | 0 | else if (scale_type == t_ulong_long) |
889 | 0 | H5Z_scaleoffset_set_filval_1(unsigned long long, dcpl_plist, type, cd_values, need_convert); |
890 | 0 | else if (scale_type == t_schar) |
891 | 0 | H5Z_scaleoffset_set_filval_3(signed char, dcpl_plist, type, cd_values, need_convertd); |
892 | 0 | else if (scale_type == t_short) |
893 | 0 | H5Z_scaleoffset_set_filval_2(short, dcpl_plist, type, cd_values, need_convert); |
894 | 0 | else if (scale_type == t_int) |
895 | 0 | H5Z_scaleoffset_set_filval_2(int, dcpl_plist, type, cd_values, need_convert); |
896 | 0 | else if (scale_type == t_long) |
897 | 0 | H5Z_scaleoffset_set_filval_2(long, dcpl_plist, type, cd_values, need_convert); |
898 | 0 | else if (scale_type == t_long_long) |
899 | 0 | H5Z_scaleoffset_set_filval_2(long long, dcpl_plist, type, cd_values, need_convert); |
900 | 0 | else if (scale_type == t_float) |
901 | 0 | H5Z_scaleoffset_set_filval_4(float, dcpl_plist, type, cd_values, need_convert); |
902 | 0 | else if (scale_type == t_double) |
903 | 0 | H5Z_scaleoffset_set_filval_4(double, dcpl_plist, type, cd_values, need_convert); |
904 | | |
905 | 0 | done: |
906 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
907 | 0 | } /* end H5Z__scaleoffset_set_parms_fillval() */ |
908 | | |
909 | | /*------------------------------------------------------------------------- |
910 | | * Function: H5Z__set_local_scaleoffset |
911 | | * |
912 | | * Purpose: Set the "local" dataset parameters for scaleoffset |
913 | | * compression. |
914 | | * |
915 | | * Return: Success: Non-negative |
916 | | * Failure: Negative |
917 | | * |
918 | | *------------------------------------------------------------------------- |
919 | | */ |
920 | | static herr_t |
921 | | H5Z__set_local_scaleoffset(hid_t dcpl_id, hid_t type_id, hid_t space_id) |
922 | 0 | { |
923 | 0 | H5P_genplist_t *dcpl_plist; /* Property list pointer */ |
924 | 0 | H5T_t *type; /* Datatype */ |
925 | 0 | const H5S_t *ds; /* Dataspace */ |
926 | 0 | unsigned flags; /* Filter flags */ |
927 | 0 | size_t cd_nelmts = H5Z_SCALEOFFSET_USER_NPARMS; /* Number of filter parameters */ |
928 | 0 | unsigned cd_values[H5Z_SCALEOFFSET_TOTAL_NPARMS]; /* Filter parameters */ |
929 | 0 | hssize_t npoints; /* Number of points in the dataspace */ |
930 | 0 | H5T_class_t dtype_class; /* Datatype's class */ |
931 | 0 | H5T_order_t dtype_order; /* Datatype's endianness order */ |
932 | 0 | size_t dtype_size; /* Datatype's size (in bytes) */ |
933 | 0 | H5T_sign_t dtype_sign; /* Datatype's sign */ |
934 | 0 | enum H5Z_scaleoffset_t scale_type; /* Specific datatype */ |
935 | 0 | H5D_fill_value_t status; /* Status of fill value in property list */ |
936 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
937 | |
|
938 | 0 | FUNC_ENTER_PACKAGE |
939 | | |
940 | | /* Get the plist structure */ |
941 | 0 | if (NULL == (dcpl_plist = H5P_object_verify(dcpl_id, H5P_DATASET_CREATE))) |
942 | 0 | HGOTO_ERROR(H5E_ID, H5E_BADID, FAIL, "can't find object for ID"); |
943 | | |
944 | | /* Get datatype */ |
945 | 0 | if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) |
946 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); |
947 | | |
948 | | /* Initialize the parameters to a known state */ |
949 | 0 | memset(cd_values, 0, sizeof(cd_values)); |
950 | | |
951 | | /* Get the filter's current parameters */ |
952 | 0 | if (H5P_get_filter_by_id(dcpl_plist, H5Z_FILTER_SCALEOFFSET, &flags, &cd_nelmts, cd_values, (size_t)0, |
953 | 0 | NULL, NULL) < 0) |
954 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get scaleoffset parameters"); |
955 | | |
956 | | /* Get dataspace */ |
957 | 0 | if (NULL == (ds = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) |
958 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace"); |
959 | | |
960 | | /* Get total number of elements in the chunk */ |
961 | 0 | if ((npoints = H5S_GET_EXTENT_NPOINTS(ds)) < 0) |
962 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get number of points in the dataspace"); |
963 | | |
964 | | /* Set "local" parameter for this dataset's number of elements */ |
965 | 0 | H5_CHECKED_ASSIGN(cd_values[H5Z_SCALEOFFSET_PARM_NELMTS], unsigned, npoints, hssize_t); |
966 | | |
967 | | /* Get datatype's class */ |
968 | 0 | if ((dtype_class = H5T_get_class(type, true)) == H5T_NO_CLASS) |
969 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class"); |
970 | | |
971 | | /* Set "local" parameter for datatype's class */ |
972 | 0 | switch (dtype_class) { |
973 | 0 | case H5T_INTEGER: |
974 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_CLASS] = H5Z_SCALEOFFSET_CLS_INTEGER; |
975 | 0 | break; |
976 | | |
977 | 0 | case H5T_FLOAT: |
978 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_CLASS] = H5Z_SCALEOFFSET_CLS_FLOAT; |
979 | 0 | break; |
980 | | |
981 | 0 | case H5T_NO_CLASS: |
982 | 0 | case H5T_TIME: |
983 | 0 | case H5T_STRING: |
984 | 0 | case H5T_BITFIELD: |
985 | 0 | case H5T_OPAQUE: |
986 | 0 | case H5T_COMPOUND: |
987 | 0 | case H5T_REFERENCE: |
988 | 0 | case H5T_ENUM: |
989 | 0 | case H5T_VLEN: |
990 | 0 | case H5T_ARRAY: |
991 | 0 | case H5T_NCLASSES: |
992 | 0 | default: |
993 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "datatype class not supported by scaleoffset"); |
994 | 0 | } /* end switch */ |
995 | | |
996 | | /* Get datatype's size */ |
997 | 0 | if ((dtype_size = H5T_get_size(type)) == 0) |
998 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size"); |
999 | | |
1000 | | /* Set "local" parameter for datatype size */ |
1001 | 0 | H5_CHECK_OVERFLOW(dtype_size, size_t, unsigned); |
1002 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_SIZE] = (unsigned)dtype_size; |
1003 | |
|
1004 | 0 | if (dtype_class == H5T_INTEGER) { |
1005 | | /* Get datatype's sign */ |
1006 | 0 | if ((dtype_sign = H5T_get_sign(type)) == H5T_SGN_ERROR) |
1007 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype sign"); |
1008 | | |
1009 | | /* Set "local" parameter for integer datatype sign */ |
1010 | 0 | switch (dtype_sign) { |
1011 | 0 | case H5T_SGN_NONE: |
1012 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_SIGN] = H5Z_SCALEOFFSET_SGN_NONE; |
1013 | 0 | break; |
1014 | | |
1015 | 0 | case H5T_SGN_2: |
1016 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_SIGN] = H5Z_SCALEOFFSET_SGN_2; |
1017 | 0 | break; |
1018 | | |
1019 | 0 | case H5T_SGN_ERROR: |
1020 | 0 | case H5T_NSGN: |
1021 | 0 | default: |
1022 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad integer sign"); |
1023 | 0 | } /* end switch */ |
1024 | 0 | } /* end if */ |
1025 | | |
1026 | | /* Get datatype's endianness order */ |
1027 | 0 | if ((dtype_order = H5T_get_order(type)) == H5T_ORDER_ERROR) |
1028 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order"); |
1029 | | |
1030 | | /* Set "local" parameter for datatype endianness */ |
1031 | 0 | switch (dtype_order) { |
1032 | 0 | case H5T_ORDER_LE: /* Little-endian byte order */ |
1033 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_ORDER] = H5Z_SCALEOFFSET_ORDER_LE; |
1034 | 0 | break; |
1035 | | |
1036 | 0 | case H5T_ORDER_BE: /* Big-endian byte order */ |
1037 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_ORDER] = H5Z_SCALEOFFSET_ORDER_BE; |
1038 | 0 | break; |
1039 | | |
1040 | 0 | case H5T_ORDER_ERROR: |
1041 | 0 | case H5T_ORDER_VAX: |
1042 | 0 | case H5T_ORDER_MIXED: |
1043 | 0 | case H5T_ORDER_NONE: |
1044 | 0 | default: |
1045 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order"); |
1046 | 0 | } /* end switch */ |
1047 | | |
1048 | | /* Check whether fill value is defined for dataset */ |
1049 | 0 | if (H5P_fill_value_defined(dcpl_plist, &status) < 0) |
1050 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to determine if fill value is defined"); |
1051 | | |
1052 | | /* Set local parameter for availability of fill value */ |
1053 | 0 | if (status == H5D_FILL_VALUE_UNDEFINED) |
1054 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL] = H5Z_SCALEOFFSET_FILL_UNDEFINED; |
1055 | 0 | else { |
1056 | 0 | int need_convert = false; /* Flag indicating conversion of byte order */ |
1057 | |
|
1058 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL] = H5Z_SCALEOFFSET_FILL_DEFINED; |
1059 | | |
1060 | | /* Check if memory byte order matches dataset datatype byte order */ |
1061 | 0 | if (H5T_native_order_g != dtype_order) |
1062 | 0 | need_convert = true; |
1063 | | |
1064 | | /* Before getting fill value, get its type */ |
1065 | 0 | if ((scale_type = H5Z__scaleoffset_get_type(cd_values[H5Z_SCALEOFFSET_PARM_CLASS], |
1066 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_SIZE], |
1067 | 0 | cd_values[H5Z_SCALEOFFSET_PARM_SIGN])) == 0) |
1068 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "cannot use C integer datatype for cast"); |
1069 | | |
1070 | | /* Get dataset fill value and store in cd_values[] */ |
1071 | 0 | if (H5Z__scaleoffset_set_parms_fillval(dcpl_plist, type, scale_type, cd_values, need_convert) < 0) |
1072 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "unable to set fill value"); |
1073 | 0 | } /* end else */ |
1074 | | |
1075 | | /* Modify the filter's parameters for this dataset */ |
1076 | 0 | if (H5P_modify_filter(dcpl_plist, H5Z_FILTER_SCALEOFFSET, flags, (size_t)H5Z_SCALEOFFSET_TOTAL_NPARMS, |
1077 | 0 | cd_values) < 0) |
1078 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local scaleoffset parameters"); |
1079 | | |
1080 | 0 | done: |
1081 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1082 | 0 | } /* end H5Z__set_local_scaleoffset() */ |
1083 | | |
1084 | | /*------------------------------------------------------------------------- |
1085 | | * Function: H5Z__filter_scaleoffset |
1086 | | * |
1087 | | * Purpose: Implement an I/O filter for storing packed integer |
1088 | | * data using scale and offset method. |
1089 | | * |
1090 | | * Return: Success: Size of buffer filtered |
1091 | | * Failure: 0 |
1092 | | * |
1093 | | *------------------------------------------------------------------------- |
1094 | | */ |
1095 | | static size_t |
1096 | | H5Z__filter_scaleoffset(unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, |
1097 | | size_t *buf_size, void **buf) |
1098 | 0 | { |
1099 | 0 | size_t ret_value = 0; /* return value */ |
1100 | 0 | size_t size_out = 0; /* size of output buffer */ |
1101 | 0 | unsigned d_nelmts = 0; /* number of data elements in the chunk */ |
1102 | 0 | unsigned dtype_class; /* datatype class */ |
1103 | 0 | unsigned dtype_sign; /* integer datatype sign */ |
1104 | 0 | unsigned filavail; /* flag indicating if fill value is defined or not */ |
1105 | 0 | H5Z_SO_scale_type_t scale_type = H5Z_SO_FLOAT_DSCALE; /* scale type */ |
1106 | 0 | int scale_factor = 0; /* scale factor */ |
1107 | 0 | double D_val = 0.0; /* decimal scale factor */ |
1108 | 0 | uint32_t minbits = 0; /* minimum number of bits to store values */ |
1109 | 0 | unsigned long long minval = 0; /* minimum value of input buffer */ |
1110 | 0 | enum H5Z_scaleoffset_t type; /* memory type corresponding to dataset datatype */ |
1111 | 0 | int need_convert = false; /* flag indicating conversion of byte order */ |
1112 | 0 | unsigned char *outbuf = NULL; /* pointer to new output buffer */ |
1113 | 0 | unsigned buf_offset = 21; /* buffer offset because of parameters stored in file */ |
1114 | 0 | unsigned i; /* index */ |
1115 | 0 | parms_atomic p; /* parameters needed for compress/decompress functions */ |
1116 | |
|
1117 | 0 | FUNC_ENTER_PACKAGE |
1118 | | |
1119 | | /* check arguments */ |
1120 | 0 | if (cd_nelmts != H5Z_SCALEOFFSET_TOTAL_NPARMS) |
1121 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scaleoffset number of parameters"); |
1122 | | |
1123 | | /* Check if memory byte order matches dataset datatype byte order */ |
1124 | 0 | switch (H5T_native_order_g) { |
1125 | 0 | case H5T_ORDER_LE: /* memory is little-endian byte order */ |
1126 | 0 | if (cd_values[H5Z_SCALEOFFSET_PARM_ORDER] == H5Z_SCALEOFFSET_ORDER_BE) |
1127 | 0 | need_convert = true; |
1128 | 0 | break; |
1129 | | |
1130 | 0 | case H5T_ORDER_BE: /* memory is big-endian byte order */ |
1131 | 0 | if (cd_values[H5Z_SCALEOFFSET_PARM_ORDER] == H5Z_SCALEOFFSET_ORDER_LE) |
1132 | 0 | need_convert = true; |
1133 | 0 | break; |
1134 | | |
1135 | 0 | case H5T_ORDER_ERROR: |
1136 | 0 | case H5T_ORDER_VAX: |
1137 | 0 | case H5T_ORDER_MIXED: |
1138 | 0 | case H5T_ORDER_NONE: |
1139 | 0 | default: |
1140 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "bad H5T_NATIVE_INT endianness order"); |
1141 | 0 | } /* end switch */ |
1142 | | |
1143 | | /* copy filter parameters to local variables */ |
1144 | 0 | d_nelmts = cd_values[H5Z_SCALEOFFSET_PARM_NELMTS]; |
1145 | 0 | dtype_class = cd_values[H5Z_SCALEOFFSET_PARM_CLASS]; |
1146 | 0 | dtype_sign = cd_values[H5Z_SCALEOFFSET_PARM_SIGN]; |
1147 | 0 | filavail = cd_values[H5Z_SCALEOFFSET_PARM_FILAVAIL]; |
1148 | 0 | scale_factor = (int)cd_values[H5Z_SCALEOFFSET_PARM_SCALEFACTOR]; |
1149 | 0 | scale_type = (H5Z_SO_scale_type_t)cd_values[H5Z_SCALEOFFSET_PARM_SCALETYPE]; |
1150 | | |
1151 | | /* check and assign proper values set by user to related parameters |
1152 | | * scale type can be H5Z_SO_FLOAT_DSCALE (0), H5Z_SO_FLOAT_ESCALE (1) or H5Z_SO_INT (other) |
1153 | | * H5Z_SO_FLOAT_DSCALE : floating-point type, variable-minimum-bits method, |
1154 | | * scale factor is decimal scale factor |
1155 | | * H5Z_SO_FLOAT_ESCALE : floating-point type, fixed-minimum-bits method, |
1156 | | * scale factor is the fixed minimum number of bits |
1157 | | * H5Z_SO_INT : integer type, scale_factor is minimum number of bits |
1158 | | */ |
1159 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_FLOAT) { /* floating-point type */ |
1160 | 0 | if (scale_type != H5Z_SO_FLOAT_DSCALE && scale_type != H5Z_SO_FLOAT_ESCALE) |
1161 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scale type"); |
1162 | 0 | } |
1163 | | |
1164 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_INTEGER) { /* integer type */ |
1165 | 0 | if (scale_type != H5Z_SO_INT) |
1166 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid scale type"); |
1167 | | |
1168 | | /* if scale_factor is less than 0 for integer, library will reset it to 0 |
1169 | | * in this case, library will calculate the minimum-bits |
1170 | | */ |
1171 | 0 | if (scale_factor < 0) |
1172 | 0 | scale_factor = 0; |
1173 | 0 | } |
1174 | | |
1175 | | /* fixed-minimum-bits method is not implemented and is forbidden */ |
1176 | 0 | if (scale_type == H5Z_SO_FLOAT_ESCALE) |
1177 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "E-scaling method not supported"); |
1178 | | |
1179 | 0 | if (scale_type == H5Z_SO_FLOAT_DSCALE) { /* floating-point type, variable-minimum-bits */ |
1180 | 0 | D_val = (double)scale_factor; |
1181 | 0 | } |
1182 | 0 | else { /* integer type, or floating-point type with fixed-minimum-bits method */ |
1183 | 0 | if (scale_factor > (int)(cd_values[H5Z_SCALEOFFSET_PARM_SIZE] * 8)) |
1184 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "minimum number of bits exceeds maximum"); |
1185 | | |
1186 | | /* no need to process data */ |
1187 | 0 | if (scale_factor == (int)(cd_values[H5Z_SCALEOFFSET_PARM_SIZE] * 8)) { |
1188 | 0 | ret_value = *buf_size; |
1189 | 0 | goto done; |
1190 | 0 | } |
1191 | 0 | minbits = (uint32_t)scale_factor; |
1192 | 0 | } |
1193 | | |
1194 | | /* prepare parameters to pass to compress/decompress functions */ |
1195 | 0 | p.size = cd_values[H5Z_SCALEOFFSET_PARM_SIZE]; |
1196 | 0 | p.mem_order = (unsigned)H5T_native_order_g; |
1197 | | |
1198 | | /* input; decompress */ |
1199 | 0 | if (flags & H5Z_FLAG_REVERSE) { |
1200 | | /* retrieve values of minbits and minval from input compressed buffer |
1201 | | * retrieve them corresponding to how they are stored during compression |
1202 | | */ |
1203 | 0 | uint32_t minbits_mask = 0; |
1204 | 0 | unsigned long long minval_mask = 0; |
1205 | 0 | unsigned minval_size = 0; |
1206 | |
|
1207 | 0 | minbits = 0; |
1208 | 0 | for (i = 0; i < 4; i++) { |
1209 | 0 | minbits_mask = ((unsigned char *)*buf)[i]; |
1210 | 0 | minbits_mask <<= i * 8; |
1211 | 0 | minbits |= minbits_mask; |
1212 | 0 | } |
1213 | 0 | if (minbits >= p.size * 8) |
1214 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "minimum number of bits exceeds size of type"); |
1215 | | |
1216 | | /* retrieval of minval takes into consideration situation where sizeof |
1217 | | * unsigned long long (datatype of minval) may change from compression |
1218 | | * to decompression, only smaller size is used |
1219 | | */ |
1220 | 0 | minval_size = sizeof(unsigned long long) <= ((unsigned char *)*buf)[4] ? sizeof(unsigned long long) |
1221 | 0 | : ((unsigned char *)*buf)[4]; |
1222 | 0 | minval = 0; |
1223 | 0 | for (i = 0; i < minval_size; i++) { |
1224 | 0 | minval_mask = ((unsigned char *)*buf)[5 + i]; |
1225 | 0 | minval_mask <<= i * 8; |
1226 | 0 | minval |= minval_mask; |
1227 | 0 | } |
1228 | |
|
1229 | 0 | assert(minbits <= p.size * 8); |
1230 | 0 | p.minbits = minbits; |
1231 | | |
1232 | | /* calculate size of output buffer after decompression */ |
1233 | 0 | size_out = d_nelmts * (size_t)p.size; |
1234 | | |
1235 | | /* allocate memory space for decompressed buffer */ |
1236 | 0 | if (NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out))) |
1237 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, |
1238 | 0 | "memory allocation failed for scaleoffset decompression"); |
1239 | | |
1240 | | /* special case: minbits equal to full precision */ |
1241 | 0 | if (minbits == p.size * 8) { |
1242 | 0 | H5MM_memcpy(outbuf, (unsigned char *)(*buf) + buf_offset, size_out); |
1243 | | /* free the original buffer */ |
1244 | 0 | H5MM_xfree(*buf); |
1245 | | |
1246 | | /* convert to dataset datatype endianness order if needed */ |
1247 | 0 | if (need_convert) |
1248 | 0 | H5Z__scaleoffset_convert(outbuf, d_nelmts, p.size); |
1249 | |
|
1250 | 0 | *buf = outbuf; |
1251 | 0 | outbuf = NULL; |
1252 | 0 | *buf_size = size_out; |
1253 | 0 | ret_value = size_out; |
1254 | 0 | goto done; |
1255 | 0 | } |
1256 | | |
1257 | | /* decompress the buffer if minbits not equal to zero */ |
1258 | 0 | if (minbits != 0) |
1259 | 0 | H5Z__scaleoffset_decompress(outbuf, d_nelmts, (unsigned char *)(*buf) + buf_offset, p); |
1260 | 0 | else { |
1261 | | /* fill value is not defined and all data elements have the same value */ |
1262 | 0 | for (i = 0; i < size_out; i++) |
1263 | 0 | outbuf[i] = 0; |
1264 | 0 | } |
1265 | | |
1266 | | /* before postprocess, get memory type */ |
1267 | 0 | if ((type = H5Z__scaleoffset_get_type(dtype_class, p.size, dtype_sign)) == 0) |
1268 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "cannot use C integer datatype for cast"); |
1269 | | |
1270 | | /* postprocess after decompression */ |
1271 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_INTEGER) |
1272 | 0 | H5Z__scaleoffset_postdecompress_i(outbuf, d_nelmts, type, filavail, cd_values, minbits, minval); |
1273 | |
|
1274 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_FLOAT) |
1275 | 0 | if (scale_type == 0) { /* variable-minimum-bits method */ |
1276 | 0 | if (H5Z__scaleoffset_postdecompress_fd(outbuf, d_nelmts, type, filavail, cd_values, minbits, |
1277 | 0 | minval, D_val) == FAIL) |
1278 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "post-decompression failed"); |
1279 | 0 | } |
1280 | | |
1281 | | /* after postprocess, convert to dataset datatype endianness order if needed */ |
1282 | 0 | if (need_convert) |
1283 | 0 | H5Z__scaleoffset_convert(outbuf, d_nelmts, p.size); |
1284 | 0 | } |
1285 | | /* output; compress */ |
1286 | 0 | else { |
1287 | 0 | size_t used_bytes; |
1288 | 0 | size_t unused_bytes; |
1289 | |
|
1290 | 0 | assert(nbytes == d_nelmts * p.size); |
1291 | | |
1292 | | /* before preprocess, convert to memory endianness order if needed */ |
1293 | 0 | if (need_convert) |
1294 | 0 | H5Z__scaleoffset_convert(*buf, d_nelmts, p.size); |
1295 | | |
1296 | | /* before preprocess, get memory type */ |
1297 | 0 | if ((type = H5Z__scaleoffset_get_type(dtype_class, p.size, dtype_sign)) == 0) |
1298 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "cannot use C integer datatype for cast"); |
1299 | | |
1300 | | /* preprocess before compression */ |
1301 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_INTEGER) |
1302 | 0 | H5Z__scaleoffset_precompress_i(*buf, d_nelmts, type, filavail, cd_values, &minbits, &minval); |
1303 | |
|
1304 | 0 | if (dtype_class == H5Z_SCALEOFFSET_CLS_FLOAT) |
1305 | 0 | if (scale_type == 0) { /* variable-minimum-bits method */ |
1306 | 0 | if (H5Z__scaleoffset_precompress_fd(*buf, d_nelmts, type, filavail, cd_values, &minbits, |
1307 | 0 | &minval, D_val) == FAIL) |
1308 | 0 | HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, 0, "pre-compression failed"); |
1309 | 0 | } |
1310 | | |
1311 | 0 | assert(minbits <= p.size * 8); |
1312 | | |
1313 | | /* calculate buffer size after compression |
1314 | | * minbits and minval are stored in the front of the compressed buffer |
1315 | | */ |
1316 | 0 | p.minbits = minbits; |
1317 | 0 | size_out = buf_offset + nbytes * p.minbits / (p.size * 8) + 1; /* may be 1 larger */ |
1318 | | |
1319 | | /* allocate memory space for compressed buffer */ |
1320 | 0 | if (NULL == (outbuf = (unsigned char *)H5MM_malloc(size_out))) |
1321 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for scaleoffset compression"); |
1322 | | |
1323 | | /* store minbits and minval in the front of output compressed buffer |
1324 | | * store byte by byte from least significant byte to most significant byte |
1325 | | * constant buffer size (21 bytes) is left for these two parameters |
1326 | | * 4 bytes for minbits, 1 byte for size of minval, 16 bytes for minval |
1327 | | */ |
1328 | 0 | for (i = 0; i < 4; i++) |
1329 | 0 | ((unsigned char *)outbuf)[i] = (unsigned char)((minbits & ((uint32_t)0xff << i * 8)) >> i * 8); |
1330 | |
|
1331 | 0 | ((unsigned char *)outbuf)[4] = sizeof(unsigned long long); |
1332 | |
|
1333 | 0 | for (i = 0; i < sizeof(unsigned long long); i++) |
1334 | 0 | ((unsigned char *)outbuf)[5 + i] = |
1335 | 0 | (unsigned char)((minval & ((unsigned long long)0xff << i * 8)) >> i * 8); |
1336 | | |
1337 | | /* Zero out remaining, unused bytes */ |
1338 | | /* (Looks like an error in the original determination of how many |
1339 | | * bytes would be needed for parameters. - QAK, 2010/08/19) |
1340 | | */ |
1341 | 0 | used_bytes = 4 + 1 + sizeof(unsigned long long); |
1342 | 0 | assert(used_bytes <= size_out); |
1343 | 0 | unused_bytes = size_out - used_bytes; |
1344 | 0 | memset(outbuf + 13, 0, unused_bytes); |
1345 | | |
1346 | | /* special case: minbits equal to full precision */ |
1347 | 0 | if (minbits == p.size * 8) { |
1348 | 0 | H5MM_memcpy(outbuf + buf_offset, *buf, nbytes); |
1349 | | /* free the original buffer */ |
1350 | 0 | H5MM_xfree(*buf); |
1351 | |
|
1352 | 0 | *buf = outbuf; |
1353 | 0 | outbuf = NULL; |
1354 | 0 | *buf_size = size_out; |
1355 | 0 | ret_value = buf_offset + nbytes; |
1356 | 0 | goto done; |
1357 | 0 | } |
1358 | | |
1359 | | /* compress the buffer if minbits not equal to zero |
1360 | | * minbits equal to zero only when fill value is not defined and |
1361 | | * all data elements have the same value |
1362 | | */ |
1363 | 0 | if (minbits != 0) |
1364 | 0 | H5Z__scaleoffset_compress((unsigned char *)*buf, d_nelmts, outbuf + buf_offset, |
1365 | 0 | size_out - buf_offset, p); |
1366 | 0 | } |
1367 | | |
1368 | | /* free the input buffer */ |
1369 | 0 | H5MM_xfree(*buf); |
1370 | | |
1371 | | /* set return values */ |
1372 | 0 | *buf = outbuf; |
1373 | 0 | outbuf = NULL; |
1374 | 0 | *buf_size = size_out; |
1375 | 0 | ret_value = size_out; |
1376 | |
|
1377 | 0 | done: |
1378 | 0 | if (outbuf) |
1379 | 0 | H5MM_xfree(outbuf); |
1380 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1381 | 0 | } |
1382 | | |
1383 | | /* ============ Scaleoffset Algorithm =============================================== |
1384 | | * assume one byte has 8 bit |
1385 | | * assume padding bit is 0 |
1386 | | * assume size of unsigned char is one byte |
1387 | | * assume one data item of certain datatype is stored continuously in bytes |
1388 | | * atomic datatype is treated on byte basis |
1389 | | */ |
1390 | | |
1391 | | /* change byte order of input buffer either from little-endian to big-endian |
1392 | | * or from big-endian to little-endian 2/21/2005 |
1393 | | */ |
1394 | | static void |
1395 | | H5Z__scaleoffset_convert(void *buf, unsigned d_nelmts, unsigned dtype_size) |
1396 | 0 | { |
1397 | 0 | if (dtype_size > 1) { |
1398 | 0 | size_t i, j; |
1399 | 0 | unsigned char *buffer, temp; |
1400 | |
|
1401 | 0 | buffer = (unsigned char *)buf; |
1402 | 0 | for (i = 0; i < d_nelmts * (size_t)dtype_size; i += dtype_size) |
1403 | 0 | for (j = 0; j < dtype_size / 2; j++) { |
1404 | | /* swap pair of bytes */ |
1405 | 0 | temp = buffer[i + j]; |
1406 | 0 | buffer[i + j] = buffer[i + dtype_size - 1 - j]; |
1407 | 0 | buffer[i + dtype_size - 1 - j] = temp; |
1408 | 0 | } /* end for */ |
1409 | 0 | } /* end if */ |
1410 | 0 | } /* end H5Z__scaleoffset_convert() */ |
1411 | | |
1412 | | /* return ceiling of floating-point log2 function |
1413 | | * receive unsigned integer as argument 3/10/2005 |
1414 | | */ |
1415 | | static unsigned |
1416 | | H5Z__scaleoffset_log2(unsigned long long num) |
1417 | 0 | { |
1418 | 0 | unsigned v = 0; |
1419 | 0 | unsigned long long lower_bound = 1; /* is power of 2, largest value <= num */ |
1420 | 0 | unsigned long long val = num; |
1421 | |
|
1422 | 0 | while (val >>= 1) { |
1423 | 0 | v++; |
1424 | 0 | lower_bound <<= 1; |
1425 | 0 | } |
1426 | |
|
1427 | 0 | if (num == lower_bound) |
1428 | 0 | return v; |
1429 | 0 | else |
1430 | 0 | return v + 1; |
1431 | 0 | } |
1432 | | |
1433 | | /* precompress for integer type */ |
1434 | | static void |
1435 | | H5Z__scaleoffset_precompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, unsigned filavail, |
1436 | | const unsigned cd_values[], uint32_t *minbits, unsigned long long *minval) |
1437 | 0 | { |
1438 | 0 | if (type == t_uchar) |
1439 | 0 | H5Z_scaleoffset_precompress_1(unsigned char, data, d_nelmts, filavail, cd_values, minbits, minval); |
1440 | 0 | else if (type == t_ushort) |
1441 | 0 | H5Z_scaleoffset_precompress_1(unsigned short, data, d_nelmts, filavail, cd_values, minbits, minval); |
1442 | 0 | else if (type == t_uint) |
1443 | 0 | H5Z_scaleoffset_precompress_1(unsigned int, data, d_nelmts, filavail, cd_values, minbits, minval); |
1444 | 0 | else if (type == t_ulong) |
1445 | 0 | H5Z_scaleoffset_precompress_1(unsigned long, data, d_nelmts, filavail, cd_values, minbits, minval); |
1446 | 0 | else if (type == t_ulong_long) |
1447 | 0 | H5Z_scaleoffset_precompress_1(unsigned long long, data, d_nelmts, filavail, cd_values, minbits, |
1448 | 0 | minval); |
1449 | 0 | else if (type == t_schar) { |
1450 | 0 | signed char *buf = (signed char *)data, min = 0, max = 0, filval = 0; |
1451 | 0 | unsigned char span; |
1452 | 0 | unsigned i; |
1453 | |
|
1454 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ |
1455 | 0 | H5Z_scaleoffset_get_filval_1(signed char, cd_values, filval); |
1456 | 0 | if (*minbits == |
1457 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ |
1458 | 0 | H5Z_scaleoffset_max_min_1(i, d_nelmts, buf, filval, max, |
1459 | 0 | min) if ((unsigned char)(max - min) > |
1460 | 0 | (unsigned char)(~(unsigned char)0 - 2)) |
1461 | 0 | { |
1462 | 0 | *minbits = sizeof(signed char) * 8; |
1463 | 0 | return; |
1464 | 0 | } |
1465 | 0 | span = (unsigned char)(max - min + 1); |
1466 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)(span + 1)); |
1467 | 0 | } |
1468 | 0 | else /* minbits already set, only calculate min */ |
1469 | 0 | H5Z_scaleoffset_min_1(i, d_nelmts, buf, filval, |
1470 | 0 | min) if (*minbits != |
1471 | 0 | sizeof(signed char) * |
1472 | 0 | 8) /* change values if minbits != full precision */ |
1473 | 0 | for (i = 0; i < d_nelmts; i++) buf[i] = |
1474 | 0 | (signed char)((buf[i] == filval) ? (((unsigned char)1 << *minbits) - 1) |
1475 | 0 | : (buf[i] - min)); |
1476 | 0 | } |
1477 | 0 | else { /* fill value undefined */ |
1478 | 0 | if (*minbits == |
1479 | 0 | H5Z_SO_INT_MINBITS_DEFAULT) { /* minbits not set yet, calculate max, min, and minbits */ |
1480 | 0 | H5Z_scaleoffset_max_min_2(i, d_nelmts, buf, max, |
1481 | 0 | min) if ((unsigned char)(max - min) > |
1482 | 0 | (unsigned char)(~(unsigned char)0 - 2)) |
1483 | 0 | { |
1484 | 0 | *minbits = sizeof(signed char) * 8; |
1485 | 0 | *minval = (unsigned long long)min; |
1486 | 0 | return; |
1487 | 0 | } |
1488 | 0 | span = (unsigned char)(max - min + 1); |
1489 | 0 | *minbits = H5Z__scaleoffset_log2((unsigned long long)span); |
1490 | 0 | } |
1491 | 0 | else /* minbits already set, only calculate min */ |
1492 | 0 | H5Z_scaleoffset_min_2(i, d_nelmts, buf, |
1493 | 0 | min) if (*minbits != |
1494 | 0 | sizeof(signed char) * |
1495 | 0 | 8) /* change values if minbits != full precision */ |
1496 | 0 | for (i = 0; i < d_nelmts; i++) buf[i] = (signed char)(buf[i] - min); |
1497 | 0 | } |
1498 | 0 | *minval = (unsigned long long)min; |
1499 | 0 | } |
1500 | 0 | else if (type == t_short) |
1501 | 0 | H5Z_scaleoffset_precompress_2(short, data, d_nelmts, filavail, cd_values, minbits, minval); |
1502 | 0 | else if (type == t_int) |
1503 | 0 | H5Z_scaleoffset_precompress_2(int, data, d_nelmts, filavail, cd_values, minbits, minval); |
1504 | 0 | else if (type == t_long) |
1505 | 0 | H5Z_scaleoffset_precompress_2(long, data, d_nelmts, filavail, cd_values, minbits, minval); |
1506 | 0 | else if (type == t_long_long) |
1507 | 0 | H5Z_scaleoffset_precompress_2(long long, data, d_nelmts, filavail, cd_values, minbits, minval); |
1508 | 0 | } |
1509 | | |
1510 | | /* postdecompress for integer type */ |
1511 | | static void |
1512 | | H5Z__scaleoffset_postdecompress_i(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
1513 | | unsigned filavail, const unsigned cd_values[], uint32_t minbits, |
1514 | | unsigned long long minval) |
1515 | 0 | { |
1516 | 0 | long long sminval = *(long long *)&minval; /* for signed integer types */ |
1517 | |
|
1518 | 0 | if (type == t_uchar) |
1519 | 0 | H5Z_scaleoffset_postdecompress_1(unsigned char, data, d_nelmts, filavail, cd_values, minbits, minval); |
1520 | 0 | else if (type == t_ushort) |
1521 | 0 | H5Z_scaleoffset_postdecompress_1(unsigned short, data, d_nelmts, filavail, cd_values, minbits, |
1522 | 0 | minval); |
1523 | 0 | else if (type == t_uint) |
1524 | 0 | H5Z_scaleoffset_postdecompress_1(unsigned int, data, d_nelmts, filavail, cd_values, minbits, minval); |
1525 | 0 | else if (type == t_ulong) |
1526 | 0 | H5Z_scaleoffset_postdecompress_1(unsigned long, data, d_nelmts, filavail, cd_values, minbits, minval); |
1527 | 0 | else if (type == t_ulong_long) |
1528 | 0 | H5Z_scaleoffset_postdecompress_1(unsigned long long, data, d_nelmts, filavail, cd_values, minbits, |
1529 | 0 | minval); |
1530 | 0 | else if (type == t_schar) { |
1531 | 0 | signed char *buf = (signed char *)data, filval = 0; |
1532 | 0 | unsigned i; |
1533 | |
|
1534 | 0 | if (filavail == H5Z_SCALEOFFSET_FILL_DEFINED) { /* fill value defined */ |
1535 | 0 | H5Z_scaleoffset_get_filval_1(signed char, cd_values, filval); |
1536 | 0 | for (i = 0; i < d_nelmts; i++) |
1537 | 0 | buf[i] = (signed char)((buf[i] == (((unsigned char)1 << minbits) - 1)) ? filval |
1538 | 0 | : (buf[i] + sminval)); |
1539 | 0 | } |
1540 | 0 | else /* fill value undefined */ |
1541 | 0 | for (i = 0; i < d_nelmts; i++) |
1542 | 0 | buf[i] = (signed char)(buf[i] + sminval); |
1543 | 0 | } |
1544 | 0 | else if (type == t_short) |
1545 | 0 | H5Z_scaleoffset_postdecompress_2(short, data, d_nelmts, filavail, cd_values, minbits, sminval); |
1546 | 0 | else if (type == t_int) |
1547 | 0 | H5Z_scaleoffset_postdecompress_2(int, data, d_nelmts, filavail, cd_values, minbits, sminval); |
1548 | 0 | else if (type == t_long) |
1549 | 0 | H5Z_scaleoffset_postdecompress_2(long, data, d_nelmts, filavail, cd_values, minbits, sminval); |
1550 | 0 | else if (type == t_long_long) |
1551 | 0 | H5Z_scaleoffset_postdecompress_2(long long, data, d_nelmts, filavail, cd_values, minbits, sminval); |
1552 | 0 | } |
1553 | | |
1554 | | /* precompress for floating-point type, variable-minimum-bits method |
1555 | | success: non-negative, failure: negative 4/15/05 */ |
1556 | | static herr_t |
1557 | | H5Z__scaleoffset_precompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, unsigned filavail, |
1558 | | const unsigned cd_values[], uint32_t *minbits, unsigned long long *minval, |
1559 | | double D_val) |
1560 | 0 | { |
1561 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1562 | |
|
1563 | 0 | FUNC_ENTER_PACKAGE |
1564 | |
|
1565 | 0 | if (type == t_float) |
1566 | 0 | H5Z_scaleoffset_precompress_3(float, powf, fabsf, roundf, lroundf, llroundf, data, d_nelmts, filavail, |
1567 | 0 | cd_values, minbits, minval, D_val); |
1568 | 0 | else if (type == t_double) |
1569 | 0 | H5Z_scaleoffset_precompress_3(double, pow, fabs, round, lround, llround, data, d_nelmts, filavail, |
1570 | 0 | cd_values, minbits, minval, D_val); |
1571 | | |
1572 | 0 | done: |
1573 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1574 | 0 | } |
1575 | | |
1576 | | /* postdecompress for floating-point type, variable-minimum-bits method |
1577 | | success: non-negative, failure: negative 4/15/05 */ |
1578 | | static herr_t |
1579 | | H5Z__scaleoffset_postdecompress_fd(void *data, unsigned d_nelmts, enum H5Z_scaleoffset_t type, |
1580 | | unsigned filavail, const unsigned cd_values[], uint32_t minbits, |
1581 | | unsigned long long minval, double D_val) |
1582 | 0 | { |
1583 | 0 | long long sminval = (long long)minval; /* for signed integer types */ |
1584 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1585 | |
|
1586 | 0 | FUNC_ENTER_PACKAGE |
1587 | |
|
1588 | 0 | if (type == t_float) |
1589 | 0 | H5Z_scaleoffset_postdecompress_3(float, powf, data, d_nelmts, filavail, cd_values, minbits, sminval, |
1590 | 0 | D_val); |
1591 | 0 | else if (type == t_double) |
1592 | 0 | H5Z_scaleoffset_postdecompress_3(double, pow, data, d_nelmts, filavail, cd_values, minbits, sminval, |
1593 | 0 | D_val); |
1594 | | |
1595 | 0 | done: |
1596 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1597 | 0 | } |
1598 | | |
1599 | | static void |
1600 | | H5Z__scaleoffset_next_byte(size_t *j, unsigned *buf_len) |
1601 | 0 | { |
1602 | 0 | ++(*j); |
1603 | 0 | *buf_len = 8 * sizeof(unsigned char); |
1604 | 0 | } |
1605 | | |
1606 | | static void |
1607 | | H5Z__scaleoffset_decompress_one_byte(unsigned char *data, size_t data_offset, unsigned k, unsigned begin_i, |
1608 | | const unsigned char *buffer, size_t *j, unsigned *buf_len, |
1609 | | parms_atomic p, unsigned dtype_len) |
1610 | 0 | { |
1611 | 0 | unsigned dat_len; /* dat_len is the number of bits to be copied in each data byte */ |
1612 | 0 | unsigned char val; /* value to be copied in each data byte */ |
1613 | | |
1614 | | /* initialize value and bits of unsigned char to be copied */ |
1615 | 0 | val = buffer[*j]; |
1616 | 0 | if (k == begin_i) |
1617 | 0 | dat_len = 8 - (dtype_len - p.minbits) % 8; |
1618 | 0 | else |
1619 | 0 | dat_len = 8; |
1620 | |
|
1621 | 0 | if (*buf_len > dat_len) { |
1622 | 0 | data[data_offset + k] = |
1623 | 0 | (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & (unsigned)(~((unsigned)~0 << dat_len))); |
1624 | 0 | *buf_len -= dat_len; |
1625 | 0 | } /* end if */ |
1626 | 0 | else { |
1627 | 0 | data[data_offset + k] = |
1628 | 0 | (unsigned char)((val & ~((unsigned)(~0) << *buf_len)) << (dat_len - *buf_len)); |
1629 | 0 | dat_len -= *buf_len; |
1630 | 0 | H5Z__scaleoffset_next_byte(j, buf_len); |
1631 | 0 | if (dat_len == 0) |
1632 | 0 | return; |
1633 | | |
1634 | 0 | val = buffer[*j]; |
1635 | 0 | data[data_offset + k] |= |
1636 | 0 | (unsigned char)((unsigned)(val >> (*buf_len - dat_len)) & ~((unsigned)(~0) << dat_len)); |
1637 | 0 | *buf_len -= dat_len; |
1638 | 0 | } /* end else */ |
1639 | 0 | } |
1640 | | |
1641 | | static void |
1642 | | H5Z__scaleoffset_decompress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer, |
1643 | | size_t *j, unsigned *buf_len, parms_atomic p) |
1644 | 0 | { |
1645 | | /* begin_i: the index of byte having first significant bit */ |
1646 | 0 | unsigned begin_i; |
1647 | 0 | unsigned dtype_len; |
1648 | 0 | int k; |
1649 | |
|
1650 | 0 | assert(p.minbits > 0); |
1651 | |
|
1652 | 0 | dtype_len = p.size * 8; |
1653 | |
|
1654 | 0 | if (p.mem_order == H5Z_SCALEOFFSET_ORDER_LE) { /* little endian */ |
1655 | 0 | begin_i = p.size - 1 - (dtype_len - p.minbits) / 8; |
1656 | |
|
1657 | 0 | for (k = (int)begin_i; k >= 0; k--) |
1658 | 0 | H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, |
1659 | 0 | p, dtype_len); |
1660 | 0 | } |
1661 | 0 | else { /* big endian */ |
1662 | 0 | assert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE); |
1663 | |
|
1664 | 0 | begin_i = (dtype_len - p.minbits) / 8; |
1665 | |
|
1666 | 0 | for (k = (int)begin_i; k <= (int)(p.size - 1); k++) |
1667 | 0 | H5Z__scaleoffset_decompress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, |
1668 | 0 | p, dtype_len); |
1669 | 0 | } |
1670 | 0 | } |
1671 | | |
1672 | | static void |
1673 | | H5Z__scaleoffset_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, parms_atomic p) |
1674 | 0 | { |
1675 | | /* i: index of data, j: index of buffer, |
1676 | | buf_len: number of bits to be filled in current byte */ |
1677 | 0 | size_t i, j; |
1678 | 0 | unsigned buf_len; |
1679 | | |
1680 | | /* must initialize to zeros */ |
1681 | 0 | for (i = 0; i < d_nelmts * (size_t)p.size; i++) |
1682 | 0 | data[i] = 0; |
1683 | | |
1684 | | /* initialization before the loop */ |
1685 | 0 | j = 0; |
1686 | 0 | buf_len = sizeof(unsigned char) * 8; |
1687 | | |
1688 | | /* decompress */ |
1689 | 0 | for (i = 0; i < d_nelmts; i++) |
1690 | 0 | H5Z__scaleoffset_decompress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p); |
1691 | 0 | } |
1692 | | |
1693 | | static void |
1694 | | H5Z__scaleoffset_compress_one_byte(const unsigned char *data, size_t data_offset, unsigned k, |
1695 | | unsigned begin_i, unsigned char *buffer, size_t *j, unsigned *buf_len, |
1696 | | parms_atomic p, unsigned dtype_len) |
1697 | 0 | { |
1698 | 0 | unsigned dat_len; /* dat_len is the number of bits to be copied in each data byte */ |
1699 | 0 | unsigned char val; /* value to be copied in each data byte */ |
1700 | | |
1701 | | /* initialize value and bits of unsigned char to be copied */ |
1702 | 0 | val = data[data_offset + k]; |
1703 | 0 | if (k == begin_i) |
1704 | 0 | dat_len = 8 - (dtype_len - p.minbits) % 8; |
1705 | 0 | else |
1706 | 0 | dat_len = 8; |
1707 | |
|
1708 | 0 | if (*buf_len > dat_len) { |
1709 | 0 | buffer[*j] |= (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len)); |
1710 | 0 | *buf_len -= dat_len; |
1711 | 0 | } |
1712 | 0 | else { |
1713 | 0 | buffer[*j] |= |
1714 | 0 | (unsigned char)((unsigned)(val >> (dat_len - *buf_len)) & ~((unsigned)(~0) << *buf_len)); |
1715 | 0 | dat_len -= *buf_len; |
1716 | 0 | H5Z__scaleoffset_next_byte(j, buf_len); |
1717 | 0 | if (dat_len == 0) |
1718 | 0 | return; |
1719 | | |
1720 | 0 | buffer[*j] = (unsigned char)((val & ~((unsigned)(~0) << dat_len)) << (*buf_len - dat_len)); |
1721 | 0 | *buf_len -= dat_len; |
1722 | 0 | } /* end else */ |
1723 | 0 | } |
1724 | | |
1725 | | static void |
1726 | | H5Z__scaleoffset_compress_one_atomic(unsigned char *data, size_t data_offset, unsigned char *buffer, |
1727 | | size_t *j, unsigned *buf_len, parms_atomic p) |
1728 | 0 | { |
1729 | | /* begin_i: the index of byte having first significant bit */ |
1730 | 0 | unsigned begin_i; |
1731 | 0 | unsigned dtype_len; |
1732 | 0 | int k; |
1733 | |
|
1734 | 0 | assert(p.minbits > 0); |
1735 | |
|
1736 | 0 | dtype_len = p.size * 8; |
1737 | |
|
1738 | 0 | if (p.mem_order == H5Z_SCALEOFFSET_ORDER_LE) { /* little endian */ |
1739 | 0 | begin_i = p.size - 1 - (dtype_len - p.minbits) / 8; |
1740 | |
|
1741 | 0 | for (k = (int)begin_i; k >= 0; k--) |
1742 | 0 | H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, p, |
1743 | 0 | dtype_len); |
1744 | 0 | } |
1745 | 0 | else { /* big endian */ |
1746 | 0 | assert(p.mem_order == H5Z_SCALEOFFSET_ORDER_BE); |
1747 | 0 | begin_i = (dtype_len - p.minbits) / 8; |
1748 | |
|
1749 | 0 | for (k = (int)begin_i; k <= (int)(p.size - 1); k++) |
1750 | 0 | H5Z__scaleoffset_compress_one_byte(data, data_offset, (unsigned)k, begin_i, buffer, j, buf_len, p, |
1751 | 0 | dtype_len); |
1752 | 0 | } |
1753 | 0 | } |
1754 | | |
1755 | | static void |
1756 | | H5Z__scaleoffset_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer, size_t buffer_size, |
1757 | | parms_atomic p) |
1758 | 0 | { |
1759 | | /* i: index of data, j: index of buffer, |
1760 | | buf_len: number of bits to be filled in current byte */ |
1761 | 0 | size_t i, j; |
1762 | 0 | unsigned buf_len; |
1763 | | |
1764 | | /* must initialize buffer to be zeros */ |
1765 | 0 | for (j = 0; j < buffer_size; j++) |
1766 | 0 | buffer[j] = 0; |
1767 | | |
1768 | | /* initialization before the loop */ |
1769 | 0 | j = 0; |
1770 | 0 | buf_len = sizeof(unsigned char) * 8; |
1771 | | |
1772 | | /* compress */ |
1773 | 0 | for (i = 0; i < d_nelmts; i++) |
1774 | 0 | H5Z__scaleoffset_compress_one_atomic(data, i * p.size, buffer, &j, &buf_len, p); |
1775 | 0 | } |