66b6ae617a274e3d1e5e152308c294604e39a9e2
[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 val->i64 = zval_get_long(zv);
302 break;
303 case PSI_T_INT8:
304 val->i8 = zval_get_long(zv);
305 break;
306 case PSI_T_UINT8:
307 val->u8 = zval_get_long(zv);
308 break;
309 case PSI_T_INT16:
310 val->i16 = zval_get_long(zv);
311 break;
312 case PSI_T_UINT16:
313 val->u16 = zval_get_long(zv);
314 break;
315 case PSI_T_INT32:
316 val->i32 = zval_get_long(zv);
317 break;
318 case PSI_T_UINT32:
319 val->u32 = zval_get_long(zv);
320 break;
321 case PSI_T_INT64:
322 val->i64 = zval_get_long(zv);
323 break;
324 case PSI_T_UINT64:
325 val->u64 = zval_get_long(zv);
326 break;
327 case PSI_T_FLOAT:
328 val->fval = zval_get_double(zv);
329 break;
330 case PSI_T_DOUBLE:
331 val->dval = zval_get_double(zv);
332 break;
333 #ifdef HAVE_LONG_DOUBLE
334 case PSI_T_LONG_DOUBLE:
335 val->ldval = zval_get_double(zv);
336 break;
337 #endif
338 case PSI_T_ENUM:
339 val->ival = zval_get_long(zv);
340 break;
341 case PSI_T_STRUCT:
342 *tmp = *ptr = psi_array_to_struct(real->real.strct, HASH_OF(zv));
343 break;
344 case PSI_T_UNION:
345 *tmp = *ptr = psi_array_to_union(real->real.unn, HASH_OF(zv));
346 break;
347 case PSI_T_FUNCTION:
348 /*FIXME*/
349 val->ptr = NULL;
350 break;
351 case PSI_T_VOID:
352 val->ptr = NULL;
353 if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), psi_object_get_class_entry())) {
354 *ptr = PSI_OBJ(zv, NULL)->data;
355 } else {
356 zend_string *zs = zval_get_string(zv);
357 *tmp = val->ptr = estrndup(zs->val, zs->len);
358 zend_string_release(zs);
359 }
360 break;
361 }
362 }
363
364 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
365 {
366 size_t i, j = 0;
367 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
368
369 if (arr) for (i = 0; i < s->args->count; ++i) {
370 decl_arg *darg = s->args->args[i];
371 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
372
373 if (entry) {
374 impl_val val, *ptr = &val;
375 void *tmp = NULL;
376
377 memset(&val, 0, sizeof(val));
378 psi_from_zval_ex(&ptr, darg, /*FIXME*/0, entry, &tmp);
379 memcpy(mem + darg->layout->pos, ptr, darg->layout->len);
380 if (tmp) {
381 ((void **)(mem + s->size))[j++] = tmp;
382 }
383 }
384 }
385 return mem;
386 }
387
388 void *psi_array_to_union(decl_union *u, HashTable *arr) {
389 size_t i;
390 char *mem = ecalloc(1, u->size + sizeof(void *));
391
392 if (arr) for (i = 0; i < u->args->count; ++i) {
393 decl_arg *darg = u->args->args[i];
394 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
395
396 if (entry) {
397 impl_val val, *ptr = &val;
398 void *tmp = NULL;
399
400 memset(&val, 0, sizeof(val));
401 psi_from_zval_ex(&ptr, darg, /*FIXME*/0, entry, &tmp);
402 memcpy(mem, &val, darg->layout->len);
403 if (tmp) {
404 ((void **)(mem + u->size))[0] = tmp;
405 }
406 /* first found entry wins */
407 break;
408 }
409 }
410
411 return mem;
412 }
413
414 void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val)
415 {
416 set->outer.set->func->handler(return_value, set, r_val);
417 }
418
419 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
420 {
421 size_t i;
422 decl_var *var = set->vars->vars[0];
423 token_t t = real_decl_type(var->arg->type)->type;
424 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
425
426 if ((intptr_t) ret_val <= (intptr_t) 0) {
427 RETURN_NULL();
428 }
429
430 array_init(return_value);
431
432 if (t == PSI_T_STRUCT || t == PSI_T_UNION) {
433 // decl_struct *s = real_decl_type(var->arg->type)->strct;
434
435 if (set->inner && set->inner->count) {
436 /* explicit member casts */
437 for (i = 0; i < set->inner->count; ++i) {
438 set_value *sub_set = set->inner->vals[i];
439 decl_var *sub_var = sub_set->vars->vars[0];
440
441 sub_set->outer.val = ret_val;
442
443 if (sub_var->arg) {
444 impl_val *tmp = NULL, *val;
445 zval ztmp;
446
447 val = struct_member_ref(sub_var->arg, ret_val, &tmp);
448 sub_set->func->handler(&ztmp, sub_set, val);
449 add_assoc_zval(return_value, sub_var->name, &ztmp);
450
451 if (tmp) {
452 free(tmp);
453 }
454 }
455 }
456 return;
457 }
458 }
459
460 if (var->arg->var->array_size) {
461 /* to_array(foo[NUMBER]) */
462 for (i = 0; i < var->arg->var->array_size; ++i) {
463 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
464 impl_val *ptr = iterate(ret_val, size, i, &tmp);
465 zval ele;
466
467 switch (t) {
468 case PSI_T_FLOAT:
469 ZVAL_DOUBLE(&ele, (double) ptr->fval);
470 break;
471 case PSI_T_DOUBLE:
472 ZVAL_DOUBLE(&ele, ptr->dval);
473 break;
474 default:
475 ZVAL_LONG(&ele, ptr->lval);
476 break;
477 }
478
479 add_next_index_zval(return_value, &ele);
480 }
481 return;
482 } else if (set->num) {
483 /* to_array(arr_var, num_expr, to_int(*arr_var)) */
484 zval ele;
485 char *ptr;
486 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
487 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
488 set_value *sub_set = set->inner->vals[0];
489
490 sub_set->outer.val = set->outer.val;
491 for (i = 0; i < n; ++i) {
492 ptr = (char *) ret_val->ptr + i * size;
493 sub_set->func->handler(&ele, sub_set, (void *) ptr);
494 add_next_index_zval(return_value, &ele);
495 }
496 } else {
497 /* to_array(arr_var, to_int(*arr_var)) */
498 zval ele;
499 char *ptr = ret_val->ptr;
500 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
501 set_value *sub_set = set->inner->vals[0];
502
503 sub_set->outer.val = set->outer.val;
504 while (*(void **) ptr) {
505 sub_set->func->handler(&ele, sub_set, (void *) ptr);
506 add_next_index_zval(return_value, &ele);
507 ptr += size;
508 }
509 }
510 }
511
512 impl_val *psi_let_arrval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
513 {
514 decl_type *real = real_decl_type(type);
515 HashTable *arr;
516
517 if (iarg->type->type != PSI_T_ARRAY) {
518 SEPARATE_ARG_IF_REF(iarg->_zv);
519 convert_to_array(iarg->_zv);
520 }
521 arr = HASH_OF(iarg->_zv);
522
523 switch (real->type) {
524 case PSI_T_STRUCT:
525 *to_free = tmp = psi_array_to_struct(real->real.strct, arr);
526 break;
527 case PSI_T_UNION:
528 *to_free = tmp = psi_array_to_union(real->real.unn, arr);
529 break;
530 EMPTY_SWITCH_DEFAULT_CASE();
531 }
532
533 return tmp;
534 }
535
536 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
537 {
538 decl_var *var = set->vars->vars[0];
539 impl_val *ret_val = deref_impl_val(r_val, var);
540
541 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
542 object_init_ex(return_value, psi_object_get_class_entry());
543 PSI_OBJ(return_value, NULL)->data = ret_val->ptr;
544 } else {
545 RETVAL_NULL();
546 }
547 }
548
549 impl_val *psi_let_objval(impl_val *tmp, decl_type *type, impl_arg *iarg, void **to_free)
550 {
551 psi_object *obj;
552
553 if (Z_TYPE_P(iarg->_zv) != IS_OBJECT
554 || !instanceof_function(Z_OBJCE_P(iarg->_zv), psi_object_get_class_entry())) {
555 return NULL;
556 }
557
558 obj = PSI_OBJ(iarg->_zv, NULL);
559 tmp->ptr = obj->data;
560
561 return tmp;
562 }
563