Coverage Report

Created: 2026-04-29 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Ztrans.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
#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 "H5VMprivate.h" /* H5VM_array_fill                     */
20
#include "H5Zpkg.h"      /* Data filters                                */
21
22
/* Token types */
23
typedef enum {
24
    H5Z_XFORM_ERROR,
25
    H5Z_XFORM_INTEGER, /* this represents an integer type in the data transform expression */
26
    H5Z_XFORM_FLOAT,   /* this represents a floating point type in the data transform expression */
27
    H5Z_XFORM_SYMBOL,
28
    H5Z_XFORM_PLUS,
29
    H5Z_XFORM_MINUS,
30
    H5Z_XFORM_MULT,
31
    H5Z_XFORM_DIVIDE,
32
    H5Z_XFORM_LPAREN,
33
    H5Z_XFORM_RPAREN,
34
    H5Z_XFORM_END
35
} H5Z_token_type;
36
37
typedef struct {
38
    unsigned int num_ptrs;
39
    void       **ptr_dat_val;
40
} H5Z_datval_ptrs;
41
42
/* Used to represent values in transform expression */
43
typedef union {
44
    void  *dat_val;
45
    long   int_val;
46
    double float_val;
47
} H5Z_num_val;
48
49
typedef struct H5Z_node {
50
    struct H5Z_node *lchild;
51
    struct H5Z_node *rchild;
52
    H5Z_token_type   type;
53
    H5Z_num_val      value;
54
} H5Z_node;
55
56
struct H5Z_data_xform_t {
57
    char            *xform_exp;
58
    H5Z_node        *parse_root;
59
    H5Z_datval_ptrs *dat_val_pointers;
60
};
61
62
typedef struct result {
63
    H5Z_token_type type;
64
    H5Z_num_val    value;
65
} H5Z_result;
66
67
/* The token */
68
typedef struct {
69
    const char *tok_expr; /* Holds the original expression        */
70
71
    /* Current token values */
72
    H5Z_token_type tok_type;  /* The type of the current token        */
73
    const char    *tok_begin; /* The beginning of the current token   */
74
    const char    *tok_end;   /* The end of the current token         */
75
76
    /* Previous token values */
77
    H5Z_token_type tok_last_type;  /* The type of the last token           */
78
    const char    *tok_last_begin; /* The beginning of the last token      */
79
    const char    *tok_last_end;   /* The end of the last token            */
80
} H5Z_token;
81
82
/* Local function prototypes */
83
static H5Z_token *H5Z__get_token(H5Z_token *current);
84
static H5Z_node  *H5Z__parse_expression(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
85
static H5Z_node  *H5Z__parse_term(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
86
static H5Z_node  *H5Z__parse_factor(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
87
static H5Z_node  *H5Z__new_node(H5Z_token_type type);
88
static void       H5Z__do_op(H5Z_node *tree);
89
static bool       H5Z__op_is_numbs(H5Z_node *_tree);
90
static bool       H5Z__op_is_numbs2(H5Z_node *_tree);
91
static hid_t      H5Z__xform_find_type(const H5T_t *type);
92
static herr_t     H5Z__xform_eval_full(H5Z_node *tree, size_t array_size, hid_t array_type, H5Z_result *res);
93
static void       H5Z__xform_destroy_parse_tree(H5Z_node *tree);
94
static void      *H5Z__xform_parse(const char *expression, H5Z_datval_ptrs *dat_val_pointers);
95
static void      *H5Z__xform_copy_tree(H5Z_node *tree, H5Z_datval_ptrs *dat_val_pointers,
96
                                       H5Z_datval_ptrs *new_dat_val_pointers);
97
static void       H5Z__xform_reduce_tree(H5Z_node *tree);
98
99
/* PGCC (11.8-0) has trouble with the command *p++ = *p OP tree_val. It increments P first before
100
 * doing the operation.  So I break down the command into two lines:
101
 *     *p = *p OP tree_val; p++;
102
 * Actually, the behavior of *p++ = *p OP tree_val is undefined. (SLU - 2012/3/19)
103
 */
104
#define H5Z_XFORM_DO_OP1(RESL, RESR, TYPE, OP, SIZE)                                                         \
105
0
    {                                                                                                        \
106
0
        size_t u;                                                                                            \
107
0
                                                                                                             \
108
0
        if (((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type != H5Z_XFORM_SYMBOL)) {                        \
109
0
            uint8_t *p;                                                                                      \
110
0
            double   tree_val;                                                                               \
111
0
                                                                                                             \
112
0
            tree_val =                                                                                       \
113
0
                ((RESR).type == H5Z_XFORM_INTEGER ? (double)(RESR).value.int_val : (RESR).value.float_val);  \
114
0
                                                                                                             \
115
0
            p = (uint8_t *)(RESL).value.dat_val;                                                             \
116
0
            for (u = 0; u < (SIZE); u++) {                                                                   \
117
0
                TYPE data;                                                                                   \
118
0
                TYPE result;                                                                                 \
119
0
                                                                                                             \
120
0
                H5MM_memcpy(&data, p, sizeof(TYPE));                                                         \
121
0
                result = (TYPE)((double)data OP tree_val);                                                   \
122
0
                H5MM_memcpy(p, &result, sizeof(TYPE));                                                       \
123
0
                                                                                                             \
124
0
                p += sizeof(TYPE);                                                                           \
125
0
            }                                                                                                \
126
0
        }                                                                                                    \
127
0
        else if (((RESR).type == H5Z_XFORM_SYMBOL) && ((RESL).type != H5Z_XFORM_SYMBOL)) {                   \
128
0
            uint8_t *p;                                                                                      \
129
0
            double   tree_val;                                                                               \
130
0
                                                                                                             \
131
0
            /* The case that the left operand is nothing, like -x or +x */                                   \
132
0
            if ((RESL).type == H5Z_XFORM_ERROR)                                                              \
133
0
                tree_val = 0;                                                                                \
134
0
            else                                                                                             \
135
0
                tree_val = ((RESL).type == H5Z_XFORM_INTEGER ? (double)(RESL).value.int_val                  \
136
0
                                                             : (RESL).value.float_val);                      \
137
0
                                                                                                             \
138
0
            p = (uint8_t *)(RESR).value.dat_val;                                                             \
139
0
            for (u = 0; u < (SIZE); u++) {                                                                   \
140
0
                TYPE data;                                                                                   \
141
0
                TYPE result;                                                                                 \
142
0
                                                                                                             \
143
0
                H5MM_memcpy(&data, p, sizeof(TYPE));                                                         \
144
0
                result = (TYPE)(tree_val OP(double) data);                                                   \
145
0
                H5MM_memcpy(p, &result, sizeof(TYPE));                                                       \
146
0
                                                                                                             \
147
0
                p += sizeof(TYPE);                                                                           \
148
0
            }                                                                                                \
149
0
        }                                                                                                    \
150
0
        else if (((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type == H5Z_XFORM_SYMBOL)) {                   \
151
0
            uint8_t *pl = (uint8_t *)(RESL).value.dat_val;                                                   \
152
0
            uint8_t *pr = (uint8_t *)(RESR).value.dat_val;                                                   \
153
0
                                                                                                             \
154
0
            for (u = 0; u < (SIZE); u++) {                                                                   \
155
0
                TYPE datal;                                                                                  \
156
0
                TYPE datar;                                                                                  \
157
0
                                                                                                             \
158
0
                H5MM_memcpy(&datal, pl, sizeof(TYPE));                                                       \
159
0
                H5MM_memcpy(&datar, pr, sizeof(TYPE));                                                       \
160
0
                datal = (TYPE)(datal OP datar);                                                              \
161
0
                H5MM_memcpy(pl, &datal, sizeof(TYPE));                                                       \
162
0
                                                                                                             \
163
0
                pl += sizeof(TYPE);                                                                          \
164
0
                pr += sizeof(TYPE);                                                                          \
165
0
            }                                                                                                \
166
0
        }                                                                                                    \
167
0
        else                                                                                                 \
168
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unexpected type conversion operation");               \
169
0
    }
170
171
#if CHAR_MIN >= 0
172
#define H5Z_XFORM_TYPE_OP(RESL, RESR, TYPE, OP, SIZE)                                                        \
173
    {                                                                                                        \
174
        if ((TYPE) == H5T_NATIVE_CHAR)                                                                       \
175
            H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE))                                               \
176
        else if ((TYPE) == H5T_NATIVE_SCHAR)                                                                 \
177
            H5Z_XFORM_DO_OP1((RESL), (RESR), signed char, OP, (SIZE))                                        \
178
        else if ((TYPE) == H5T_NATIVE_SHORT)                                                                 \
179
            H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE))                                              \
180
        else if ((TYPE) == H5T_NATIVE_USHORT)                                                                \
181
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE))                                     \
182
        else if ((TYPE) == H5T_NATIVE_INT)                                                                   \
183
            H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE))                                                \
184
        else if ((TYPE) == H5T_NATIVE_UINT)                                                                  \
185
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE))                                       \
186
        else if ((TYPE) == H5T_NATIVE_LONG)                                                                  \
187
            H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE))                                               \
188
        else if ((TYPE) == H5T_NATIVE_ULONG)                                                                 \
