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