flush
[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
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 void psi_to_bool(zval *return_value, set_value *set, impl_val *ret_val)
17 {
18 psi_to_int(return_value, set, ret_val);
19 convert_to_boolean(return_value);
20 }
21
22 void psi_to_int(zval *return_value, set_value *set, impl_val *ret_val)
23 {
24 decl_var *var = set->vars->vars[0];
25 token_t t = real_decl_type(var->arg->type)->type;
26 impl_val *v = deref_impl_val(ret_val, var);
27
28 switch (t) {
29 case PSI_T_FLOAT:
30 RETVAL_DOUBLE((double) v->fval);
31 convert_to_long(return_value);
32 break;
33 case PSI_T_DOUBLE:
34 RETVAL_DOUBLE(v->dval);
35 convert_to_long(return_value);
36 break;
37 case PSI_T_INT8:
38 RETVAL_LONG(v->i8);
39 break;
40 case PSI_T_UINT8:
41 RETVAL_LONG(v->u8);
42 break;
43 case PSI_T_INT16:
44 RETVAL_LONG(v->i16);
45 break;
46 case PSI_T_UINT16:
47 RETVAL_LONG(v->u16);
48 break;
49 case PSI_T_INT32:
50 RETVAL_LONG(v->i32);
51 break;
52 case PSI_T_UINT32:
53 #if UINT32_MAX >= ZEND_LONG_MAX
54 if (v->u32 > ZEND_LONG_MAX) {
55 char d[12] = {0};
56
57 RETVAL_STRING(zend_print_ulong_to_buf(&d[10], v->u32));
58 } else {
59 #endif
60 RETVAL_LONG(v->u32);
61 #if UINT32_MAX >= ZEND_LONG_MAX
62 }
63 #endif
64 break;
65 case PSI_T_INT64:
66 RETVAL_LONG(v->i64);
67 break;
68 case PSI_T_UINT64:
69 if (v->u64 > ZEND_LONG_MAX) {
70 char d[24] = {0};
71
72 RETVAL_STRING(zend_print_ulong_to_buf(&d[22], v->u64));
73 } else {
74 RETVAL_LONG(v->u64);
75 }
76 break;
77 EMPTY_SWITCH_DEFAULT_CASE();
78 }
79 }
80
81 void psi_to_double(zval *return_value, set_value *set, impl_val *ret_val)
82 {
83 decl_var *var = set->vars->vars[0];
84 token_t t = real_decl_type(var->arg->type)->type;
85 impl_val *v = deref_impl_val(ret_val, var);
86
87 switch (t) {
88 case PSI_T_FLOAT:
89 RETVAL_DOUBLE((double) v->fval);
90 break;
91 case PSI_T_DOUBLE:
92 RETVAL_DOUBLE(v->dval);
93 break;
94 #ifdef HAVE_LONG_DOUBLE
95 case PSI_T_LONG_DOUBLE:
96 RETVAL_DOUBLE((double) v->ldval);
97 break;
98 #endif
99 case PSI_T_INT8:
100 RETVAL_DOUBLE((double) v->i8);
101 break;
102 case PSI_T_UINT8:
103 RETVAL_DOUBLE((double) v->u8);
104 break;
105 case PSI_T_INT16:
106 RETVAL_DOUBLE((double) v->i16);
107 break;
108 case PSI_T_UINT16:
109 RETVAL_DOUBLE((double) v->u16);
110 break;
111 case PSI_T_INT32:
112 RETVAL_DOUBLE((double) v->i32);
113 break;
114 case PSI_T_UINT32:
115 RETVAL_DOUBLE((double) v->u32);
116 break;
117 case PSI_T_INT64:
118 RETVAL_DOUBLE((double) v->i64);
119 break;
120 case PSI_T_UINT64:
121 RETVAL_DOUBLE((double) v->u64);
122 break;
123 EMPTY_SWITCH_DEFAULT_CASE();
124 }
125 }
126
127 void psi_to_string(zval *return_value, set_value *set, impl_val *ret_val)
128 {
129 char *str;
130 decl_var *var = set->vars->vars[0];
131 token_t t = real_decl_type(var->arg->type)->type;
132
133 switch (t) {
134 case PSI_T_FLOAT:
135 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
136 break;
137 case PSI_T_DOUBLE:
138 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
139 break;
140 #ifdef HAVE_LONG_DOUBLE
141 case PSI_T_LONG_DOUBLE:
142 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->ldval);
143 break;
144 #endif
145 default:
146 if (!var->arg->var->pointer_level) {
147 RETVAL_STRINGL(&ret_val->cval, 1);
148 } else {
149 ret_val = deref_impl_val(ret_val, var);
150 if (var->arg->var->array_size) {
151 str = (char *) ret_val;
152 } else {
153 str = ret_val->ptr;
154 }
155 if (str) {
156 if (set->num) {
157 zend_long n = psi_long_num_exp(set->num, set->outer.val);
158 RETVAL_STRINGL(str, n);
159 } else {
160 RETVAL_STRING(str);
161 }
162 } else {
163 RETVAL_EMPTY_STRING();
164 }
165 }
166 return;
167 }
168 convert_to_string(return_value);
169 }
170
171
172 static impl_val *iterate(impl_val *val, size_t size, unsigned i, impl_val *tmp)
173 {
174 memset(tmp, 0, sizeof(*tmp));
175 memcpy(tmp, ((void*) val) + size * i, size);
176 return tmp;
177 }
178
179 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
180 {
181 decl_type *type = real_decl_type(spec->type);
182
183 switch (type->type) {
184 case PSI_T_FLOAT:
185 mem->fval = (float) zval_get_double(zv);
186 break;
187 case PSI_T_DOUBLE:
188 mem->dval = zval_get_double(zv);
189 break;
190 case PSI_T_VOID:
191 case PSI_T_INT8:
192 case PSI_T_UINT8:
193 if (spec->var->pointer_level) {
194 zend_string *zs = zval_get_string(zv);
195 *tmp = mem->ptr = estrndup(zs->val, zs->len);
196 zend_string_release(zs);
197 break;
198 }
199 /* no break */
200 default:
201 mem->zend.lval = zval_get_long(zv);
202 break;
203 }
204 }
205
206 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
207 {
208 size_t i, j = 0;
209 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
210
211 if (arr) for (i = 0; i < s->args->count; ++i) {
212 decl_arg *darg = s->args->args[i];
213 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
214
215 if (entry) {
216 impl_val val;
217 void *tmp = NULL;
218
219 memset(&tmp, 0, sizeof(tmp));
220 psi_from_zval(&val, darg, entry, &tmp);
221 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
222 if (tmp) {
223 ((void **)(mem + s->size))[j++] = tmp;
224 }
225 }
226 }
227 return mem;
228 }
229
230 void psi_to_recursive(zval *return_value, set_value *set, impl_val *r_val)
231 {
232 set->outer.set->func->handler(return_value, set, r_val);
233 }
234
235 void psi_to_array(zval *return_value, set_value *set, impl_val *r_val)
236 {
237 size_t i;
238 decl_var *var = set->vars->vars[0];
239 token_t t = real_decl_type(var->arg->type)->type;
240 impl_val tmp, *ret_val = deref_impl_val(r_val, var);
241
242 if ((intptr_t) ret_val <= (intptr_t) 0) {
243 RETURN_NULL();
244 }
245
246 array_init(return_value);
247
248 if (t == PSI_T_STRUCT) {
249 // decl_struct *s = real_decl_type(var->arg->type)->strct;
250
251 if (set->inner && set->inner->count) {
252 /* explicit member casts */
253 for (i = 0; i < set->inner->count; ++i) {
254 set_value *sub_set = set->inner->vals[i];
255 decl_var *sub_var = sub_set->vars->vars[0];
256
257 sub_set->outer.val = ret_val;
258
259 if (sub_var->arg) {
260 impl_val *tmp = NULL, *val;
261 zval ztmp;
262
263 val = struct_member_ref(sub_var->arg, ret_val, &tmp);
264 sub_set->func->handler(&ztmp, sub_set, val);
265 add_assoc_zval(return_value, sub_var->name, &ztmp);
266
267 if (tmp) {
268 free(tmp);
269 }
270 }
271 }
272 }
273 return;
274 }
275
276 if (var->arg->var->array_size) {
277 /* to_array(foo[NUMBER]) */
278 for (i = 0; i < var->arg->var->array_size; ++i) {
279 size_t size = psi_t_size(var->arg->var->pointer_level > 1 ? PSI_T_POINTER : t);
280 impl_val *ptr = iterate(ret_val, size, i, &tmp);
281 zval ele;
282
283 switch (t) {
284 case PSI_T_FLOAT:
285 ZVAL_DOUBLE(&ele, (double) ptr->fval);
286 break;
287 case PSI_T_DOUBLE:
288 ZVAL_DOUBLE(&ele, ptr->dval);
289 break;
290 default:
291 ZVAL_LONG(&ele, ptr->lval);
292 break;
293 }
294
295 add_next_index_zval(return_value, &ele);
296 }
297 return;
298 } else if (set->num) {
299 /* to_array(arr_var, num_expr, to_int(*arr_var)) */
300 zval ele;
301 char *ptr;
302 zend_long i, n = psi_long_num_exp(set->num, set->outer.val);
303 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
304 set_value *sub_set = set->inner->vals[0];
305
306 sub_set->outer.val = set->outer.val;
307 for (i = 0; i < n; ++i) {
308 ptr = (char *) ret_val->ptr + i * size;
309 sub_set->func->handler(&ele, sub_set, (void *) ptr);
310 add_next_index_zval(return_value, &ele);
311 }
312 } else {
313 /* to_array(arr_var, to_int(*arr_var)) */
314 zval ele;
315 char *ptr = ret_val->ptr;
316 size_t size = psi_t_size(var->arg->var->pointer_level ? PSI_T_POINTER : t);
317 set_value *sub_set = set->inner->vals[0];
318
319 sub_set->outer.val = set->outer.val;
320 while (*(void **) ptr) {
321 sub_set->func->handler(&ele, sub_set, (void *) ptr);
322 add_next_index_zval(return_value, &ele);
323 ptr += size;
324 }
325 }
326 }
327
328 void psi_to_object(zval *return_value, set_value *set, impl_val *r_val)
329 {
330 decl_var *var = set->vars->vars[0];
331 impl_val *ret_val = deref_impl_val(r_val, var);
332 psi_object *obj;
333
334 if ((intptr_t) ret_val->ptr > (intptr_t) 0) {
335 object_init_ex(return_value, psi_object_get_class_entry());
336 obj = PSI_OBJ(return_value, NULL);
337 obj->data = ret_val->ptr;
338 } else {
339 RETVAL_NULL();
340 }
341 }