189
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE))                                      \
190
        else if ((TYPE) == H5T_NATIVE_LLONG)                                                                 \
191
            H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE))                                          \
192
        else if ((TYPE) == H5T_NATIVE_ULLONG)                                                                \
193
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE))                                 \
194
        else if ((TYPE) == H5T_NATIVE_FLOAT)                                                                 \
195
            H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE))                                              \
196
        else if ((TYPE) == H5T_NATIVE_DOUBLE)                                                                \
197
            H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE))                                             \
198
        else if ((TYPE) == H5T_NATIVE_LDOUBLE)                                                               \
199
            H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE))                                        \
200
    }
201
#else /* CHAR_MIN >= 0 */
202
#define H5Z_XFORM_TYPE_OP(RESL, RESR, TYPE, OP, SIZE)                                                        \
203
0
    {                                                                                                        \
204
0
        if ((TYPE) == H5T_NATIVE_CHAR)                                                                       \
205
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE))                                               \
206
0
        else if ((TYPE) == H5T_NATIVE_UCHAR)                                                                 \
207
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned char, OP, (SIZE))                                      \
208
0
        else if ((TYPE) == H5T_NATIVE_SHORT)                                                                 \
209
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE))                                              \
210
0
        else if ((TYPE) == H5T_NATIVE_USHORT)                                                                \
211
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE))                                     \
212
0
        else if ((TYPE) == H5T_NATIVE_INT)                                                                   \
213
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE))                                                \
214
0
        else if ((TYPE) == H5T_NATIVE_UINT)                                                                  \
215
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE))                                       \
216
0
        else if ((TYPE) == H5T_NATIVE_LONG)                                                                  \
217
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE))                                               \
218
0
        else if ((TYPE) == H5T_NATIVE_ULONG)                                                                 \
219
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE))                                      \
220
0
        else if ((TYPE) == H5T_NATIVE_LLONG)                                                                 \
221
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE))                                          \
222
0
        else if ((TYPE) == H5T_NATIVE_ULLONG)                                                                \
223
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE))                                 \
224
0
        else if ((TYPE) == H5T_NATIVE_FLOAT)                                                                 \
225
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE))                                              \
226
0
        else if ((TYPE) == H5T_NATIVE_DOUBLE)                                                                \
227
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE))                                             \
228
0
        else if ((TYPE) == H5T_NATIVE_LDOUBLE)                                                               \
229
0
            H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE))                                        \
230
0
    }
