inner let vals
[m6w6/ext-psi] / src / marshal.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6 #include "php_psi.h"
7 #include "parser.h"
8 #include "marshal.h"
9 #include "calc.h"
10
11 void psi_to_void(zval *return_value, set_value *set, impl_val *ret_val)
12 {
13 RETVAL_NULL();
14 }
15
16 impl_val *psi_let_void(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free) {
17 return tmp;
18 }
19
20 void psi_to_zval(zval *return_value, set_value *set, impl_val *ret_val) {
21 RETVAL_ZVAL(ret_val->ptr, 1, 0);
22 }
23
24 impl_val *psi_let_zval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
25 {
26 *to_free = tmp->ptr = emalloc(sizeof(zval));
27 ZVAL_COPY_VALUE(tmp->ptr, iarg->_zv);
28 return tmp;
29 }
30
31 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
32 {
33 psi_to_int(return_value, set, ret_val);
34 convert_to_boolean(return_value);
35 }
36
37 static inline impl_val *psi_val_boolval(impl_val *tmp, token_t real_type, zend_bool boolval) {
38 switch (real_type) {
39 case PSI_T_INT8: tmp->i8 = boolval; break;
40 case PSI_T_UINT8: tmp->u8 = boolval; break;
41 case PSI_T_INT16: tmp->i16 = boolval; break;
42 case PSI_T_UINT16: tmp->u16 = boolval; break;
43 case PSI_T_INT32: tmp->i32 = boolval; break;
44 case PSI_T_UINT32: tmp->u32 = boolval; break;
45 case PSI_T_INT64: tmp->i64 = boolval; break;
46 case PSI_T_UINT64: tmp->u64 = boolval; break;
47 case PSI_T_FLOAT: tmp->fval = boolval; break;
48 case PSI_T_DOUBLE: tmp->dval = boolval; break;
49 #ifdef HAVE_LONG_DOUBLE
50 case PSI_T_LONG_DOUBLE: tmp->ldval = boolval; break;
51 #endif
52 EMPTY_SWITCH_DEFAULT_CASE();
53 }
54 return tmp;
55 }
56
57 impl_val *psi_let_boolval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
58 {
59 zend_bool boolval;
60 token_t real_type = type ? real_decl_type(type)->type : PSI_T_UINT8;
61
62 if (iarg->type->type == PSI_T_BOOL) {
63 boolval = iarg->val.zend.bval;
64 } else {
65 boolval = zend_is_true(iarg->_zv);
66 }
67
68 return psi_val_boolval(tmp, real_type, boolval);
69 }
70
71 # define RETVAL_LONG_U64(V) \
72 if (V > ZEND_LONG_MAX) { \
73 char d[24] = {0}; \
74 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], V)); \
75 } else { \
76 RETVAL_LONG(V); \
77 }
78
79 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
80 {
81 decl_var *var = set->vars->vars[0];
82 token_t t = real_decl_type(var->arg->type)->type;
83 impl_val *v = deref_impl_val(ret_val, var);
84
85 switch (t) {
86 case PSI_T_INT8: RETVAL_LONG(v->i8); break;
87 case PSI_T_UINT8: RETVAL_LONG(v->u8); break;
88 case PSI_T_INT16: RETVAL_LONG(v->i16); break;
89 case PSI_T_UINT16: RETVAL_LONG(v->u16); break;
90 case PSI_T_INT32: RETVAL_LONG(v->i32); break;
91 case PSI_T_UINT32: RETVAL_LONG(v->u32); break;
92 case PSI_T_INT64: RETVAL_LONG(v->i64); break;
93 case PSI_T_UINT64: RETVAL_LONG_U64(v->u64); break;
94 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
95 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
96 #ifdef HAVE_LONG_DOUBLE
97 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
98 #endif
99 EMPTY_SWITCH_DEFAULT_CASE();
100 }
101
102 convert_to_long(return_value);
103 }
104
105 static inline impl_val *psi_val_intval(impl_val *tmp, token_t real_type, zend_long intval) {
106 switch (real_type) {
107 case PSI_T_INT8: tmp->i8 = intval; break;
108 case PSI_T_UINT8: tmp->u8 = intval; break;
109 case PSI_T_INT16: tmp->i16 = intval; break;
110 case PSI_T_UINT16: tmp->u16 = intval; break;
111 case PSI_T_INT32: tmp->i32 = intval; break;
112 case PSI_T_UINT32: tmp->u32 = intval; break;
113 case PSI_T_INT64: tmp->i64 = intval; break;
114 case PSI_T_UINT64: tmp->u64 = intval; break;
115 case PSI_T_INT: tmp->ival = intval; break;
116 case PSI_T_LONG: tmp->lval = intval; break;
117 case PSI_T_FLOAT: tmp->fval = intval; break;
118 case PSI_T_DOUBLE: tmp->dval = intval; break;
119 #ifdef HAVE_LONG_DOUBLE
120 case PSI_T_LONG_DOUBLE: tmp->ldval = intval; break;
121 #endif
122 EMPTY_SWITCH_DEFAULT_CASE();
123 }
124
125 return tmp;
126 }
127
128 impl_val *psi_let_intval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
129 {
130 zend_long intval;
131 token_t real_type = type ? real_decl_type(type)->type : PSI_T_LONG;
132
133 if (iarg->type->type == PSI_T_INT) {
134 intval = iarg->val.zend.lval;
135 } else {
136 intval = zval_get_long(iarg->_zv);
137 }
138
139 return psi_val_intval(tmp, real_type, intval);
140 }
141
142 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
143 {
144 decl_var *var = set->vars->vars[0];
145 token_t t = real_decl_type(var->arg->type)->type;
146 impl_val *v = deref_impl_val(ret_val, var);
147
148 switch (t) {
149 case PSI_T_FLOAT: RETVAL_DOUBLE((double) v->fval); break;
150 case PSI_T_DOUBLE: RETVAL_DOUBLE(v->dval); break;
151 #ifdef HAVE_LONG_DOUBLE
152 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) v->ldval); break;
153 #endif
154 case PSI_T_INT8: RETVAL_DOUBLE((double) v->i8); break;
155 case PSI_T_UINT8: RETVAL_DOUBLE((double) v->u8); break;
156 case PSI_T_INT16: RETVAL_DOUBLE((double) v->i16); break;
157 case PSI_T_UINT16: RETVAL_DOUBLE((double) v->u16); break;
158 case PSI_T_INT32: RETVAL_DOUBLE((double) v->i32); break;
159 case PSI_T_UINT32: RETVAL_DOUBLE((double) v->u32); break;
160 case PSI_T_INT64: RETVAL_DOUBLE((double) v->i64); break;
161 case PSI_T_UINT64: RETVAL_DOUBLE((double) v->u64); break;
162 EMPTY_SWITCH_DEFAULT_CASE();
163 }
164 }
165
166 static inline impl_val *psi_val_floatval(impl_val *tmp, token_t real_type, double floatval) {
167 switch (real_type) {
168 case PSI_T_INT8: tmp->i8 = floatval; break;
169 case PSI_T_UINT8: tmp->u8 = floatval; break;
170 case PSI_T_INT16: tmp->i16 = floatval; break;
171 case PSI_T_UINT16: tmp->u16 = floatval; break;
172 case PSI_T_INT32: tmp->i32 = floatval; break;
173 case PSI_T_UINT32: tmp->u32 = floatval; break;
174 case PSI_T_INT64: tmp->i64 = floatval; break;
175 case PSI_T_UINT64: tmp->u64 = floatval; break;
176 case PSI_T_FLOAT: tmp->fval = floatval; break;
177 case PSI_T_DOUBLE: tmp->dval = floatval; break;
178 #ifdef HAVE_LONG_DOUBLE
179 case PSI_T_LONG_DOUBLE: tmp->ldval = floatval; break;
180 #endif
181 EMPTY_SWITCH_DEFAULT_CASE();
182 }
183
184 return tmp;
185 }
186
187 impl_val *psi_let_floatval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
188 {
189 double floatval;
190 token_t real_type = type ? real_decl_type(type)->type : PSI_T_DOUBLE;
191
192 if (iarg->type->type == PSI_T_FLOAT || iarg->type->type == PSI_T_DOUBLE) {
193 floatval = iarg->val.dval;
194 } else {
195 floatval = zval_get_double(iarg->_zv);
196 }
197
198 return psi_val_floatval(tmp, real_type, floatval);
199 }
200
201 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
202 {
203 char *str;
204 decl_var *var = set->vars->vars[0];
205 token_t t = real_decl_type(var->arg->type)->type;
206
207 switch (t) {
208 case PSI_T_FLOAT: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval); break;
209 case PSI_T_DOUBLE: RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval); break;
210 #ifdef HAVE_LONG_DOUBLE
211 case PSI_T_LONG_DOUBLE: RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval); break;
212 #endif
213 default:
214 if (!var->arg->var->pointer_level) {
215 RETVAL_STRINGL(&ret_val->cval, 1);
216 } else {
217 ret_val = deref_impl_val(ret_val, var);
218 if (var->arg->var->array_size) {
219 str = (char *) ret_val;
220 } else {
221 str = ret_val->ptr;
222 }
223 if (str) {
224 if (set->num) {
225 zend_long n = psi_long_num_exp(set->num, set->outer.val);
226 RETVAL_STRINGL(str, n);
227 } else {
228 RETVAL_STRING(str);
229 }
230 } else {
231 RETVAL_EMPTY_STRING();
232 }
233 }
234 return;
235 }
236
237 convert_to_string(return_value);
238 }
239
240 impl_val *psi_let_strval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
241 {
242 if (iarg->type->type == PSI_T_STRING) {
243 if (iarg->val.zend.str) {
244 tmp->ptr = estrndup(iarg->val.zend.str->val, iarg->val.zend.str->len);
245 *to_free = tmp->ptr;
246 } else {
247 tmp->ptr = "";
248 }
249 } else {
250 zend_string *zs = zval_get_string(iarg->_zv);
251 tmp->ptr = estrdup(zs->val);
252 *to_free = tmp->ptr;
253 zend_string_release(zs);
254 }
255
256 return tmp;
257 }
258
259 impl_val *psi_let_pathval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
260 {
261 tmp = psi_let_strval(tmp, type, iarg, to_free);
262 if (SUCCESS != php_check_open_basedir(tmp->ptr)) {
263 efree(tmp->ptr);
264 return *to_free = NULL;
265 }
266 return tmp;
267 }
268
269 impl_val *psi_let_strlen(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
270 {
271 if (iarg->type->type == PSI_T_STRING) {
272 if (iarg->val.zend.str) {
273 tmp->lval = iarg->val.zend.str->len;
274 } else {
275 tmp->lval = 0;
276 }
277 } else {
278 zend_string *zs = zval_get_string(iarg->_zv);
279 tmp->lval = zs->len;
280 zend_string_release(zs);
281 }
282
283 return tmp;
284 }
285
286 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
287 {
288 memset(tmp, 0, sizeof(*tmp));
289 memcpy(tmp, ((void*) val) + size * i, size);
290 return tmp;
291 }
292
293 void psi_from_zval_ex(impl_val **ptr, decl_arg *spec, token_t cast, zval *zv, void **tmp)
294 {
295 decl_type *real = real_decl_type(spec->type);
296 impl_val *val = *ptr;
297
298 switch (real->type) {
299 default:
300 ZEND_ASSERT(0);
301 /* no break */
302 case PSI_T_INT8:
303 val->i8 = zval_get_long(zv);
304 break;
305 case PSI_T_UINT8:
306 val->u8 = zval_get_long(zv);
307 break;
308 case PSI_T_INT16:
309 val->i16 = zval_get_long(zv);
310 break;
311 case PSI_T_UINT16:
312 val->u16 = zval_get_long(zv);
313 break;
314 case PSI_T_INT32:
315 val->i32 = zval_get_long(zv);
316 break;
317 case PSI_T_UINT32:
318 val->u32 = zval_get_long(zv);
319 break;
320 case PSI_T_INT64:
321 val->i64 = zval_get_long(zv);
322 break;
323 case PSI_T_UINT64:
324 val->u64 = zval_get_long(zv);
325 break;
326 case PSI_T_FLOAT:
327 val->fval = zval_get_double(zv);
328 break;
329 case PSI_T_DOUBLE:
330 val->dval = zval_get_double(zv);
331 break;
332 #ifdef HAVE_LONG_DOUBLE
333 case PSI_T_LONG_DOUBLE:
334 val->ldval = zval_get_double(zv);
335 break;
336 #endif
337 case PSI_T_ENUM:
338 val->ival = zval_get_long(zv);
339 break;
340 case PSI_T_STRUCT:
341 *tmp = *ptr = psi_array_to_struct(real->real.strct, HASH_OF(zv));
342 break;
343 }
344 }
345
346 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
347 {
348 decl_type *type = real_decl_type(spec->type);
349
350 switch (type->type) {
351 case PSI_T_FLOAT:
352 mem->fval = (float) zval_get_double(zv);
353 break;
354 case PSI_T_DOUBLE:
355 mem->dval = zval_get_double(zv);
356 break;
357 case PSI_T_VOID:
358 case PSI_T_INT8:
359 case PSI_T_UINT8:
360 if (spec->var->pointer_level) {
361 zend_string *zs = zval_get_string(zv);
362 *tmp = mem->ptr = estrndup(zs->val, zs->len);
363 zend_string_release(zs);
364 break;
365 }
366 /* no break */
367 default:
368 mem->zend.lval = zval_get_long(zv);
369 break;
370 }
371 }
372
373 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
374 {
375 size_t i, j = 0;
376 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
377
378 if (arr) for (i = 0; i < s->args->count; ++i) {
379 decl_arg *darg = s->args->args[i];
380 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
381
382 if (entry) {
383 impl_val val;
384 void *tmp = NULL;
385
386 memset(&tmp, 0, sizeof(tmp));
387 psi_from_zval(&val, darg, entry, &tmp);
388 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
389 if (tmp) {
390 ((void **)(mem + s->size))[j++] = tmp;
391 }
392 }
393 }
394 return mem;
395 }
396
397 void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val)
398 {
399 set->outer.set->func->handler(return_value, set, r_val);
400 }
401
402 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
403 {
404 size_t i;
405 decl_var *var = set->vars->vars[0];
406 token_t t = real_decl_type(var->arg->type)->type;
407 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
408
409 if ((intptr_t) ret_val <= (intptr_t) 0) {
410 RETURN_NULL();
411 }
412
413 array_init(return_value);
414
415 if (t == PSI_T_STRUCT) {
416 // decl_struct *s = real_decl_type(var->arg->type)->strct;
417
418 if (set->inner && set->inner->count) {
419 /* explicit member casts */
420 for (i = 0; i < set->inner->count; ++i) {
421 set_value *sub_set = set->inner->vals[i];
422 decl_var *sub_var = sub_set->vars->vars[0];
423
424 sub_set->outer.val = ret_val;
425
426 if (sub_var->arg) {
427 impl_val *tmp = NULL, *val;
428 zval ztmp;
429
430 val = struct_member_ref(sub_var->arg, ret_val, &tmp);
431 sub_set->func->handler(&ztmp, sub_set, val);
432 add_assoc_zval(return_value, sub_var->name, &ztmp);
433
434 if (tmp) {
435 free(tmp);
436 }
437 }
438 }
439 }
440 return;
441 }
442
443 if (var->arg->var->array_size) {
444 /* to_array(foo[NUMBER]) */
445 for (i = 0; i < var->arg->var->array_size; ++i) {
446 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
447 impl_val *ptr = iterate(ret_val, size, i, &tmp);
448 zval ele;
449
450 switch (t) {
451 case PSI_T_FLOAT:
452 ZVAL_DOUBLE(&ele, (double) ptr->fval);
453 break;
454 case PSI_T_DOUBLE:
455 ZVAL_DOUBLE(&ele, ptr->dval);
456 break;
457 default:
458 ZVAL_LONG(&ele, ptr->lval);
459 break;
460 }
461
462 add_next_index_zval(return_value, &ele);
463 }
464 return;
465 } else if (set->num) {
466 /* to_array(arr_var, num_expr, to_int(*arr_var)) */
467 zval ele;
468 char *ptr;
469 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
470 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
471 set_value *sub_set = set->inner->vals[0];
472
473 sub_set->outer.val = set->outer.val;
474 for (i = 0; i < n; ++i) {
475 ptr = (char *) ret_val->ptr + i * size;
476 sub_set->func->handler(&ele, sub_set, (void *) ptr);
477 add_next_index_zval(return_value, &ele);
478 }
479 } else {
480 /* to_array(arr_var, to_int(*arr_var)) */
481 zval ele;
482 char *ptr = ret_val->ptr;
483 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
484 set_value *sub_set = set->inner->vals[0];
485
486 sub_set->outer.val = set->outer.val;
487 while (*(void **) ptr) {
488 sub_set->func->handler(&ele, sub_set, (void *) ptr);
489 add_next_index_zval(return_value, &ele);
490 ptr += size;
491 }
492 }
493 }
494
495 impl_val *psi_let_arrval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
496 {
497 decl_type *real = real_decl_type(type);
498 HashTable *arr;
499
500 if (iarg->type->type != PSI_T_ARRAY) {
501 SEPARATE_ARG_IF_REF(iarg->_zv);
502 convert_to_array(iarg->_zv);
503 }
504 arr = HASH_OF(iarg->_zv);
505
506 switch (real->type) {
507 case PSI_T_STRUCT:
508 *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
509 break;
510 EMPTY_SWITCH_DEFAULT_CASE();
511 }
512
513 return tmp;
514 }
515
516 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
517 {
518 decl_var *var = set->vars->vars[0];
519 impl_val *ret_val = deref_impl_val(r_val, var);
520 psi_object *obj;
521
522 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
523 object_init_ex(return_value, psi_object_get_class_entry());
524 obj = PSI_OBJ(return_value, NULL);
525 obj->data = ret_val->ptr;
526 } else {
527 RETVAL_NULL();
528 }
529 }
530
531 impl_val *psi_let_objval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
532 {
533 psi_object *obj;
534
535 if (Z_TYPE_P(iarg->_zv) != IS_OBJECT
536 || !instanceof_function(Z_OBJCE_P(iarg->_zv), psi_object_get_class_entry())) {
537 return NULL;
538 }
539
540 obj = PSI_OBJ(iarg->_zv, NULL);
541 tmp->ptr = obj->data;
542
543 return tmp;
544 }
545