Skip to content

Commit a2845e3

Browse files
committed
FFI::CType reflection API
1 parent 3fc3cfb commit a2845e3

File tree

4 files changed

+545
-2
lines changed

4 files changed

+545
-2
lines changed

ext/ffi/ffi.c

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4469,6 +4469,318 @@ ZEND_METHOD(FFI_CType, getName) /* {{{ */
44694469
RETURN_STR(res);
44704470
}
44714471
}
4472+
/* }}} */
4473+
4474+
ZEND_METHOD(FFI_CType, getKind) /* {{{ */
4475+
{
4476+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4477+
zend_ffi_type *type;
4478+
4479+
if (zend_parse_parameters_none() == FAILURE) {
4480+
RETURN_THROWS();
4481+
}
4482+
4483+
type = ZEND_FFI_TYPE(ctype->type);
4484+
RETURN_LONG(type->kind);
4485+
}
4486+
/* }}} */
4487+
4488+
ZEND_METHOD(FFI_CType, getSize) /* {{{ */
4489+
{
4490+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4491+
zend_ffi_type *type;
4492+
4493+
if (zend_parse_parameters_none() == FAILURE) {
4494+
RETURN_THROWS();
4495+
}
4496+
4497+
type = ZEND_FFI_TYPE(ctype->type);
4498+
RETURN_LONG(type->size);
4499+
}
4500+
/* }}} */
4501+
4502+
ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */
4503+
{
4504+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4505+
zend_ffi_type *type;
4506+
4507+
if (zend_parse_parameters_none() == FAILURE) {
4508+
RETURN_THROWS();
4509+
}
4510+
4511+
type = ZEND_FFI_TYPE(ctype->type);
4512+
RETURN_LONG(type->align);
4513+
}
4514+
/* }}} */
4515+
4516+
ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */
4517+
{
4518+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4519+
zend_ffi_type *type;
4520+
4521+
if (zend_parse_parameters_none() == FAILURE) {
4522+
RETURN_THROWS();
4523+
}
4524+
4525+
type = ZEND_FFI_TYPE(ctype->type);
4526+
RETURN_LONG(type->attr);
4527+
}
4528+
/* }}} */
4529+
4530+
ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */
4531+
{
4532+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4533+
zend_ffi_type *type;
4534+
4535+
if (zend_parse_parameters_none() == FAILURE) {
4536+
RETURN_THROWS();
4537+
}
4538+
4539+
type = ZEND_FFI_TYPE(ctype->type);
4540+
if (type->kind != ZEND_FFI_TYPE_ENUM) {
4541+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an enumeration");
4542+
RETURN_THROWS();
4543+
}
4544+
RETURN_LONG(type->enumeration.kind);
4545+
}
4546+
/* }}} */
4547+
4548+
ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */
4549+
{
4550+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4551+
zend_ffi_type *type;
4552+
zend_ffi_ctype *ret;
4553+
4554+
if (zend_parse_parameters_none() == FAILURE) {
4555+
RETURN_THROWS();
4556+
}
4557+
4558+
type = ZEND_FFI_TYPE(ctype->type);
4559+
if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4560+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4561+
RETURN_THROWS();
4562+
}
4563+
4564+
ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4565+
ret->type = ZEND_FFI_TYPE(type->array.type);
4566+
RETURN_OBJ(&ret->std);
4567+
}
4568+
/* }}} */
4569+
4570+
ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */
4571+
{
4572+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4573+
zend_ffi_type *type;
4574+
4575+
if (zend_parse_parameters_none() == FAILURE) {
4576+
RETURN_THROWS();
4577+
}
4578+
4579+
type = ZEND_FFI_TYPE(ctype->type);
4580+
if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4581+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4582+
RETURN_THROWS();
4583+
}
4584+
RETURN_LONG(type->array.length);
4585+
}
4586+
/* }}} */
4587+
4588+
ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */
4589+
{
4590+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4591+
zend_ffi_ctype *ret;
4592+
zend_ffi_type *type;
4593+
4594+
if (zend_parse_parameters_none() == FAILURE) {
4595+
RETURN_THROWS();
4596+
}
4597+
4598+
type = ZEND_FFI_TYPE(ctype->type);
4599+
if (type->kind != ZEND_FFI_TYPE_POINTER) {
4600+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a pointer");
4601+
RETURN_THROWS();
4602+
}
4603+
4604+
ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4605+
ret->type = ZEND_FFI_TYPE(type->pointer.type);
4606+
RETURN_OBJ(&ret->std);
4607+
}
4608+
/* }}} */
4609+
4610+
ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */
4611+
{
4612+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4613+
zend_ffi_type *type;
4614+
HashTable *ht;
4615+
zend_string* name;
4616+
zval zv;
4617+
4618+
if (zend_parse_parameters_none() == FAILURE) {
4619+
RETURN_THROWS();
4620+
}
4621+
4622+
type = ZEND_FFI_TYPE(ctype->type);
4623+
if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4624+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4625+
RETURN_THROWS();
4626+
}
4627+
4628+
ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
4629+
RETVAL_ARR(ht);
4630+
ZEND_HASH_FOREACH_STR_KEY(&type->record.fields, name) {
4631+
ZVAL_STR_COPY(&zv, name);
4632+
zend_hash_next_index_insert_new(ht, &zv);
4633+
} ZEND_HASH_FOREACH_END();
4634+
}
4635+
/* }}} */
4636+
4637+
ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */
4638+
{
4639+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4640+
zend_ffi_type *type;
4641+
zend_string *name;
4642+
zend_ffi_field *ptr;
4643+
4644+
ZEND_PARSE_PARAMETERS_START(1, 1)
4645+
Z_PARAM_STR(name)
4646+
ZEND_PARSE_PARAMETERS_END();
4647+
4648+
type = ZEND_FFI_TYPE(ctype->type);
4649+
if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4650+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4651+
RETURN_THROWS();
4652+
}
4653+
4654+
ptr = zend_hash_find_ptr(&type->record.fields, name);
4655+
if (!ptr) {
4656+
zend_throw_error(zend_ffi_exception_ce, "Wrong fileld name");
4657+
RETURN_THROWS();
4658+
}
4659+
RETURN_LONG(ptr->offset);
4660+
}
4661+
/* }}} */
4662+
4663+
ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */
4664+
{
4665+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4666+
zend_ffi_type *type;
4667+
zend_string *name;
4668+
zend_ffi_field *ptr;
4669+
zend_ffi_ctype *ret;
4670+
4671+
ZEND_PARSE_PARAMETERS_START(1, 1)
4672+
Z_PARAM_STR(name)
4673+
ZEND_PARSE_PARAMETERS_END();
4674+
4675+
type = ZEND_FFI_TYPE(ctype->type);
4676+
if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4677+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4678+
RETURN_THROWS();
4679+
}
4680+
4681+
ptr = zend_hash_find_ptr(&type->record.fields, name);
4682+
if (!ptr) {
4683+
zend_throw_error(zend_ffi_exception_ce, "Wrong fileld name");
4684+
RETURN_THROWS();
4685+
}
4686+
4687+
ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4688+
ret->type = ZEND_FFI_TYPE(ptr->type);
4689+
RETURN_OBJ(&ret->std);
4690+
}
4691+
/* }}} */
4692+
4693+
ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */
4694+
{
4695+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4696+
zend_ffi_type *type;
4697+
4698+
if (zend_parse_parameters_none() == FAILURE) {
4699+
RETURN_THROWS();
4700+
}
4701+
4702+
type = ZEND_FFI_TYPE(ctype->type);
4703+
if (type->kind != ZEND_FFI_TYPE_FUNC) {
4704+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4705+
RETURN_THROWS();
4706+
}
4707+
RETURN_LONG(type->func.abi);
4708+
}
4709+
/* }}} */
4710+
4711+
ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */
4712+
{
4713+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4714+
zend_ffi_ctype *ret;
4715+
zend_ffi_type *type;
4716+
4717+
if (zend_parse_parameters_none() == FAILURE) {
4718+
RETURN_THROWS();
4719+
}
4720+
4721+
type = ZEND_FFI_TYPE(ctype->type);
4722+
if (type->kind != ZEND_FFI_TYPE_FUNC) {
4723+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4724+
RETURN_THROWS();
4725+
}
4726+
4727+
ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4728+
ret->type = ZEND_FFI_TYPE(type->func.ret_type);
4729+
RETURN_OBJ(&ret->std);
4730+
}
4731+
/* }}} */
4732+
4733+
ZEND_METHOD(FFI_CType, getFuncArgCount) /* {{{ */
4734+
{
4735+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4736+
zend_ffi_type *type;
4737+
4738+
if (zend_parse_parameters_none() == FAILURE) {
4739+
RETURN_THROWS();
4740+
}
4741+
4742+
type = ZEND_FFI_TYPE(ctype->type);
4743+
if (type->kind != ZEND_FFI_TYPE_FUNC) {
4744+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4745+
RETURN_THROWS();
4746+
}
4747+
RETURN_LONG(type->func.args ? zend_hash_num_elements(type->func.args) : 0);
4748+
}
4749+
/* }}} */
4750+
4751+
ZEND_METHOD(FFI_CType, getFuncArgType) /* {{{ */
4752+
{
4753+
zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4754+
zend_ffi_type *type, *ptr;
4755+
zend_long n;
4756+
zend_ffi_ctype *ret;
4757+
4758+
ZEND_PARSE_PARAMETERS_START(1, 1)
4759+
Z_PARAM_LONG(n)
4760+
ZEND_PARSE_PARAMETERS_END();
4761+
4762+
type = ZEND_FFI_TYPE(ctype->type);
4763+
if (type->kind != ZEND_FFI_TYPE_FUNC) {
4764+
zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4765+
RETURN_THROWS();
4766+
}
4767+
4768+
if (!type->func.args) {
4769+
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4770+
RETURN_THROWS();
4771+
}
4772+
4773+
ptr = zend_hash_index_find_ptr(type->func.args, n);
4774+
if (!ptr) {
4775+
zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4776+
RETURN_THROWS();
4777+
}
4778+
4779+
ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4780+
ret->type = ZEND_FFI_TYPE(ptr);
4781+
RETURN_OBJ(&ret->std);
4782+
}
4783+
/* }}} */
44724784