231
#endif /* CHAR_MIN >= 0 */
232
233
#define H5Z_XFORM_DO_OP3(OP)                                                                                 \
234
0
    {                                                                                                        \
235
0
        if ((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type == H5Z_XFORM_INTEGER)) {        \
236
0
            tree->type          = H5Z_XFORM_INTEGER;                                                         \
237
0
            tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val;                \
238
0
            H5MM_xfree(tree->lchild);                                                                        \
239
0
            H5MM_xfree(tree->rchild);                                                                        \
240
0
            tree->lchild = NULL;                                                                             \
241
0
            tree->rchild = NULL;                                                                             \
242
0
        }                                                                                                    \
243
0
        else if (((tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) &&   \
244
0
                 ((tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) {   \
245
0
            tree->type = H5Z_XFORM_FLOAT;                                                                    \
246
0
            tree->value.float_val =                                                                          \
247
0
                ((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val                     \
248
0
                                                         : (double)tree->lchild->value.int_val)              \
249
0
                    OP((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val               \
250
0
                                                               : (double)tree->rchild->value.int_val);       \
251
0
            H5MM_xfree(tree->lchild);                                                                        \
252
0
            H5MM_xfree(tree->rchild);                                                                        \
253
0
            tree->lchild = NULL;                                                                             \
254
0
            tree->rchild = NULL;                                                                             \
255
0
        }                                                                                                    \
256
0
    }
257
258
#define H5Z_XFORM_DO_OP4(TYPE)                                                                               \
259
0
    {                                                                                                        \
260
0
        if ((ret_value = (H5Z_node *)H5MM_malloc(sizeof(H5Z_node))) == NULL)                                 \
261
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree");     \
262
0
        else {                                                                                               \
263
0
            ret_value->type = (TYPE);                                                                        \
264
0
            if (tree->lchild)                                                                                \
265
0
                ret_value->lchild =                                                                          \
266
0
                    (H5Z_node *)H5Z__xform_copy_tree(tree->lchild, dat_val_pointers, new_dat_val_pointers);  \
267
0
            else                                                                                             \
268
0
                ret_value->lchild = NULL;                                                                    \
269
0
            if (tree->rchild)                                                                                \
270
0
                ret_value->rchild =                                                                          \
271
0
                    (H5Z_node *)H5Z__xform_copy_tree(tree->rchild, dat_val_pointers, new_dat_val_pointers);  \
272
0
            else                                                                                             \
273
0
                ret_value->rchild = NULL;                                                                    \
274
0
        }                                                                                                    \
275
0
    }
276
277
#define H5Z_XFORM_DO_OP5(TYPE, SIZE)                                                                         \
278
0
    {                                                                                                        \
279
0
        TYPE val =                                                                                           \
280
0
            ((tree->type == H5Z_XFORM_INTEGER) ? (TYPE)tree->value.int_val : (TYPE)tree->value.float_val);   \
281
0
        H5VM_array_fill(array, &val, sizeof(TYPE), (SIZE));                                                  \
282
0
    }
283
284
/* The difference of this macro from H5Z_XFORM_DO_OP3 is that it handles the operations when the left operand
285
 * is empty, like -x or +x. The reason that it's separated from H5Z_XFORM_DO_OP3 is because compilers don't
286
 * accept operations like *x or /x.  So in H5Z__do_op, these two macros are called in different ways. (SLU
287
 * 2012/3/20)
288
 */
289
#define H5Z_XFORM_DO_OP6(OP)                                                                                 \
290
0
    {                                                                                                        \
291
0
        if (!tree->lchild && (tree->rchild->type == H5Z_XFORM_INTEGER)) {                                    \
292
0
            tree->type          = H5Z_XFORM_INTEGER;                                                         \
293
0
            tree->value.int_val = OP tree->rchild->value.int_val;                                            \
294
0
            H5MM_xfree(tree->rchild);                                                                        \
295
0
            tree->rchild = NULL;                                                                             \
296
0
        }                                                                                                    \
297
0
        else if (!tree->lchild && (tree->rchild->type == H5Z_XFORM_FLOAT)) {                                 \
298
0
            tree->type            = H5Z_XFORM_FLOAT;                                                         \
299
0
            tree->value.float_val = OP tree->rchild->value.float_val;                                        \
300
0
            H5MM_xfree(tree->rchild);                                                                        \
301
0
            tree->rchild = NULL;                                                                             \
302
0
        }                                                                                                    \
303
0
        else if ((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type == H5Z_XFORM_INTEGER)) {   \
304
0
            tree->type          = H5Z_XFORM_INTEGER;                                                         \
305
0
            tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val;                \
306
0
            H5MM_xfree(tree->lchild);                                                                        \
307
0
            H5MM_xfree(tree->rchild);                                                                        \
308
0
            tree->lchild = NULL;                                                                             \
309
0
            tree->rchild = NULL;                                                                             \
310
0
        }                                                                                                    \
311
0
        else if (((tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) &&   \
312
0
                 ((tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) {   \
313
0
            tree->type = H5Z_XFORM_FLOAT;                                                                    \
314
0
            tree->value.float_val =                                                                          \
315
0
                ((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val                     \
316
0
                                                         : (double)tree->lchild->value.int_val)              \
317
0
                    OP((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val               \
318
0
                                                               : (double)tree->rchild->value.int_val);       \
319
0
            H5MM_xfree(tree->lchild);                                                                        \
320
0
            H5MM_xfree(tree->rchild);                                                                        \
321
0
            tree->lchild = NULL;                                                                             \
322
0
            tree->rchild = NULL;                                                                             \
323
0
        }                                                                                                    \
324
0
    }
325
326
/*
327
 * This is the context-free grammar for our expressions:
328
 *
329
 * expr     :=  term    | term '+ term      | term '-' term
330
 * term     :=  factor  | factor '*' factor | factor '/' factor
331
 * factor   :=  number      |
332
 *              symbol      |
333
 *              '-' factor  |   // unary minus
334
 *              '+' factor  |   // unary plus
335
 *              '(' expr ')'
336
 * symbol   :=  [a-zA-Z][a-zA-Z0-9]*
337
 * number   :=  H5Z_XFORM_INTEGER | FLOAT
338
 *      // H5Z_XFORM_INTEGER is a C long int
339
 *      // FLOAT is a C double
340
 */
341
342
/*-------------------------------------------------------------------------
343
 * Function:    H5Z__unget_token
344
 *
345
 * Purpose:     Rollback the H5Z_token to the previous H5Z_token retrieved. There
346
 *              should only need to be one level of rollback necessary
347
 *              for our grammar.
348
 *
349
 * Return:      Always succeeds.
350
 *
351
 *-------------------------------------------------------------------------
352
 */
353
static void
354
H5Z__unget_token(H5Z_token *current)
355
0
{
356
0
    FUNC_ENTER_PACKAGE_NOERR
357
358
    /* check args */
359
0
    assert(current);
360
361
0
    current->tok_type  = current->tok_last_type;
362
0
    current->tok_begin = current->tok_last_begin;
363
0
    current->tok_end   = current->tok_last_end;
364
365
0
    FUNC_LEAVE_NOAPI_VOID
366
0
}
367
368
/*-------------------------------------------------------------------------
369
 * Function:    H5Z__get_token
370
 *
371
 * Purpose:     Determine what the next valid H5Z_token is in the expression
372
 *              string. The current position within the H5Z_token string is
373
 *              kept internal to the H5Z_token and handled by this and the
374
 *              unget_H5Z_token function.
375
 *
376
 * Return:      Success:        The passed in H5Z_token with a valid tok_type
377
 *                              field.
378
 *              Failure:        The passed in H5Z_token but with the tok_type
379
 *                              field set to ERROR.
380
 *
381
 *-------------------------------------------------------------------------
382
 */
383
static H5Z_token *
384
H5Z__get_token(H5Z_token *current)
385
0
{
386
0
    H5Z_token *ret_value = current;
387
388
0
    FUNC_ENTER_PACKAGE
389
390
    /* check args */
391
0
    assert(current);
392
393
    /* Save the last position for possible ungets */
394
0
    current->tok_last_type  = current->tok_type;
395
0
    current->tok_last_begin = current->tok_begin;
396
0
    current->tok_last_end   = current->tok_end;
397
398
0
    current->tok_begin = current->tok_end;
399
400
0
    while (current->tok_begin[0] != '\0') {
401
0
        if (isspace(current->tok_begin[0])) {
402
            /* ignore whitespace */
403
0
        }
404
0
        else if (isdigit(current->tok_begin[0]) || current->tok_begin[0] == '.') {
405
0
            current->tok_end = current->tok_begin;
406
407
            /*
408
             * H5Z_XFORM_INTEGER          :=  digit-sequence
409
             * digit-sequence   :=  digit | digit digit-sequence
410
             * digit            :=  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
411
             */
412
0
            if (current->tok_end[0] != '.') {
413
                /* is number */
414
0
                current->tok_type = H5Z_XFORM_INTEGER;
415
416
0
                while (isdigit(current->tok_end[0]))
417
0
                    ++current->tok_end;
418
0
            }
419
420
            /*
421
             * float            :=  digit-sequence exponent |
422
             *                      dotted-digits exponent?
423
             * dotted-digits    :=  digit-sequence '.' digit-sequence?  |
424
             *                      '.' digit-sequence
425
             * exponent         :=  [Ee] [-+]? digit-sequence
426
             */
427
0
            if (current->tok_end[0] == '.' || current->tok_end[0] == 'e' || current->tok_end[0] == 'E') {
428
0
                current->tok_type = H5Z_XFORM_FLOAT;
429
430
0
                if (current->tok_end[0] == '.')
431
0
                    do {
432
0
                        ++current->tok_end;
433
0
                    } while (isdigit(current->tok_end[0]));
434
435
0
                if (current->tok_end[0] == 'e' || current->tok_end[0] == 'E') {
436
0
                    ++current->tok_end;
437
438
0
                    if (current->tok_end[0] == '-' || current->tok_end[0] == '+')
439
0
                        ++current->tok_end;
440
441
0
                    if (!isdigit(current->tok_end[0])) {
442
0
                        current->tok_type = H5Z_XFORM_ERROR;
443
0
                        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current,
444
0
                                    "Invalidly formatted floating point number");
445
0
                    }
446
447
0
                    while (isdigit(current->tok_end[0]))
448
0
                        ++current->tok_end;
449
0
                }
450
451
                /* Check that this is a properly formatted numerical value */
452
0
                if (isalpha(current->tok_end[0]) || current->tok_end[0] == '.') {
453
0
                    current->tok_type = H5Z_XFORM_ERROR;
454
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number");
455
0
                }
456
0
            }
457
458
0
            break;
459
0
        }
460
0
        else if (isalpha(current->tok_begin[0])) {
461
            /* is symbol */
462
0
            current->tok_type = H5Z_XFORM_SYMBOL;
463
0
            current->tok_end  = current->tok_begin;
464
465
0
            while (isalnum(current->tok_end[0]))
466
0
                ++current->tok_end;
467
468
0
            break;
469
0
        }
470
0
        else {
471
            /* should be +, -, *, /, (, or ) */
472
0
            switch (current->tok_begin[0]) {
473
0
                case '+':
474
0
                    current->tok_type = H5Z_XFORM_PLUS;
475
0
                    break;
476
0
                case '-':
477
0
                    current->tok_type = H5Z_XFORM_MINUS;
478
0
                    break;
479
0
                case '*':
480
0
                    current->tok_type = H5Z_XFORM_MULT;
481
0
                    break;
482
0
                case '/':
483
0
                    current->tok_type = H5Z_XFORM_DIVIDE;
484
0
                    break;
485
0
                case '(':
486
0
                    current->tok_type = H5Z_XFORM_LPAREN;
487
0
                    break;
488
0
                case ')':
489
0
                    current->tok_type = H5Z_XFORM_RPAREN;
490
0
                    break;
491
0
                default:
492
0
                    current->tok_type = H5Z_XFORM_ERROR;
493
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current,
494
0
                                "Unknown H5Z_token in data transform expression ");
495
0
            }
496
497
0
            current->tok_end = current->tok_begin + 1;
498
0
            break;
499
0
        }
500
501
0
        ++current->tok_begin;
502
0
    }
503
504
0
    if (current->tok_begin[0] == '\0')
505
0
        current->tok_type = H5Z_XFORM_END;
506
507
    /* Set return value */
508
0
    ret_value = current;
509
510
0
done:
511
0
    FUNC_LEAVE_NOAPI(ret_value)
512
0
}
513
514
/*-------------------------------------------------------------------------
515
 * Function:    H5Z__xform_destroy_parse_tree
516
 * Purpose:     Recursively destroys the expression tree.
517
 * Return:      Nothing
518
 *-------------------------------------------------------------------------
519
 */
520
static void
521
H5Z__xform_destroy_parse_tree(H5Z_node *tree)
522
0
{
523
0
    FUNC_ENTER_PACKAGE_NOERR
524
525
0
    if (tree) {
526
0
        H5Z__xform_destroy_parse_tree(tree->lchild);
527
0
        H5Z__xform_destroy_parse_tree(tree->rchild);
528
0
        H5MM_xfree(tree);
529
0
        tree = NULL;
530
0
    }
531
532
0
    FUNC_LEAVE_NOAPI_VOID
533
0
}
534
535
/*-------------------------------------------------------------------------
536
 * Function:    H5Z_parse
537
 *
538
 * Purpose:     Entry function for parsing the expression string.
539
 *
540
 * Return:      Success:    Valid H5Z_node ptr to an expression tree.
541
 *              Failure:    NULL
542
 *
543
 *-------------------------------------------------------------------------
544
 */
545
static void *
546
H5Z__xform_parse(const char *expression, H5Z_datval_ptrs *dat_val_pointers)
547
0
{
548
0
    H5Z_token tok;
549
0
    void     *ret_value = NULL; /* Return value */
550
551
0
    FUNC_ENTER_PACKAGE
552
553
0
    if (!expression)
554
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "No expression provided?");
555
556
    /* Set up the initial H5Z_token for parsing */
557
0
    tok.tok_expr = tok.tok_begin = tok.tok_end = expression;
558
559
0
    ret_value = (void *)H5Z__parse_expression(&tok, dat_val_pointers);
560
561
0
    H5Z__xform_reduce_tree((H5Z_node *)ret_value);
562
563
0
done:
564
0
    FUNC_LEAVE_NOAPI(ret_value)
565
0
}
566
567
/*-------------------------------------------------------------------------
568
 * Function:    H5Z__parse_expression
569
 * Purpose:     Beginning of the recursive descent parser to parse the
570
 *              expression. An expression is:
571
 *
572
 *                  expr     :=  term | term '+' term | term '-' term
573
 *
574
 * Return:      Success:    Valid H5Z_node ptr to expression tree
575
 *              Failure:    NULL
576
 *
577
 *-------------------------------------------------------------------------
578
 */
579
static H5Z_node *
580
H5Z__parse_expression(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
581
0
{
582
0
    H5Z_node *expr;
583
0
    H5Z_node *ret_value = NULL; /* Return value */
584
585
0
    FUNC_ENTER_PACKAGE
586
587
0
    expr = H5Z__parse_term(current, dat_val_pointers);
588
589
0
    for (;;) {
590
0
        H5Z_node *new_node;
591
592
0
        current = H5Z__get_token(current);
593
594
0
        switch (current->tok_type) {
595
0
            case H5Z_XFORM_PLUS:
596
0
                new_node = H5Z__new_node(H5Z_XFORM_PLUS);
597
598
0
                if (!new_node) {
599
0
                    H5Z__xform_destroy_parse_tree(expr);
600
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
601
0
                }
602
603
0
                new_node->lchild = expr;
604
0
                new_node->rchild = H5Z__parse_term(current, dat_val_pointers);
605
606
0
                if (!new_node->rchild) {
607
0
                    H5Z__xform_destroy_parse_tree(new_node);
608
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
609
0
                }
610
611
0
                expr = new_node;
612
0
                break;
613
614
0
            case H5Z_XFORM_MINUS:
615
0
                new_node = H5Z__new_node(H5Z_XFORM_MINUS);
616
617
0
                if (!new_node) {
618
0
                    H5Z__xform_destroy_parse_tree(expr);
619
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
620
0
                }
621
622
0
                new_node->lchild = expr;
623
0
                new_node->rchild = H5Z__parse_term(current, dat_val_pointers);
624
625
0
                if (!new_node->rchild) {
626
0
                    H5Z__xform_destroy_parse_tree(new_node);
627
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
628
0
                }
629
630
0
                expr = new_node;
631
0
                break;
632
633
0
            case H5Z_XFORM_RPAREN:
634
0
                H5Z__unget_token(current);
635
0
                HGOTO_DONE(expr);
636
637
0
            case H5Z_XFORM_END:
638
0
                HGOTO_DONE(expr);
639
640
0
            case H5Z_XFORM_ERROR:
641
0
            case H5Z_XFORM_INTEGER:
642
0
            case H5Z_XFORM_FLOAT:
643
0
            case H5Z_XFORM_SYMBOL:
644
0
            case H5Z_XFORM_MULT:
645
0
            case H5Z_XFORM_DIVIDE:
646
0
            case H5Z_XFORM_LPAREN:
647
0
            default:
648
0
                H5Z__xform_destroy_parse_tree(expr);
649
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
650
0
        }
651
0
    }
652
653
0
done:
654
0
    FUNC_LEAVE_NOAPI(ret_value)
655
0
}
656
657
/*-------------------------------------------------------------------------
658
 * Function:    H5Z__parse_term
659
 * Purpose:     Parses a term in our expression language. A term is:
660
 *
661
 *                  term :=  factor | factor '*' factor | factor '/' factor
662
 *
663
 * Return:      Success:    Valid H5Z_node ptr to expression tree
664
 *              Failure:    NULL
665
 *
666
 *-------------------------------------------------------------------------
667
 */
668
static H5Z_node *
669
H5Z__parse_term(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
670
0
{
671
0
    H5Z_node *term      = NULL;
672
0
    H5Z_node *ret_value = NULL; /* Return value */
673
674
0
    FUNC_ENTER_PACKAGE
675
676
0
    term = H5Z__parse_factor(current, dat_val_pointers);
677
678
0
    for (;;) {
679
0
        H5Z_node *new_node;
680
681
0
        current = H5Z__get_token(current);
682
683
0
        switch (current->tok_type) {
684
0
            case H5Z_XFORM_MULT:
685
0
                new_node = H5Z__new_node(H5Z_XFORM_MULT);
686
687
0
                if (!new_node) {
688
0
                    H5Z__xform_destroy_parse_tree(term);
689
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
690
0
                }
691
692
0
                new_node->lchild = term;
693
0
                new_node->rchild = H5Z__parse_factor(current, dat_val_pointers);
694
695
0
                if (!new_node->rchild) {
696
0
                    H5Z__xform_destroy_parse_tree(new_node);
697
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
698
0
                }
699
700
0
                term = new_node;
701
0
                break;
702
703
0
            case H5Z_XFORM_DIVIDE:
704
0
                new_node = H5Z__new_node(H5Z_XFORM_DIVIDE);
705
706
0
                if (!new_node) {
707
0
                    H5Z__xform_destroy_parse_tree(term);
708
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
709
0
                }
710
711
0
                new_node->lchild = term;
712
0
                new_node->rchild = H5Z__parse_factor(current, dat_val_pointers);
713
0
                term             = new_node;
714
715
0
                if (!new_node->rchild) {
716
0
                    H5Z__xform_destroy_parse_tree(new_node);
717
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
718
0
                }
719
0
                break;
720
721
0
            case H5Z_XFORM_RPAREN:
722
0
                H5Z__unget_token(current);
723
0
                HGOTO_DONE(term);
724
725
0
            case H5Z_XFORM_END:
726
0
                HGOTO_DONE(term);
727
728
0
            case H5Z_XFORM_INTEGER:
729
0
            case H5Z_XFORM_FLOAT:
730
0
            case H5Z_XFORM_SYMBOL:
731
0
            case H5Z_XFORM_PLUS:
732
0
            case H5Z_XFORM_MINUS:
733
0
            case H5Z_XFORM_LPAREN:
734
0
                H5Z__unget_token(current);
735
0
                HGOTO_DONE(term);
736
737
0
            case H5Z_XFORM_ERROR:
738
0
            default:
739
0
                H5Z__xform_destroy_parse_tree(term);
740
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL,
741
0
                            "bad transform type passed to data transform expression");
742
0
        } /* end switch */
743
0
    }     /* end for */
744
745
0
done:
746
0
    FUNC_LEAVE_NOAPI(ret_value)
747
0
}
748
749
/*-------------------------------------------------------------------------
750
 * Function:    H5Z__parse_factor
751
 * Purpose:     Parses a factor in our expression language. A factor is:
752
 *
753
 *                  factor   :=  number      |  // C long or double
754
 *                               symbol      |  // C identifier
755
 *                               '-' factor  |  // unary minus
756
 *                               '+' factor  |  // unary plus
757
 *                               '(' expr ')'
758
 *
759
 * Return:      Success:    Valid H5Z_node ptr to expression tree
760
 *              Failure:    NULL
761
 *
762
 *-------------------------------------------------------------------------
763
 */
764
static H5Z_node *
765
H5Z__parse_factor(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
766
0
{
767
0
    H5Z_node *factor = NULL;
768
0
    H5Z_node *new_node;
769
0
    H5Z_node *ret_value = NULL; /* Return value */
770
771
0
    FUNC_ENTER_PACKAGE
772
773
0
    current = H5Z__get_token(current);
774
775
0
    switch (current->tok_type) {
776
0
        case H5Z_XFORM_INTEGER:
777
0
            factor = H5Z__new_node(H5Z_XFORM_INTEGER);
778
779
0
            if (!factor)
780
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
781
0
            sscanf(current->tok_begin, "%ld", &factor->value.int_val);
782
0
            break;
783
784
0
        case H5Z_XFORM_FLOAT:
785
0
            factor = H5Z__new_node(H5Z_XFORM_FLOAT);
786
787
0
            if (!factor)
788
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
789
0
            sscanf(current->tok_begin, "%lf", &factor->value.float_val);
790
0
            break;
791
792
0
        case H5Z_XFORM_SYMBOL:
793
0
            factor = H5Z__new_node(H5Z_XFORM_SYMBOL);
794
795
0
            if (!factor)
796
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
797
798
0
            factor->value.dat_val = &(dat_val_pointers->ptr_dat_val[dat_val_pointers->num_ptrs]);
799
0
            dat_val_pointers->num_ptrs++;
800
0
            break;
801
802
0
        case H5Z_XFORM_LPAREN:
803
0
            factor = H5Z__parse_expression(current, dat_val_pointers);
804
805
0
            if (!factor)
806
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node");
807
808
0
            current = H5Z__get_token(current);
809
810
0
            if (current->tok_type != H5Z_XFORM_RPAREN) {
811
0
                H5Z__xform_destroy_parse_tree(factor);
812
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error in data transform expression");
813
0
            }
814
0
            break;
815
816
0
        case H5Z_XFORM_RPAREN:
817
            /* We shouldn't see a ) right now */
818
0
            H5Z__xform_destroy_parse_tree(factor);
819
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error: unexpected ')' ");
820
821
0
        case H5Z_XFORM_PLUS:
822
            /* unary + */
823
0
            new_node = H5Z__parse_factor(current, dat_val_pointers);
824
825
0
            if (new_node) {
826
0
                if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
827
0
                    new_node->type != H5Z_XFORM_SYMBOL) {
828
0
                    H5Z__xform_destroy_parse_tree(new_node);
829
0
                    H5Z__xform_destroy_parse_tree(factor);
830
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
831
0
                }
832
833
0
                factor   = new_node;
834
0
                new_node = H5Z__new_node(H5Z_XFORM_PLUS);
835
836
0
                if (!new_node) {
837
0
                    H5Z__xform_destroy_parse_tree(factor);
838
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
839
0
                }
840
841
0
                new_node->rchild = factor;
842
0
                factor           = new_node;
843
0
            }
844
0
            else {
845
0
                H5Z__xform_destroy_parse_tree(factor);
846
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
847
0
            }
848
0
            break;
849
850
0
        case H5Z_XFORM_MINUS:
851
            /* unary - */
852
0
            new_node = H5Z__parse_factor(current, dat_val_pointers);
853
854
0
            if (new_node) {
855
0
                if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
856
0
                    new_node->type != H5Z_XFORM_SYMBOL) {
857
0
                    H5Z__xform_destroy_parse_tree(new_node);
858
0
                    H5Z__xform_destroy_parse_tree(factor);
859
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
860
0
                }
861
862
0
                factor   = new_node;
863
0
                new_node = H5Z__new_node(H5Z_XFORM_MINUS);
864
865
0
                if (!new_node) {
866
0
                    H5Z__xform_destroy_parse_tree(factor);
867
0
                    HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
868
0
                }
869
870
0
                new_node->rchild = factor;
871
0
                factor           = new_node;
872
0
            }
873
0
            else {
874
0
                H5Z__xform_destroy_parse_tree(factor);
875
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression");
876
0
            }
877
0
            break;
878
879
0
        case H5Z_XFORM_END:
880
0
            break;
881
882
0
        case H5Z_XFORM_MULT:
883
0
        case H5Z_XFORM_DIVIDE:
884
0
        case H5Z_XFORM_ERROR:
885
0
        default:
886
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL,
887
0
                        "Invalid token while parsing data transform expression");
888
0
    }
889
890
    /* Set return value */
891
0
    ret_value = factor;
892
893
0
done:
894
0
    FUNC_LEAVE_NOAPI(ret_value)
895
0
}
896
897
/*-------------------------------------------------------------------------
898
 * Function:    H5Z__new_node
899
 *
900
 * Purpose:     Create and initialize a new H5Z_node structure.
901
 *
902
 * Return:      Success:    Valid H5Z_node ptr
903
 *              Failure:    NULL
904
 *
905
 *-------------------------------------------------------------------------
906
 */
907
static H5Z_node *
908
H5Z__new_node(H5Z_token_type type)
909
0
{
910
0
    H5Z_node *ret_value = NULL; /* Return value */
911
912
0
    FUNC_ENTER_PACKAGE
913
914
0
    if (NULL == (ret_value = (H5Z_node *)H5MM_calloc(sizeof(H5Z_node))))
915
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
916
0
                    "Ran out of memory trying to allocate space for nodes in the parse tree");
917
918
0
    ret_value->type = type;
919
920
0
done:
921
0
    FUNC_LEAVE_NOAPI(ret_value)
922
0
}
923
924
/*-------------------------------------------------------------------------
925
 * Function:    H5Z_xform_eval
926
 * Purpose:     If the transform is trivial, this function applies it.
927
 *              Otherwise, it calls H5Z__xform_eval_full to do the full
928
 *              transform.
929
 * Return:      SUCCEED if transform applied successfully, FAIL otherwise
930
 *-------------------------------------------------------------------------
931
 */
932
herr_t
933
H5Z_xform_eval(H5Z_data_xform_t *data_xform_prop, void *array, size_t array_size, const H5T_t *buf_type)
934
0
{
935
0
    H5Z_node  *tree;
936
0
    hid_t      array_type;
937
0
    H5Z_result res;
938
0
    size_t     i;
939
0
    herr_t     ret_value = SUCCEED; /* Return value */
940
941
0
    FUNC_ENTER_NOAPI(FAIL)
942
943
0
    assert(data_xform_prop);
944
945
0
    tree = data_xform_prop->parse_root;
946
947
    /* Get the datatype ID for the buffer's type */
948
0
    if ((array_type = H5Z__xform_find_type(buf_type)) < 0)
949
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot perform data transform on this type.");
950
951
    /* After this point, we're assured that the type of the array is handled by the eval code,
952
     *  so we no longer have to check for valid types
953
     */
954
955
    /* If it's a trivial data transform, perform it */
956
0
    if (tree->type == H5Z_XFORM_INTEGER || tree->type == H5Z_XFORM_FLOAT) {
957
0
        if (array_type == H5T_NATIVE_CHAR)
958
0
            H5Z_XFORM_DO_OP5(char, array_size)
959
#if CHAR_MIN >= 0
960
        else if (array_type == H5T_NATIVE_SCHAR)
961
            H5Z_XFORM_DO_OP5(signed char, array_size)
962
#else  /* CHAR_MIN >= 0 */
963
0
        else if (array_type == H5T_NATIVE_UCHAR)
964
0
            H5Z_XFORM_DO_OP5(unsigned char, array_size)
965
0
#endif /* CHAR_MIN >= 0 */
966
0
        else if (array_type == H5T_NATIVE_SHORT)
967
0
            H5Z_XFORM_DO_OP5(short, array_size)
968
0
        else if (array_type == H5T_NATIVE_USHORT)
969
0
            H5Z_XFORM_DO_OP5(unsigned short, array_size)
970
0
        else if (array_type == H5T_NATIVE_INT)
971
0
            H5Z_XFORM_DO_OP5(int, array_size)
972
0
        else if (array_type == H5T_NATIVE_UINT)
973
0
            H5Z_XFORM_DO_OP5(unsigned int, array_size)
974
0
        else if (array_type == H5T_NATIVE_LONG)
975
0
            H5Z_XFORM_DO_OP5(long, array_size)
976
0
        else if (array_type == H5T_NATIVE_ULONG)
977
0
            H5Z_XFORM_DO_OP5(unsigned long, array_size)
978
0
        else if (array_type == H5T_NATIVE_LLONG)
979
0
            H5Z_XFORM_DO_OP5(long long, array_size)
980
0
        else if (array_type == H5T_NATIVE_ULLONG)
981
0
            H5Z_XFORM_DO_OP5(unsigned long long, array_size)
982
0
        else if (array_type == H5T_NATIVE_FLOAT)
983
0
            H5Z_XFORM_DO_OP5(float, array_size)
984
0
        else if (array_type == H5T_NATIVE_DOUBLE)
985
0
            H5Z_XFORM_DO_OP5(double, array_size)
986
0
        else if (array_type == H5T_NATIVE_LDOUBLE)
987
0
            H5Z_XFORM_DO_OP5(long double, array_size)
988
989
0
    } /* end if */
990
    /* Otherwise, do the full data transform */
991
0
    else {
992
        /* Optimization for linear transform: */
993
0
        if (data_xform_prop->dat_val_pointers->num_ptrs == 1)
994
0
            data_xform_prop->dat_val_pointers->ptr_dat_val[0] = array;
995
996
        /* If it's a quadratic transform, we have no choice but to store multiple copies of the data */
997
0
        else {
998
0
            for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++) {
999
0
                if (NULL == (data_xform_prop->dat_val_pointers->ptr_dat_val[i] = (void *)H5MM_malloc(
1000
0
                                 array_size * H5T_get_size((H5T_t *)H5I_object(array_type)))))
1001
0
                    HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1002
0
                                "Ran out of memory trying to allocate space for data in data transform");
1003
1004
0
                H5MM_memcpy(data_xform_prop->dat_val_pointers->ptr_dat_val[i], array,
1005
0
                            array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
1006
0
            } /* end for */
1007
0
        }     /* end else */
1008
1009
0
        if (H5Z__xform_eval_full(tree, array_size, array_type, &res) < 0)
1010
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform");
1011
1012
0
        if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
1013
0
            H5MM_memcpy(array, res.value.dat_val, array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
1014
1015
        /* Free the temporary arrays we used */
1016
0
        if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
1017
0
            for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++)
1018
0
                H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
1019
0
    } /* end else */
1020
1021
0
done:
1022
0
    if (ret_value < 0) {
1023
        /* If we ran out of memory above copying the array for temp storage (which we easily can for
1024
         * polynomial transforms of high order) we free those arrays which we already allocated */
1025
0
        if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
1026
0
            for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++)
1027
0
                if (data_xform_prop->dat_val_pointers->ptr_dat_val[i])
1028
0
                    H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
1029
0
    } /* end if */
1030
1031
0
    FUNC_LEAVE_NOAPI(ret_value)
1032
0
} /* end H5Z_xform_eval() */
1033
1034
/*-------------------------------------------------------------------------
1035
 * Function:    H5Z__xform_eval_full
1036
 *
1037
 * Purpose:     Does a full evaluation of the parse tree contained in tree
1038
 *              and applies this transform to array.
1039
 *
1040
 * Notes:       In the case of a polynomial data transform (ie, the left and right
1041
 *              subtree are both of type H5Z_XFORM_SYMBOL), the convention is
1042
 *              that the left hand side will accumulate changes and, at the end,
1043
 *              the new data will be copied from the lhs.
1044
 *
1045
 * Return:      Nothing
1046
 *
1047
 *-------------------------------------------------------------------------
1048
 */
1049
static herr_t
1050
H5Z__xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result *res)
1051
0
{
1052
0
    H5Z_result resl, resr;
1053
0
    herr_t     ret_value = SUCCEED; /* Return value */
1054
1055
0
    FUNC_ENTER_PACKAGE
1056
1057
    /* check args */
1058
0
    assert(tree);
1059
1060
0
    memset(&resl, 0, sizeof(H5Z_result));
1061
0
    memset(&resr, 0, sizeof(H5Z_result));
1062
1063
0
    if (tree->type == H5Z_XFORM_INTEGER) {
1064
0
        res->type          = H5Z_XFORM_INTEGER;
1065
0
        res->value.int_val = tree->value.int_val;
1066
0
    } /* end if */
1067
0
    else if (tree->type == H5Z_XFORM_FLOAT) {
1068
0
        res->type            = H5Z_XFORM_FLOAT;
1069
0
        res->value.float_val = tree->value.float_val;
1070
0
    } /* end if */
1071
0
    else if (tree->type == H5Z_XFORM_SYMBOL) {
1072
0
        res->type = H5Z_XFORM_SYMBOL;
1073
1074
        /*since dat_val stores the address of the array which is really stored in the dat_val_pointers,
1075
         * here we make dat_val store a pointer to the array itself instead of the address of it so that the
1076
         * rest of the code below works normally. */
1077
0
        res->value.dat_val = *((void **)(tree->value.dat_val));
1078
0
    } /* end if */
1079
0
    else {
1080
0
        if (tree->lchild && H5Z__xform_eval_full(tree->lchild, array_size, array_type, &resl) < 0)
1081
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform");
1082
0
        if (H5Z__xform_eval_full(tree->rchild, array_size, array_type, &resr) < 0)
1083
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform");
1084
1085
0
        res->type = H5Z_XFORM_SYMBOL;
1086
1087
        /* For each type of operation:
1088
         * 1.  See if "x" is on left hand side, right hand side, or if both sides are "x"
1089
         * 2.  Figure out what type of data we're going to be manipulating
1090
         * 3.  Do the operation on the data. */
1091
0
        switch (tree->type) {
1092
0
            case H5Z_XFORM_PLUS:
1093
0
                H5Z_XFORM_TYPE_OP(resl, resr, array_type, +, array_size)
1094
0
                break;
1095
1096
0
            case H5Z_XFORM_MINUS:
1097
0
                H5Z_XFORM_TYPE_OP(resl, resr, array_type, -, array_size)
1098
0
                break;
1099
1100
0
            case H5Z_XFORM_MULT:
1101
0
                H5Z_XFORM_TYPE_OP(resl, resr, array_type, *, array_size)
1102
0
                break;
1103
1104
0
            case H5Z_XFORM_DIVIDE:
1105
0
                H5Z_XFORM_TYPE_OP(resl, resr, array_type, /, array_size)
1106
0
                break;
1107
1108
0
            case H5Z_XFORM_ERROR:
1109
0
            case H5Z_XFORM_INTEGER:
1110
0
            case H5Z_XFORM_FLOAT:
1111
0
            case H5Z_XFORM_SYMBOL:
1112
0
            case H5Z_XFORM_LPAREN:
1113
0
            case H5Z_XFORM_RPAREN:
1114
0
            case H5Z_XFORM_END:
1115
0
            default:
1116
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid expression tree");
1117
0
        } /* end switch */
1118
1119
        /* The result stores a pointer to the new data */
1120
        /* So, if the left hand side got its data modified, the result stores a pointers
1121
         * to the left hand side's data, ditto for rhs */
1122
0
        if (resl.type == H5Z_XFORM_SYMBOL)
1123
0
            res->value.dat_val = resl.value.dat_val;
1124
0
        else if (resr.type == H5Z_XFORM_SYMBOL)
1125
0
            res->value.dat_val = resr.value.dat_val;
1126
0
        else
1127
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error during transform evaluation");
1128
0
    } /* end else */
1129
1130
0
done:
1131
0
    FUNC_LEAVE_NOAPI(ret_value)
1132
0
} /* end H5Z__xform_eval_full() */
1133
1134
/*-------------------------------------------------------------------------
1135
 * Function:    H5Z_find_type
1136
 *
1137
 * Return:      Native type of datatype that is passed in
1138
 *
1139
 *-------------------------------------------------------------------------
1140
 */
1141
static hid_t
1142
H5Z__xform_find_type(const H5T_t *type)
1143
0
{
1144
0
    H5T_t *tmp;                 /* Temporary datatype */
1145
0
    hid_t  ret_value = SUCCEED; /* Return value */
1146
1147
0
    FUNC_ENTER_PACKAGE
1148
1149
0
    assert(type);
1150
1151
    /* Check for SHORT type */
1152
0
    if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SHORT)) && 0 == H5T_cmp(type, tmp, false))
