summaryrefslogtreecommitdiff
path: root/ext/ffi/ffi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/ffi/ffi.c')
-rw-r--r--ext/ffi/ffi.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index ff785065fd..e3da06698f 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -293,15 +293,86 @@ static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *s
}
/* }}} */
+static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size)
+{
+ zend_ffi_field *field;
+
+ ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
+ switch (ZEND_FFI_TYPE(field->type)->kind) {
+ case ZEND_FFI_TYPE_FLOAT:
+ t->elements[(*i)++] = &ffi_type_float;
+ break;
+ case ZEND_FFI_TYPE_DOUBLE:
+ t->elements[(*i)++] = &ffi_type_double;
+ break;
+#ifdef HAVE_LONG_DOUBLE
+ case ZEND_FFI_TYPE_LONGDOUBLE:
+ t->elements[(*i)++] = &ffi_type_longdouble;
+ break;
+#endif
+ case ZEND_FFI_TYPE_SINT8:
+ case ZEND_FFI_TYPE_UINT8:
+ case ZEND_FFI_TYPE_BOOL:
+ case ZEND_FFI_TYPE_CHAR:
+ t->elements[(*i)++] = &ffi_type_uint8;
+ break;
+ case ZEND_FFI_TYPE_SINT16:
+ case ZEND_FFI_TYPE_UINT16:
+ t->elements[(*i)++] = &ffi_type_uint16;
+ break;
+ case ZEND_FFI_TYPE_SINT32:
+ case ZEND_FFI_TYPE_UINT32:
+ t->elements[(*i)++] = &ffi_type_uint32;
+ break;
+ case ZEND_FFI_TYPE_SINT64:
+ case ZEND_FFI_TYPE_UINT64:
+ t->elements[(*i)++] = &ffi_type_uint64;
+ break;
+ case ZEND_FFI_TYPE_POINTER:
+ t->elements[(*i)++] = &ffi_type_pointer;
+ break;
+ case ZEND_FFI_TYPE_STRUCT: {
+ zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
+ /* for unions we use only the first field */
+ int num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ?
+ zend_hash_num_elements(&field_type->record.fields) : 1;
+
+ if (num_fields > 1) {
+ size += sizeof(ffi_type*) * (num_fields - 1);
+ t = erealloc(t, size);
+ t->elements = (ffi_type**)(t + 1);
+ }
+ t = zend_ffi_face_struct_add_fields(t, field_type, i, size);
+ break;
+ }
+ default:
+ t->elements[(*i)++] = &ffi_type_void;
+ break;
+ }
+ if (type->attr & ZEND_FFI_ATTR_UNION) {
+ /* for unions we use only the first field */
+ break;
+ }
+ } ZEND_HASH_FOREACH_END();
+ return t;
+}
+
static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
{
- ffi_type *t = emalloc(sizeof(ffi_type) + sizeof(ffi_type*));
+ /* for unions we use only the first field */
+ int num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ?
+ zend_hash_num_elements(&type->record.fields) : 1;
+ size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1);
+ ffi_type *t = emalloc(size);
+ int i;
t->size = type->size;
t->alignment = type->align;
t->type = FFI_TYPE_STRUCT;
t->elements = (ffi_type**)(t + 1);
- t->elements[0] = NULL;
+ i = 0;
+ t = zend_ffi_face_struct_add_fields(t, type, &i, size);
+ t->elements[i] = NULL;
return t;
}
/* }}} */