blob: 3dd3c3971c8bd273a0528df2a62ac8986f3cd5f6 [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "def.h"
#include <php.h>
// This is not self-contained: it must be after other Zend includes.
#include <Zend/zend_exceptions.h>
#include "names.h"
#include "php-upb.h"
#include "protobuf.h"
static void CheckUpbStatus(const upb_Status* status, const char* msg) {
if (!upb_Status_IsOk(status)) {
zend_error(E_ERROR, "%s: %s\n", msg, upb_Status_ErrorMessage(status));
}
}
static void FieldDescriptor_FromFieldDef(zval* val, const upb_FieldDef* f);
// We use this for objects that should not be created directly from PHP.
static zend_object* CreateHandler_ReturnNull(zend_class_entry* class_type) {
return NULL; // Nobody should call this.
}
// clang-format off
ZEND_BEGIN_ARG_INFO_EX(arginfo_getByIndex, 0, 0, 1)
ZEND_ARG_INFO(0, index)
ZEND_END_ARG_INFO()
// clang-format on
// -----------------------------------------------------------------------------
// EnumValueDescriptor
// -----------------------------------------------------------------------------
typedef struct {
zend_object std;
const char* name;
int32_t number;
} EnumValueDescriptor;
zend_class_entry* EnumValueDescriptor_class_entry;
static zend_object_handlers EnumValueDescriptor_object_handlers;
/*
* EnumValueDescriptor_Make()
*
* Function to create an EnumValueDescriptor object from C.
*/
static void EnumValueDescriptor_Make(zval* val, const char* name,
int32_t number) {
EnumValueDescriptor* intern = emalloc(sizeof(EnumValueDescriptor));
zend_object_std_init(&intern->std, EnumValueDescriptor_class_entry);
intern->std.handlers = &EnumValueDescriptor_object_handlers;
intern->name = name;
intern->number = number;
// Skip object_properties_init(), we don't allow derived classes.
ZVAL_OBJ(val, &intern->std);
}
/*
* EnumValueDescriptor::getName()
*
* Returns the name for this enum value.
*/
PHP_METHOD(EnumValueDescriptor, getName) {
EnumValueDescriptor* intern = (EnumValueDescriptor*)Z_OBJ_P(getThis());
RETURN_STRING(intern->name);
}
/*
* EnumValueDescriptor::getNumber()
*
* Returns the number for this enum value.
*/
PHP_METHOD(EnumValueDescriptor, getNumber) {
EnumValueDescriptor* intern = (EnumValueDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(intern->number);
}
// clang-format off
static zend_function_entry EnumValueDescriptor_methods[] = {
PHP_ME(EnumValueDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(EnumValueDescriptor, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// EnumDescriptor
// -----------------------------------------------------------------------------
typedef struct {
zend_object std;
const upb_EnumDef* enumdef;
void* cache_key;
} EnumDescriptor;
zend_class_entry* EnumDescriptor_class_entry;
static zend_object_handlers EnumDescriptor_object_handlers;
static void EnumDescriptor_destructor(zend_object* obj) {
EnumDescriptor* intern = (EnumDescriptor*)obj;
ObjCache_Delete(intern->cache_key);
}
// Caller owns a ref on the returned zval.
static void EnumDescriptor_FromClassEntry(zval* val, zend_class_entry* ce) {
// To differentiate enums from classes, we pointer-tag the class entry.
void* key = (void*)((uintptr_t)ce | 1);
PBPHP_ASSERT(key != ce);
if (ce == NULL) {
ZVAL_NULL(val);
return;
}
if (!ObjCache_Get(key, val)) {
const upb_EnumDef* e = NameMap_GetEnum(ce);
if (!e) {
ZVAL_NULL(val);
return;
}
EnumDescriptor* ret = emalloc(sizeof(EnumDescriptor));
zend_object_std_init(&ret->std, EnumDescriptor_class_entry);
ret->std.handlers = &EnumDescriptor_object_handlers;
ret->enumdef = e;
ret->cache_key = key;
ObjCache_Add(key, &ret->std);
ZVAL_OBJ(val, &ret->std);
}
}
// Caller owns a ref on the returned zval.
static void EnumDescriptor_FromEnumDef(zval* val, const upb_EnumDef* m) {
if (!m) {
ZVAL_NULL(val);
} else {
char* classname =
GetPhpClassname(upb_EnumDef_File(m), upb_EnumDef_FullName(m), false);
zend_string* str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry* ce = zend_lookup_class(str); // May autoload the class.
zend_string_release(str);
if (!ce) {
zend_error(E_ERROR, "Couldn't load generated class %s", classname);
}
free(classname);
EnumDescriptor_FromClassEntry(val, ce);
}
}
/*
* EnumDescriptor::getValue()
*
* Returns an EnumValueDescriptor for this index. Note: we are not looking
* up by numeric enum value, but by the index in the list of enum values.
*/
PHP_METHOD(EnumDescriptor, getValue) {
EnumDescriptor* intern = (EnumDescriptor*)Z_OBJ_P(getThis());
zend_long index;
zval ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
zend_error(E_USER_ERROR, "Expect integer for index.\n");
return;
}
if (index < 0 || index >= upb_EnumDef_ValueCount(intern->enumdef)) {
zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
return;
}
const upb_EnumValueDef* ev = upb_EnumDef_Value(intern->enumdef, index);
EnumValueDescriptor_Make(&ret, upb_EnumValueDef_Name(ev),
upb_EnumValueDef_Number(ev));
RETURN_COPY_VALUE(&ret);
}
/*
* EnumDescriptor::getValueCount()
*
* Returns the number of values in this enum.
*/
PHP_METHOD(EnumDescriptor, getValueCount) {
EnumDescriptor* intern = (EnumDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_EnumDef_ValueCount(intern->enumdef));
}
/*
* EnumDescriptor::getPublicDescriptor()
*
* Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not
* have two separate EnumDescriptor classes. We use a single class for both
* the public and private descriptor.
*/
PHP_METHOD(EnumDescriptor, getPublicDescriptor) { RETURN_COPY(getThis()); }
// clang-format off
static zend_function_entry EnumDescriptor_methods[] = {
PHP_ME(EnumDescriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(EnumDescriptor, getValueCount, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(EnumDescriptor, getValue, arginfo_getByIndex, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// Oneof
// -----------------------------------------------------------------------------
typedef struct {
zend_object std;
const upb_OneofDef* oneofdef;
} OneofDescriptor;
zend_class_entry* OneofDescriptor_class_entry;
static zend_object_handlers OneofDescriptor_object_handlers;
static void OneofDescriptor_destructor(zend_object* obj) {
OneofDescriptor* intern = (OneofDescriptor*)obj;
ObjCache_Delete(intern->oneofdef);
}
static void OneofDescriptor_FromOneofDef(zval* val, const upb_OneofDef* o) {
if (o == NULL) {
ZVAL_NULL(val);
return;
}
if (!ObjCache_Get(o, val)) {
OneofDescriptor* ret = emalloc(sizeof(OneofDescriptor));
zend_object_std_init(&ret->std, OneofDescriptor_class_entry);
ret->std.handlers = &OneofDescriptor_object_handlers;
ret->oneofdef = o;
ObjCache_Add(o, &ret->std);
ZVAL_OBJ(val, &ret->std);
}
}
/*
* OneofDescriptor::getName()
*
* Returns the name of this oneof.
*/
PHP_METHOD(OneofDescriptor, getName) {
OneofDescriptor* intern = (OneofDescriptor*)Z_OBJ_P(getThis());
RETURN_STRING(upb_OneofDef_Name(intern->oneofdef));
}
/*
* OneofDescriptor::getField()
*
* Returns a field from this oneof. The given index must be in the range
* [0, getFieldCount() - 1].
*/
PHP_METHOD(OneofDescriptor, getField) {
OneofDescriptor* intern = (OneofDescriptor*)Z_OBJ_P(getThis());
zend_long index;
zval ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
zend_error(E_USER_ERROR, "Expect integer for index.\n");
return;
}
if (index < 0 || index >= upb_OneofDef_FieldCount(intern->oneofdef)) {
zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
return;
}
const upb_FieldDef* field = upb_OneofDef_Field(intern->oneofdef, index);
FieldDescriptor_FromFieldDef(&ret, field);
RETURN_COPY_VALUE(&ret);
}
/*
* OneofDescriptor::getFieldCount()
*
* Returns the number of fields in this oneof.
*/
PHP_METHOD(OneofDescriptor, getFieldCount) {
OneofDescriptor* intern = (OneofDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_OneofDef_FieldCount(intern->oneofdef));
}
// clang-format off
static zend_function_entry OneofDescriptor_methods[] = {
PHP_ME(OneofDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(OneofDescriptor, getField, arginfo_getByIndex, ZEND_ACC_PUBLIC)
PHP_ME(OneofDescriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// FieldDescriptor
// -----------------------------------------------------------------------------
typedef struct {
zend_object std;
const upb_FieldDef* fielddef;
} FieldDescriptor;
zend_class_entry* FieldDescriptor_class_entry;
static zend_object_handlers FieldDescriptor_object_handlers;
static void FieldDescriptor_destructor(zend_object* obj) {
FieldDescriptor* intern = (FieldDescriptor*)obj;
ObjCache_Delete(intern->fielddef);
}
// Caller owns a ref on the returned zval.
static void FieldDescriptor_FromFieldDef(zval* val, const upb_FieldDef* f) {
if (f == NULL) {
ZVAL_NULL(val);
return;
}
if (!ObjCache_Get(f, val)) {
FieldDescriptor* ret = emalloc(sizeof(FieldDescriptor));
zend_object_std_init(&ret->std, FieldDescriptor_class_entry);
ret->std.handlers = &FieldDescriptor_object_handlers;
ret->fielddef = f;
ObjCache_Add(f, &ret->std);
ZVAL_OBJ(val, &ret->std);
}
}
upb_CType to_fieldtype(upb_FieldType type) {
switch (type) {
#define CASE(descriptor_type, type) \
case kUpb_FieldType_##descriptor_type: \
return kUpb_CType_##type;
CASE(Float, Float);
CASE(Double, Double);
CASE(Bool, Bool);
CASE(String, String);
CASE(Bytes, Bytes);
CASE(Message, Message);
CASE(Group, Message);
CASE(Enum, Enum);
CASE(Int32, Int32);
CASE(Int64, Int64);
CASE(UInt32, UInt32);
CASE(UInt64, UInt64);
CASE(SInt32, Int32);
CASE(SInt64, Int64);
CASE(Fixed32, UInt32);
CASE(Fixed64, UInt64);
CASE(SFixed32, Int32);
CASE(SFixed64, Int64);
#undef CONVERT
}
zend_error(E_ERROR, "Unknown field type.");
return 0;
}
/*
* FieldDescriptor::getName()
*
* Returns the name of this field.
*/
PHP_METHOD(FieldDescriptor, getName) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
RETURN_STRING(upb_FieldDef_Name(intern->fielddef));
}
/*
* FieldDescriptor::getNumber()
*
* Returns the number of this field.
*/
PHP_METHOD(FieldDescriptor, getNumber) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_FieldDef_Number(intern->fielddef));
}
/*
* FieldDescriptor::getLabel()
*
* Returns the label of this field as an integer.
*/
PHP_METHOD(FieldDescriptor, getLabel) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_FieldDef_Label(intern->fielddef));
}
/*
* FieldDescriptor::getType()
*
* Returns the type of this field as an integer.
*/
PHP_METHOD(FieldDescriptor, getType) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_FieldDef_Type(intern->fielddef));
}
/*
* FieldDescriptor::isMap()
*
* Returns true if this field is a map.
*/
PHP_METHOD(FieldDescriptor, isMap) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
RETURN_BOOL(upb_FieldDef_IsMap(intern->fielddef));
}
/*
* FieldDescriptor::getEnumType()
*
* Returns the EnumDescriptor for this field, which must be an enum.
*/
PHP_METHOD(FieldDescriptor, getEnumType) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
const upb_EnumDef* e = upb_FieldDef_EnumSubDef(intern->fielddef);
zval ret;
if (!e) {
zend_throw_exception_ex(NULL, 0,
"Cannot get enum type for non-enum field '%s'",
upb_FieldDef_Name(intern->fielddef));
return;
}
EnumDescriptor_FromEnumDef(&ret, e);
RETURN_COPY_VALUE(&ret);
}
/*
* FieldDescriptor::getContainingOneof()
*
* Returns the OneofDescriptor for this field, or null if it is not inside
* a oneof.
*/
PHP_METHOD(FieldDescriptor, getContainingOneof) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
const upb_OneofDef* o = upb_FieldDef_ContainingOneof(intern->fielddef);
zval ret;
if (!o) {
RETURN_NULL();
}
OneofDescriptor_FromOneofDef(&ret, o);
RETURN_COPY_VALUE(&ret);
}
/*
* FieldDescriptor::getRealContainingOneof()
*
* Returns the non-synthetic OneofDescriptor for this field, or null if it is
* not inside a oneof.
*/
PHP_METHOD(FieldDescriptor, getRealContainingOneof) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
const upb_OneofDef* o = upb_FieldDef_RealContainingOneof(intern->fielddef);
zval ret;
if (!o) {
RETURN_NULL();
}
OneofDescriptor_FromOneofDef(&ret, o);
RETURN_COPY_VALUE(&ret);
}
/*
* FieldDescriptor::getMessageType()
*
* Returns the Descriptor for this field, which must be a message.
*/
PHP_METHOD(FieldDescriptor, getMessageType) {
FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis());
Descriptor* desc = Descriptor_GetFromFieldDef(intern->fielddef);
if (!desc) {
zend_throw_exception_ex(
NULL, 0, "Cannot get message type for non-message field '%s'",
upb_FieldDef_Name(intern->fielddef));
return;
}
RETURN_OBJ_COPY(&desc->std);
}
// clang-format off
static zend_function_entry FieldDescriptor_methods[] = {
PHP_ME(FieldDescriptor, getName, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getNumber, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getLabel, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getType, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, isMap, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getEnumType, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getContainingOneof, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getRealContainingOneof, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(FieldDescriptor, getMessageType, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// Descriptor
// -----------------------------------------------------------------------------
zend_class_entry* Descriptor_class_entry;
static zend_object_handlers Descriptor_object_handlers;
static void Descriptor_destructor(zend_object* obj) {
// We don't really need to do anything here, we don't allow this to be
// collected before the end of the request.
}
static zend_class_entry* Descriptor_GetGeneratedClass(const upb_MessageDef* m) {
for (int i = 0; i < 2; ++i) {
char* classname = GetPhpClassname(upb_MessageDef_File(m),
upb_MessageDef_FullName(m), (bool)i);
zend_string* str = zend_string_init(classname, strlen(classname), 0);
zend_class_entry* ce = zend_lookup_class(str); // May autoload the class.
zend_string_release(str);
free(classname);
if (ce) {
return ce;
}
}
char* classname = GetPhpClassname(upb_MessageDef_File(m),
upb_MessageDef_FullName(m), false);
zend_error(E_ERROR, "Couldn't load generated class %s", classname);
return NULL;
}
void Descriptor_FromMessageDef(zval* val, const upb_MessageDef* m) {
if (m == NULL) {
ZVAL_NULL(val);
return;
}
if (!ObjCache_Get(m, val)) {
zend_class_entry* ce = NULL;
if (!upb_MessageDef_IsMapEntry(m)) { // Map entries don't have a class.
ce = Descriptor_GetGeneratedClass(m);
if (!ce) {
ZVAL_NULL(val);
return;
}
}
Descriptor* ret = emalloc(sizeof(Descriptor));
zend_object_std_init(&ret->std, Descriptor_class_entry);
ret->std.handlers = &Descriptor_object_handlers;
ret->class_entry = ce;
ret->msgdef = m;
ObjCache_Add(m, &ret->std);
Descriptors_Add(&ret->std);
ZVAL_OBJ(val, &ret->std);
}
}
static void Descriptor_FromClassEntry(zval* val, zend_class_entry* ce) {
if (ce) {
Descriptor_FromMessageDef(val, NameMap_GetMessage(ce));
} else {
ZVAL_NULL(val);
}
}
static Descriptor* Descriptor_GetFromZval(zval* val) {
if (Z_TYPE_P(val) == IS_NULL) {
return NULL;
} else {
zend_object* ret = Z_OBJ_P(val);
zval_ptr_dtor(val);
return (Descriptor*)ret;
}
}
// C Functions from def.h //////////////////////////////////////////////////////
// These are documented in the header file.
Descriptor* Descriptor_GetFromClassEntry(zend_class_entry* ce) {
zval desc;
Descriptor_FromClassEntry(&desc, ce);
return Descriptor_GetFromZval(&desc);
}
Descriptor* Descriptor_GetFromMessageDef(const upb_MessageDef* m) {
zval desc;
Descriptor_FromMessageDef(&desc, m);
return Descriptor_GetFromZval(&desc);
}
Descriptor* Descriptor_GetFromFieldDef(const upb_FieldDef* f) {
return Descriptor_GetFromMessageDef(upb_FieldDef_MessageSubDef(f));
}
/*
* Descriptor::getPublicDescriptor()
*
* Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not
* have two separate EnumDescriptor classes. We use a single class for both
* the public and private descriptor.
*/
PHP_METHOD(Descriptor, getPublicDescriptor) { RETURN_COPY(getThis()); }
/*
* Descriptor::getFullName()
*
* Returns the full name for this message type.
*/
PHP_METHOD(Descriptor, getFullName) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
RETURN_STRING(upb_MessageDef_FullName(intern->msgdef));
}
/*
* Descriptor::getField()
*
* Returns a FieldDescriptor for the given index, which must be in the range
* [0, getFieldCount()-1].
*/
PHP_METHOD(Descriptor, getField) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
int count = upb_MessageDef_FieldCount(intern->msgdef);
zval ret;
zend_long index;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
zend_error(E_USER_ERROR, "Expect integer for index.\n");
return;
}
if (index < 0 || index >= count) {
zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
return;
}
FieldDescriptor_FromFieldDef(&ret,
upb_MessageDef_Field(intern->msgdef, index));
RETURN_COPY_VALUE(&ret);
}
/*
* Descriptor::getFieldCount()
*
* Returns the number of fields in this message.
*/
PHP_METHOD(Descriptor, getFieldCount) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_MessageDef_FieldCount(intern->msgdef));
}
/*
* Descriptor::getOneofDecl()
*
* Returns a OneofDescriptor for the given index, which must be in the range
* [0, getOneofDeclCount()].
*/
PHP_METHOD(Descriptor, getOneofDecl) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
zend_long index;
zval ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
zend_error(E_USER_ERROR, "Expect integer for index.\n");
return;
}
if (index < 0 || index >= upb_MessageDef_OneofCount(intern->msgdef)) {
zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
return;
}
OneofDescriptor_FromOneofDef(&ret,
upb_MessageDef_Oneof(intern->msgdef, index));
RETURN_COPY_VALUE(&ret);
}
/*
* Descriptor::getOneofDeclCount()
*
* Returns the number of oneofs in this message.
*/
PHP_METHOD(Descriptor, getOneofDeclCount) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
RETURN_LONG(upb_MessageDef_OneofCount(intern->msgdef));
}
/*
* Descriptor::getClass()
*
* Returns the name of the PHP class for this message.
*/
PHP_METHOD(Descriptor, getClass) {
Descriptor* intern = (Descriptor*)Z_OBJ_P(getThis());
const char* classname = ZSTR_VAL(intern->class_entry->name);
RETURN_STRING(classname);
}
// clang-format off
static zend_function_entry Descriptor_methods[] = {
PHP_ME(Descriptor, getClass, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getFullName, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getField, arginfo_getByIndex, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getFieldCount, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getOneofDecl, arginfo_getByIndex, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getOneofDeclCount, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(Descriptor, getPublicDescriptor, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// DescriptorPool
// -----------------------------------------------------------------------------
typedef struct DescriptorPool {
zend_object std;
upb_DefPool* symtab;
} DescriptorPool;
zend_class_entry* DescriptorPool_class_entry;
static zend_object_handlers DescriptorPool_object_handlers;
static DescriptorPool* GetPool(const zval* this_ptr) {
return (DescriptorPool*)Z_OBJ_P(this_ptr);
}
/**
* Object handler to free an DescriptorPool.
*/
static void DescriptorPool_destructor(zend_object* obj) {
DescriptorPool* intern = (DescriptorPool*)obj;
// We can't free our underlying symtab here, because user code may create
// messages from destructors that will refer to it. The symtab will be freed
// by our RSHUTDOWN() handler in protobuf.c
zend_object_std_dtor(&intern->std);
}
void DescriptorPool_CreateWithSymbolTable(zval* zv, upb_DefPool* symtab) {
DescriptorPool* intern = emalloc(sizeof(DescriptorPool));
zend_object_std_init(&intern->std, DescriptorPool_class_entry);
intern->std.handlers = &DescriptorPool_object_handlers;
intern->symtab = symtab;
ZVAL_OBJ(zv, &intern->std);
}
upb_DefPool* DescriptorPool_GetSymbolTable() { return get_global_symtab(); }
/*
* DescriptorPool::getGeneratedPool()
*
* Returns the generated DescriptorPool.
*/
PHP_METHOD(DescriptorPool, getGeneratedPool) {
DescriptorPool_CreateWithSymbolTable(return_value, get_global_symtab());
}
/*
* DescriptorPool::getDescriptorByClassName()
*
* Returns a Descriptor object for the given PHP class name.
*/
PHP_METHOD(DescriptorPool, getDescriptorByClassName) {
char* classname = NULL;
zend_long classname_len;
zend_class_entry* ce;
zend_string* str;
zval ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &classname, &classname_len) ==
FAILURE) {
return;
}
str = zend_string_init(classname, strlen(classname), 0);
ce = zend_lookup_class(str); // May autoload the class.
zend_string_release(str);
if (!ce) {
RETURN_NULL();
}
Descriptor_FromClassEntry(&ret, ce);
RETURN_COPY_VALUE(&ret);
}
/*
* DescriptorPool::getEnumDescriptorByClassName()
*
* Returns a EnumDescriptor object for the given PHP class name.
*/
PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) {
char* classname = NULL;
zend_long classname_len;
zend_class_entry* ce;
zend_string* str;
zval ret;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &classname, &classname_len) ==
FAILURE) {
return;
}
str = zend_string_init(classname, strlen(classname), 0);
ce = zend_lookup_class(str); // May autoload the class.
zend_string_release(str);
if (!ce) {
RETURN_NULL();
}
EnumDescriptor_FromClassEntry(&ret, ce);
RETURN_COPY_VALUE(&ret);
}
/*
* DescriptorPool::getEnumDescriptorByProtoName()
*
* Returns a Descriptor object for the given protobuf message name.
*/
PHP_METHOD(DescriptorPool, getDescriptorByProtoName) {
DescriptorPool* intern = GetPool(getThis());
char* protoname = NULL;
zend_long protoname_len;
const upb_MessageDef* m;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &protoname, &protoname_len) ==
FAILURE) {
return;
}
if (*protoname == '.') protoname++;
m = upb_DefPool_FindMessageByName(intern->symtab, protoname);
if (m) {
RETURN_OBJ_COPY(&Descriptor_GetFromMessageDef(m)->std);
} else {
RETURN_NULL();
}
}
/*
* depends_on_descriptor()
*
* Returns true if this FileDescriptorProto depends on descriptor.proto.
*/
bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) {
const upb_StringView* deps;
upb_StringView name =
upb_StringView_FromString("google/protobuf/descriptor.proto");
size_t i, n;
deps = google_protobuf_FileDescriptorProto_dependency(file, &n);
for (i = 0; i < n; i++) {
if (upb_StringView_IsEqual(deps[i], name)) {
return true;
}
}
return false;
}
static void add_message_name_mappings(const upb_MessageDef* message) {
NameMap_AddMessage(message);
int msg_n = upb_MessageDef_NestedMessageCount(message);
for (int i = 0; i < msg_n; i++) {
add_message_name_mappings(upb_MessageDef_NestedMessage(message, i));
}
int enum_n = upb_MessageDef_NestedEnumCount(message);
for (int i = 0; i < enum_n; i++) {
NameMap_AddEnum(upb_MessageDef_NestedEnum(message, i));
}
}
/*
* add_name_mappings()
*
* Adds the messages and enums in this file to the NameMap.
*/
static void add_name_mappings(const upb_FileDef* file) {
for (int i = 0; i < upb_FileDef_TopLevelMessageCount(file); i++) {
add_message_name_mappings(upb_FileDef_TopLevelMessage(file, i));
}
for (int i = 0; i < upb_FileDef_TopLevelEnumCount(file); i++) {
NameMap_AddEnum(upb_FileDef_TopLevelEnum(file, i));
}
}
static void add_descriptor(upb_DefPool* symtab,
const google_protobuf_FileDescriptorProto* file) {
upb_StringView name = google_protobuf_FileDescriptorProto_name(file);
upb_Status status;
const upb_FileDef* file_def;
upb_Status_Clear(&status);
if (upb_DefPool_FindFileByNameWithSize(symtab, name.data, name.size)) {
// Already added.
// TODO: Re-enable this warning when aggregate metadata is
// deprecated.
// zend_error(E_USER_WARNING,
// "proto descriptor was previously loaded (included in multiple
// " "metadata bundles?): " UPB_STRINGVIEW_FORMAT,
// UPB_STRINGVIEW_ARGS(name));
return;
}
// The PHP code generator currently special-cases descriptor.proto. It
// doesn't add it as a dependency even if the proto file actually does
// depend on it.
if (depends_on_descriptor(file)) {
google_protobuf_FileDescriptorProto_getmsgdef(symtab);
}
file_def = upb_DefPool_AddFile(symtab, file, &status);
CheckUpbStatus(&status, "Unable to load descriptor");
add_name_mappings(file_def);
}
/*
* add_descriptor()
*
* Adds the given descriptor data to this DescriptorPool.
*/
static void add_descriptor_set(upb_DefPool* symtab, const char* data,
int data_len, upb_Arena* arena) {
size_t i, n;
google_protobuf_FileDescriptorSet* set;
const google_protobuf_FileDescriptorProto* const* files;
set = google_protobuf_FileDescriptorSet_parse(data, data_len, arena);
if (!set) {
zend_error(E_ERROR, "Failed to parse binary descriptor\n");
return;
}
files = google_protobuf_FileDescriptorSet_file(set, &n);
for (i = 0; i < n; i++) {
const google_protobuf_FileDescriptorProto* file = files[i];
add_descriptor(symtab, file);
}
}
bool DescriptorPool_HasFile(const char* filename) {
return upb_DefPool_FindFileByName(get_global_symtab(), filename) != NULL;
}
void DescriptorPool_AddDescriptor(const char* filename, const char* data,
int size) {
upb_Arena* arena = upb_Arena_New();
const google_protobuf_FileDescriptorProto* file =
google_protobuf_FileDescriptorProto_parse(data, size, arena);
if (!file) {
zend_error(E_ERROR, "Failed to parse binary descriptor for %s\n", filename);
return;
}
add_descriptor(get_global_symtab(), file);
upb_Arena_Free(arena);
}
/*
* DescriptorPool::internalAddGeneratedFile()
*
* Adds the given descriptor data to this DescriptorPool.
*/
PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
DescriptorPool* intern = GetPool(getThis());
char* data = NULL;
zend_long data_len;
zend_bool use_nested_submsg = false;
upb_Arena* arena;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
&use_nested_submsg) != SUCCESS) {
return;
}
arena = upb_Arena_New();
add_descriptor_set(intern->symtab, data, data_len, arena);
upb_Arena_Free(arena);
}
// clang-format off
ZEND_BEGIN_ARG_INFO_EX(arginfo_lookupByName, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_addgeneratedfile, 0, 0, 2)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, data_len)
ZEND_END_ARG_INFO()
static zend_function_entry DescriptorPool_methods[] = {
PHP_ME(DescriptorPool, getGeneratedPool, arginfo_void,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(DescriptorPool, getDescriptorByClassName, arginfo_lookupByName, ZEND_ACC_PUBLIC)
PHP_ME(DescriptorPool, getDescriptorByProtoName, arginfo_lookupByName, ZEND_ACC_PUBLIC)
PHP_ME(DescriptorPool, getEnumDescriptorByClassName, arginfo_lookupByName, ZEND_ACC_PUBLIC)
PHP_ME(DescriptorPool, internalAddGeneratedFile, arginfo_addgeneratedfile, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// InternalDescriptorPool
// -----------------------------------------------------------------------------
// For the C extension, Google\Protobuf\Internal\DescriptorPool is not a
// separate instantiable object, it just returns a
// Google\Protobuf\DescriptorPool.
zend_class_entry* InternalDescriptorPool_class_entry;
/*
* InternalDescriptorPool::getGeneratedPool()
*
* Returns the generated DescriptorPool. Note that this is identical to
* DescriptorPool::getGeneratedPool(), and in fact returns a DescriptorPool
* instance.
*/
PHP_METHOD(InternalDescriptorPool, getGeneratedPool) {
DescriptorPool_CreateWithSymbolTable(return_value, get_global_symtab());
}
// clang-format off
static zend_function_entry InternalDescriptorPool_methods[] = {
PHP_ME(InternalDescriptorPool, getGeneratedPool, arginfo_void,
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_FE_END
};
// clang-format on
// -----------------------------------------------------------------------------
// GPBType
// -----------------------------------------------------------------------------
zend_class_entry* gpb_type_type;
static zend_function_entry gpb_type_methods[] = {ZEND_FE_END};
// -----------------------------------------------------------------------------
// Module Init
// -----------------------------------------------------------------------------
void Def_ModuleInit() {
zend_class_entry tmp_ce;
zend_object_handlers* h;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\OneofDescriptor",
OneofDescriptor_methods);
OneofDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
OneofDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
OneofDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
h = &OneofDescriptor_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = &OneofDescriptor_destructor;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumValueDescriptor",
EnumValueDescriptor_methods);
EnumValueDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
EnumValueDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
EnumValueDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
h = &EnumValueDescriptor_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumDescriptor",
EnumDescriptor_methods);
EnumDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
EnumDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
EnumDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
h = &EnumDescriptor_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = &EnumDescriptor_destructor;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Descriptor", Descriptor_methods);
Descriptor_class_entry = zend_register_internal_class(&tmp_ce);
Descriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
Descriptor_class_entry->create_object = CreateHandler_ReturnNull;
h = &Descriptor_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = Descriptor_destructor;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\FieldDescriptor",
FieldDescriptor_methods);
FieldDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
FieldDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
FieldDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
h = &FieldDescriptor_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = &FieldDescriptor_destructor;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\DescriptorPool",
DescriptorPool_methods);
DescriptorPool_class_entry = zend_register_internal_class(&tmp_ce);
DescriptorPool_class_entry->ce_flags |= ZEND_ACC_FINAL;
DescriptorPool_class_entry->create_object = CreateHandler_ReturnNull;
h = &DescriptorPool_object_handlers;
memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
h->dtor_obj = DescriptorPool_destructor;
INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\DescriptorPool",
InternalDescriptorPool_methods);
InternalDescriptorPool_class_entry = zend_register_internal_class(&tmp_ce);
// GPBType.
#define STR(str) (str), strlen(str)
zend_class_entry class_type;
INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType",
gpb_type_methods);
gpb_type_type = zend_register_internal_class(&class_type);
zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1);
zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2);
zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3);
zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4);
zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5);
zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6);
zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7);
zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8);
zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9);
zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10);
zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11);
zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12);
zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13);
zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14);
zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), 15);
zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), 16);
zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17);
zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18);
#undef STR
}