1153
0
        HGOTO_DONE(H5T_NATIVE_SHORT);
1154
    /* Check for INT type */
1155
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_INT)) && 0 == H5T_cmp(type, tmp, false))
1156
0
        HGOTO_DONE(H5T_NATIVE_INT);
1157
    /* Check for LONG type */
1158
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LONG)) && 0 == H5T_cmp(type, tmp, false))
1159
0
        HGOTO_DONE(H5T_NATIVE_LONG);
1160
    /* Check for LONGLONG type */
1161
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LLONG)) && 0 == H5T_cmp(type, tmp, false))
1162
0
        HGOTO_DONE(H5T_NATIVE_LLONG);
1163
    /* Check for UCHAR type */
1164
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UCHAR)) && 0 == H5T_cmp(type, tmp, false))
1165
0
        HGOTO_DONE(H5T_NATIVE_UCHAR);
1166
    /* Check for CHAR type */
1167
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_CHAR)) && 0 == H5T_cmp(type, tmp, false))
1168
0
        HGOTO_DONE(H5T_NATIVE_CHAR);
1169
    /* Check for SCHAR type */
1170
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SCHAR)) && 0 == H5T_cmp(type, tmp, false))
1171
0
        HGOTO_DONE(H5T_NATIVE_SCHAR);
