Coverage Report

Created: 2023-11-19 06:19

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