Coverage Report

Created: 2024-06-18 06:29

/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
}