1172
    /* Check for USHORT type */
1173
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_USHORT)) && 0 == H5T_cmp(type, tmp, false))
1174
0
        HGOTO_DONE(H5T_NATIVE_USHORT);
1175
    /* Check for UINT type */
1176
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UINT)) && 0 == H5T_cmp(type, tmp, false))
1177
0
        HGOTO_DONE(H5T_NATIVE_UINT);
1178
    /* Check for ULONG type */
1179
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULONG)) && 0 == H5T_cmp(type, tmp, false))
1180
0
        HGOTO_DONE(H5T_NATIVE_ULONG);
1181
    /* Check for ULONGLONG type */
1182
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULLONG)) && 0 == H5T_cmp(type, tmp, false))
1183
0
        HGOTO_DONE(H5T_NATIVE_ULLONG);
1184
    /* Check for FLOAT type */
1185
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT)) && 0 == H5T_cmp(type, tmp, false))
1186
0
        HGOTO_DONE(H5T_NATIVE_FLOAT);
1187
    /* Check for DOUBLE type */
1188
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE)) && 0 == H5T_cmp(type, tmp, false))
1189
0
        HGOTO_DONE(H5T_NATIVE_DOUBLE);
1190
    /* Check for LONGDOUBLE type */
1191
0
    else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LDOUBLE)) && 0 == H5T_cmp(type, tmp, false))