44734785
static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */
44744786
{
@@ -4896,6 +5208,9 @@ static int zend_ffi_preload(char *preload) /* {{{ */
48965208
}
48975209
/* }}} */
48985210

5211+
#define REGISTER_FFI_TYPE_CONSTANT(name) \
5212+
zend_declare_class_constant_long(zend_ffi_ctype_ce, #name, sizeof(#name) - 1, ZEND_FFI_ ## name)
5213+
48995214
/* {{{ ZEND_MINIT_FUNCTION */
49005215
ZEND_MINIT_FUNCTION(ffi)
49015216
{
@@ -5046,6 +5361,49 @@ ZEND_MINIT_FUNCTION(ffi)
50465361
zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
50475362
zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
50485363

5364+
REGISTER_FFI_TYPE_CONSTANT(TYPE_VOID);
5365+
REGISTER_FFI_TYPE_CONSTANT(TYPE_FLOAT);
5366+
REGISTER_FFI_TYPE_CONSTANT(TYPE_DOUBLE);
5367+
#ifdef HAVE_LONG_DOUBLE
5368+
REGISTER_FFI_TYPE_CONSTANT(TYPE_LONGDOUBLE);
5369+
#endif
5370+
REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT8);
5371+
REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT8);
5372+
REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT16);
5373+
REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT16);
5374+
REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT32);
5375+
REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT32);
5376+
REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT64);
5377+
REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT64);
5378+
REGISTER_FFI_TYPE_CONSTANT(TYPE_ENUM);
5379+
REGISTER_FFI_TYPE_CONSTANT(TYPE_BOOL);
5380+
REGISTER_FFI_TYPE_CONSTANT(TYPE_CHAR);
5381+
REGISTER_FFI_TYPE_CONSTANT(TYPE_POINTER);
5382+
REGISTER_FFI_TYPE_CONSTANT(TYPE_FUNC);
5383+
REGISTER_FFI_TYPE_CONSTANT(TYPE_ARRAY);
5384+
REGISTER_FFI_TYPE_CONSTANT(TYPE_STRUCT);
5385+
5386+
REGISTER_FFI_TYPE_CONSTANT(ATTR_CONST);
5387+
REGISTER_FFI_TYPE_CONSTANT(ATTR_INCOMPLETE_TAG);
5388+
REGISTER_FFI_TYPE_CONSTANT(ATTR_VARIADIC);
5389+
REGISTER_FFI_TYPE_CONSTANT(ATTR_INCOMPLETE_ARRAY);
5390+
REGISTER_FFI_TYPE_CONSTANT(ATTR_VLA);
5391+
REGISTER_FFI_TYPE_CONSTANT(ATTR_UNION);
5392+
REGISTER_FFI_TYPE_CONSTANT(ATTR_PACKED);
5393+
REGISTER_FFI_TYPE_CONSTANT(ATTR_MS_STRUCT);
5394+
REGISTER_FFI_TYPE_CONSTANT(ATTR_GCC_STRUCT);
5395+
5396+
REGISTER_FFI_TYPE_CONSTANT(ABI_DEFAULT);
5397+
REGISTER_FFI_TYPE_CONSTANT(ABI_CDECL);
5398+
REGISTER_FFI_TYPE_CONSTANT(ABI_FASTCALL);
5399+
REGISTER_FFI_TYPE_CONSTANT(ABI_THISCALL);
5400+
REGISTER_FFI_TYPE_CONSTANT(ABI_STDCALL);
5401+
REGISTER_FFI_TYPE_CONSTANT(ABI_PASCAL);
5402+
REGISTER_FFI_TYPE_CONSTANT(ABI_REGISTER);
5403+
REGISTER_FFI_TYPE_CONSTANT(ABI_MS);
5404+
REGISTER_FFI_TYPE_CONSTANT(ABI_SYSV);
5405+
REGISTER_FFI_TYPE_CONSTANT(ABI_VECTORCALL);
5406+
50495407
if (FFI_G(preload)) {
50505408
if (zend_ffi_preload(FFI_G(preload)) != SUCCESS) {
50515409
return FAILURE;

0 commit comments

Comments
 (0)