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