1192
0
        HGOTO_DONE(H5T_NATIVE_LDOUBLE);
1193
0
    else
1194
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not find matching type");
1195
1196
0
done:
1197
0
    FUNC_LEAVE_NOAPI(ret_value)
1198
0
} /* end H5Z__xform_find_type() */
1199
1200
/*-------------------------------------------------------------------------
1201
 * Function:    H5Z__xform_copy_tree
1202
 *
1203
 * Purpose:     Makes a copy of the parse tree passed in.
1204
 *
1205
 * Return:      A pointer to a root for a new parse tree which is a copy
1206
 *              of the one passed in.
1207
 *
1208
 *-------------------------------------------------------------------------
1209
 */
1210
static void *
1211
H5Z__xform_copy_tree(H5Z_node *tree, H5Z_datval_ptrs *dat_val_pointers, H5Z_datval_ptrs *new_dat_val_pointers)
1212
0
{
1213
0
    H5Z_node *ret_value = NULL;
1214
1215
0
    FUNC_ENTER_PACKAGE
1216
1217
0
    assert(tree);
1218
1219
0
    if (tree->type == H5Z_XFORM_INTEGER) {
1220
0
        if ((ret_value = (H5Z_node *)H5MM_malloc(sizeof(H5Z_node))) == NULL)
1221
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree");
1222
0
        else {
1223
0
            ret_value->type          = H5Z_XFORM_INTEGER;
1224
0
            ret_value->value.int_val = tree->value.int_val;
1225
0
            ret_value->lchild        = NULL;
1226
0
            ret_value->rchild        = NULL;
1227
0
        }
1228
0
    }
1229
0
    else if (tree->type == H5Z_XFORM_FLOAT) {
1230
0
        if ((ret_value = (H5Z_node *)H5MM_malloc(sizeof(H5Z_node))) == NULL)
1231
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree");
1232
0
        else {
1233
0
            ret_value->type            = H5Z_XFORM_FLOAT;
1234
0
            ret_value->value.float_val = tree->value.float_val;
1235
0
            ret_value->lchild          = NULL;
1236
0
            ret_value->rchild          = NULL;
1237
0
        }
1238
0
    }
1239
0
    else if (tree->type == H5Z_XFORM_SYMBOL) {
1240
0
        if ((ret_value = (H5Z_node *)H5MM_malloc(sizeof(H5Z_node))) == NULL)
1241
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree");
1242
0
        else {
1243
0
            ret_value->type = H5Z_XFORM_SYMBOL;
1244
1245
0
            ret_value->value.dat_val = &(new_dat_val_pointers->ptr_dat_val[new_dat_val_pointers->num_ptrs]);
1246
0
            new_dat_val_pointers->num_ptrs++;
1247
0
            ret_value->lchild = NULL;
1248
0
            ret_value->rchild = NULL;
1249
0
        }
1250
0
    }
1251
0
    else if (tree->type == H5Z_XFORM_MULT)
1252
0
        H5Z_XFORM_DO_OP4(H5Z_XFORM_MULT)
1253
0
    else if (tree->type == H5Z_XFORM_PLUS)
1254
0
        H5Z_XFORM_DO_OP4(H5Z_XFORM_PLUS)
1255
0
    else if (tree->type == H5Z_XFORM_MINUS)
1256
0
        H5Z_XFORM_DO_OP4(H5Z_XFORM_MINUS)
1257
0
    else if (tree->type == H5Z_XFORM_DIVIDE)
1258
0
        H5Z_XFORM_DO_OP4(H5Z_XFORM_DIVIDE)
1259
0
    else
1260
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error in parse tree while trying to copy");
1261
1262
0
done:
1263
0
    FUNC_LEAVE_NOAPI(ret_value)
1264
0
}
1265
1266
/*-------------------------------------------------------------------------
1267
 * Function:    H5Z__op_is_numbs
1268
 *
1269
 * Purpose:     Internal function to facilitate the condition check in
1270
 *              H5Z__xform_reduce_tree to reduce the bulkiness of the code.
1271
 *
1272
 * Return:      true or false
1273
 *
1274
 *-------------------------------------------------------------------------
1275
 */
1276
static bool
1277
H5Z__op_is_numbs(H5Z_node *_tree)
1278
0
{
1279
0
    bool ret_value = false;
1280
1281
0
    FUNC_ENTER_PACKAGE_NOERR
1282
1283
0
    assert(_tree);
1284
1285
0
    if (((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT)) &&
1286
0
        ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))
1287
0
        ret_value = true;
1288
1289
0
    FUNC_LEAVE_NOAPI(ret_value)
1290
0
}
1291
1292
/*-------------------------------------------------------------------------
1293
 * Function:    H5Z__op_is_numbs2
1294
 *
1295
 * Purpose:     Internal function to facilitate the condition check in
1296
 *              H5Z__xform_reduce_tree to reduce the bulkiness of the code.
1297
 *              The difference from H5Z__op_is_numbs is that the left child
1298
 *              can be empty, like -x or +x.
1299
 *
1300
 * Return:      true or false
1301
 *
1302
 *-------------------------------------------------------------------------
1303
 */
1304
static bool
1305
H5Z__op_is_numbs2(H5Z_node *_tree)
1306
0
{
1307
0
    bool ret_value = false;
1308
1309
0
    FUNC_ENTER_PACKAGE_NOERR
1310
1311
0
    assert(_tree);
1312
1313
0
    if ((!_tree->lchild &&
1314
0
         ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT))) ||
1315
0
        ((_tree->lchild &&
1316
0
          ((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT))) &&
1317
0
         (_tree->rchild &&
1318
0
          ((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))))
1319
0
        ret_value = true;
1320
1321
0
    FUNC_LEAVE_NOAPI(ret_value)
1322
0
}
1323
1324
/*-------------------------------------------------------------------------
1325
 * Function:    H5Z__xform_reduce_tree
1326
 *
1327
 * Purpose:     Simplifies parse tree passed in by performing any obvious
1328
 *              and trivial arithmetic calculations.
1329
 *
1330
 * Return:      None.
1331
 *
1332
 *-------------------------------------------------------------------------
1333
 */
1334
static void
1335
H5Z__xform_reduce_tree(H5Z_node *tree)
1336
0
{
1337
0
    FUNC_ENTER_PACKAGE_NOERR
1338
1339
0
    if (tree) {
1340
0
        if ((tree->type == H5Z_XFORM_DIVIDE) || (tree->type == H5Z_XFORM_MULT)) {
1341
0
            if (H5Z__op_is_numbs(tree))
1342
0
                H5Z__do_op(tree);
1343
0
            else {
1344
0
                H5Z__xform_reduce_tree(tree->lchild);
1345
0
                if (H5Z__op_is_numbs(tree))
1346
0
                    H5Z__do_op(tree);
1347
0
                else {
1348
0
                    H5Z__xform_reduce_tree(tree->rchild);
1349
0
                    if (H5Z__op_is_numbs(tree))
1350
0
                        H5Z__do_op(tree);
1351
0
                }
1352
0
            }
1353
0
        }
1354
0
        else if ((tree->type == H5Z_XFORM_PLUS) || (tree->type == H5Z_XFORM_MINUS)) {
1355
0
            if (H5Z__op_is_numbs2(tree))
1356
0
                H5Z__do_op(tree);
1357
0
            else {
1358
0
                H5Z__xform_reduce_tree(tree->lchild);
1359
0
                if (H5Z__op_is_numbs2(tree))
1360
0
                    H5Z__do_op(tree);
1361
0
                else {
1362
0
                    H5Z__xform_reduce_tree(tree->rchild);
1363
0
                    if (H5Z__op_is_numbs2(tree))
1364
0
                        H5Z__do_op(tree);
1365
0
                }
1366
0
            }
1367
0
        }
1368
0
    }
1369
1370
0
    FUNC_LEAVE_NOAPI_VOID
1371
0
}
1372
1373
/*-------------------------------------------------------------------------
1374
 * Function:    H5Z__do_op
1375
 *
1376
 * Purpose:     If the root of the tree passed in points to a simple
1377
 *              arithmetic operation and the left and right subtrees are both
1378
 *              integer or floating point values, this function does that
1379
 *              operation, free the left and right subtrees, and replaces
1380
 *              the root with the result of the operation.
1381
 *
1382
 * Return:      None.
1383
 *
1384
 *-------------------------------------------------------------------------
1385
 */
1386
static void
1387
H5Z__do_op(H5Z_node *tree)
1388
0
{
1389
0
    FUNC_ENTER_PACKAGE_NOERR
1390
1391
0
    if (tree->type == H5Z_XFORM_DIVIDE)
1392
0
        H5Z_XFORM_DO_OP3(/)
1393
0
    else if (tree->type == H5Z_XFORM_MULT)
1394
0
        H5Z_XFORM_DO_OP3(*)
1395
0
    else if (tree->type == H5Z_XFORM_PLUS)
1396
0
        H5Z_XFORM_DO_OP6(+)
1397
0
    else if (tree->type == H5Z_XFORM_MINUS)
1398
0
        H5Z_XFORM_DO_OP6(-)
1399
1400
0
    FUNC_LEAVE_NOAPI_VOID
1401
0
}
1402
1403
/*-------------------------------------------------------------------------
1404
 * Function: H5Z_xform_create
1405
 *
1406
 * Purpose: Create a new data transform object from a string.
1407
 *
1408
 * Return:
1409
 *      Success: SUCCEED
1410
 *      Failure: FAIL
1411
 *
1412
 *-------------------------------------------------------------------------
1413
 */
1414
H5Z_data_xform_t *
1415
H5Z_xform_create(const char *expr)
1416
0
{
1417
0
    H5Z_data_xform_t *data_xform_prop = NULL;
1418
0
    unsigned int      i;
1419
0
    unsigned int      count     = 0;
1420
0
    H5Z_data_xform_t *ret_value = NULL; /* Return value */
1421
1422
0
    FUNC_ENTER_NOAPI(NULL)
1423
1424
0
    assert(expr);
1425
1426
    /* Allocate space for the data transform information */
1427
0
    if (NULL == (data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
1428
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform info");
1429
1430
0
    if (NULL == (data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
1431
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
1432
0
                    "unable to allocate memory for data transform array storage");
1433
1434
    /* copy the user's string into the property */
1435
0
    if (NULL == (data_xform_prop->xform_exp = (char *)H5MM_xstrdup(expr)))
1436
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
1437
0
                    "unable to allocate memory for data transform expression");
1438
1439
    /* Find the number of times "x" is used in this equation, and allocate room for storing that many points
1440
     * A more sophisticated check is needed to support scientific notation.
1441
     */
1442
0
    for (i = 0; i < strlen(expr); i++) {
1443
0
        if (isalpha(expr[i])) {
1444
0
            if ((i > 0) && (i < (strlen(expr) - 1))) {
1445
0
                if (((expr[i] == 'E') || (expr[i] == 'e')) &&
1446
0
                    (isdigit(expr[i - 1]) || (expr[i - 1] == '.')) &&
1447
0
                    (isdigit(expr[i + 1]) || (expr[i + 1] == '-') || (expr[i + 1] == '+')))
1448
0
                    continue;
1449
0
            } /* end if */
1450
1451
0
            count++;
1452
0
        } /* end if */
1453
0
    }     /* end for */
1454
1455
    /* When there are no "x"'s in the equation (ie, simple transform case),
1456
     * we don't need to allocate any space since no array will have to be
1457
     * stored */
1458
0
    if (count > 0)
1459
0
        if (NULL ==
1460
0
            (data_xform_prop->dat_val_pointers->ptr_dat_val = (void **)H5MM_calloc(count * sizeof(void *))))
1461
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
1462
0
                        "unable to allocate memory for pointers in transform array");
1463
1464
    /* Initialize the num_ptrs field, which will be used to keep track of the number of copies
1465
     * of the data we have for polynomial transforms */
1466
0
    data_xform_prop->dat_val_pointers->num_ptrs = 0;
1467
1468
    /* we generate the parse tree right here and store a pointer to its root in the property. */
1469
0
    if ((data_xform_prop->parse_root =
1470
0
             (H5Z_node *)H5Z__xform_parse(expr, data_xform_prop->dat_val_pointers)) == NULL)
1471
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to generate parse tree from expression");
1472
1473
    /* Sanity check
1474
     * count should be the same num_ptrs */
1475
0
    if (count != data_xform_prop->dat_val_pointers->num_ptrs)
1476
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL,
1477
0
                    "error copying the parse tree, did not find correct number of \"variables\"");
1478
1479
    /* Assign return value */
1480
0
    ret_value = data_xform_prop;
1481
1482
0
done:
1483
    /* Clean up on error */
1484
0
    if (ret_value == NULL) {
1485
0
        if (data_xform_prop) {
1486
0
            if (data_xform_prop->parse_root)
1487
0
                H5Z__xform_destroy_parse_tree(data_xform_prop->parse_root);
1488
0
            if (data_xform_prop->xform_exp)
1489
0
                H5MM_xfree(data_xform_prop->xform_exp);
1490
0
            if (count > 0 && data_xform_prop->dat_val_pointers->ptr_dat_val)
1491
0
                H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
1492
0
            if (data_xform_prop->dat_val_pointers)
1493
0
                H5MM_xfree(data_xform_prop->dat_val_pointers);
1494
0
            H5MM_xfree(data_xform_prop);
1495
0
        } /* end if */
1496
0
    }     /* end if */
1497
1498
0
    FUNC_LEAVE_NOAPI(ret_value)
1499
0
} /* H5Z_xform_create() */
1500
1501
/*-------------------------------------------------------------------------
1502
 * Function: H5Z_xform_destroy
1503
 *
1504
 * Purpose: Destroy a data transform object.
1505
 *
1506
 * Return:
1507
 *      Success: SUCCEED
1508
 *      Failure: FAIL
1509
 *
1510
 *-------------------------------------------------------------------------
1511
 */
1512
herr_t
1513
H5Z_xform_destroy(H5Z_data_xform_t *data_xform_prop)
1514
2
{
1515
2
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1516
1517
0
    if (data_xform_prop) {
1518
        /* Destroy the parse tree */
1519
0
        H5Z__xform_destroy_parse_tree(data_xform_prop->parse_root);
1520
1521
        /* Free the expression */
1522
0
        H5MM_xfree(data_xform_prop->xform_exp);
1523
1524
        /* Free the pointers to the temp. arrays, if there are any */
1525
0
        if (data_xform_prop->dat_val_pointers->num_ptrs > 0)
1526
0
            H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
1527
1528
        /* Free the data storage struct */
1529
0
        H5MM_xfree(data_xform_prop->dat_val_pointers);
1530
1531
        /* Free the node */
1532
0
        H5MM_xfree(data_xform_prop);
1533
0
    } /* end if */
1534
1535
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1536
2
} /* H5Z_xform_destroy() */
1537
1538
/*-------------------------------------------------------------------------
1539
 * Function: H5Z_xform_copy
1540
 *
1541
 * Purpose: Clone a data transform object.
1542
 *
1543
 * Return:
1544
 *      Success: SUCCEED
1545
 *      Failure: FAIL
1546
 *
1547
 * Comments: This is an "in-place" copy, since this routine gets called
1548
 *      after the top-level copy has been performed and this routine finishes
1549
 *      the "deep" part of the copy.
1550
 *
1551
 *-------------------------------------------------------------------------
1552
 */
1553
herr_t
1554
H5Z_xform_copy(H5Z_data_xform_t **data_xform_prop)
1555
0
{
1556
0
    unsigned int      i;
1557
0
    unsigned int      count               = 0;
1558
0
    H5Z_data_xform_t *new_data_xform_prop = NULL;
1559
0
    herr_t            ret_value           = SUCCEED;
1560
1561
0
    FUNC_ENTER_NOAPI(FAIL)
1562
1563
0
    if (*data_xform_prop) {
1564
        /* Allocate new node */
1565
0
        if (NULL == (new_data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
1566
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform info");
1567
1568
        /* Copy string */
1569
0
        if (NULL == (new_data_xform_prop->xform_exp = (char *)H5MM_xstrdup((*data_xform_prop)->xform_exp)))
1570
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1571
0
                        "unable to allocate memory for data transform expression");
1572
1573
0
        if (NULL ==
1574
0
            (new_data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
1575
0
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1576
0
                        "unable to allocate memory for data transform array storage");
1577
1578
        /* Find the number of times "x" is used in this equation, and allocate room for storing that many
1579
         * points */
1580
0
        for (i = 0; i < strlen(new_data_xform_prop->xform_exp); i++)
1581
0
            if (isalpha(new_data_xform_prop->xform_exp[i]))
1582
0
                count++;
1583
1584
0
        if (count > 0)
1585
0
            if (NULL == (new_data_xform_prop->dat_val_pointers->ptr_dat_val =
1586
0
                             (void **)H5MM_calloc(count * sizeof(void *))))
1587
0
                HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
1588
0
                            "unable to allocate memory for pointers in transform array");
1589
1590
        /* Zero out num_pointers prior to H5Z_xform_cop_tree call; that call will increment it to the right
1591
         * amount */
1592
0
        new_data_xform_prop->dat_val_pointers->num_ptrs = 0;
1593
1594
        /* Copy parse tree */
1595
0
        if ((new_data_xform_prop->parse_root = (H5Z_node *)H5Z__xform_copy_tree(
1596
0
                 (*data_xform_prop)->parse_root, (*data_xform_prop)->dat_val_pointers,
1597
0
                 new_data_xform_prop->dat_val_pointers)) == NULL)
1598
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree");
1599
1600
        /* Sanity check
1601
         * count should be the same num_ptrs */
1602
0
        if (count != new_data_xform_prop->dat_val_pointers->num_ptrs)
1603
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL,
1604
0
                        "error copying the parse tree, did not find correct number of \"variables\"");
1605
1606
        /* Copy new information on top of old information */
1607
0
        *data_xform_prop = new_data_xform_prop;
1608
0
    } /* end if */
1609
1610
0
done:
1611
    /* Clean up on error */
1612
0
    if (ret_value < 0) {
1613
0
        if (new_data_xform_prop) {
1614
0
            if (new_data_xform_prop->parse_root)
1615
0
                H5Z__xform_destroy_parse_tree(new_data_xform_prop->parse_root);
1616
0
            if (new_data_xform_prop->xform_exp)
1617
0
                H5MM_xfree(new_data_xform_prop->xform_exp);
1618
0
            H5MM_xfree(new_data_xform_prop);
1619
0
        } /* end if */
1620
0
    }     /* end if */
1621
1622
0
    FUNC_LEAVE_NOAPI(ret_value)
1623
0
} /* H5Z_xform_copy() */
1624
1625
/*-------------------------------------------------------------------------
1626
 * Function: H5Z_xform_noop
1627
 *
1628
 * Purpose: Checks if a data transform will be performed
1629
 *
1630
 * Return:  true for no data transform, false for a data transform
1631
 *
1632
 * Comments: Can't fail
1633
 *
1634
 *-------------------------------------------------------------------------
1635
 */
1636
bool
1637
H5Z_xform_noop(const H5Z_data_xform_t *data_xform_prop)
1638
0
{
1639
0
    bool ret_value = true; /* Return value */
1640
1641
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1642
1643
0
    if (data_xform_prop) {
1644
0
        ret_value = false;
1645
1646
        /* Check for trivial data transformation: expression = "x" */
1647
0
        if ((strlen(data_xform_prop->xform_exp) == 1) && data_xform_prop->dat_val_pointers &&
1648
0
            (data_xform_prop->dat_val_pointers->num_ptrs == 1)) {
1649
0
            ret_value = true;
1650
0
        } /* end if */
1651
0
    }     /* end if */
1652
1653
0
    FUNC_LEAVE_NOAPI(ret_value)
1654
0
} /* H5Z_xform_noop() */
1655
1656
/*-------------------------------------------------------------------------
1657
 * Function: H5Z_xform_extract_xform_str
1658
 *
1659
 * Purpose: Extracts the pointer to the data transform strings from the
1660
 *              data transform property.`
1661
 * Return:
1662
 *          Pointer to a copy of the string in the data_xform property.
1663
 *
1664
 *-------------------------------------------------------------------------
1665
 */
1666
const char *
1667
H5Z_xform_extract_xform_str(const H5Z_data_xform_t *data_xform_prop)
1668
0
{
1669
0
    FUNC_ENTER_NOAPI_NOINIT_NOERR
1670
1671
    /* There should be no way that this can be NULL since the function
1672
     * that calls this one checks to make sure it isn't before
1673
     * passing them */
1674
0
    assert(data_xform_prop);
1675
1676
0
    FUNC_LEAVE_NOAPI(data_xform_prop->xform_exp)
1677
0
} /* H5Z_xform_extract_xform_str() */