| // 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::isRequired() | |
| * | |
| * Returns true if this field is a required field. | |
| */ | |
| PHP_METHOD(FieldDescriptor, isRequired) { | |
| FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis()); | |
| RETURN_BOOL(upb_FieldDef_IsRequired(intern->fielddef)); | |
| } | |
| /* | |
| * FieldDescriptor::isRepeated() | |
| * | |
| * Returns true if this field is a repeated field. | |
| */ | |
| PHP_METHOD(FieldDescriptor, isRepeated) { | |
| FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis()); | |
| RETURN_BOOL(upb_FieldDef_IsRepeated(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::hasPresence() | |
| * | |
| * Returns true if this field tracks presence, ie. does the field | |
| * distinguish between "unset" and "present with default value." | |
| * | |
| * This includes required, optional, and oneof fields. It excludes maps, | |
| * repeated fields, and singular proto3 fields without "optional". | |
| * | |
| * For fields where hasPresence() == true, the return value of | |
| * msg.hasField() is semantically meaningful. | |
| * | |
| */ | |
| PHP_METHOD(FieldDescriptor, hasPresence) { | |
| FieldDescriptor* intern = (FieldDescriptor*)Z_OBJ_P(getThis()); | |
| RETURN_BOOL(upb_FieldDef_HasPresence(intern->fielddef)); | |
| } | |
| /* | |
| * 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, isRequired, arginfo_void, ZEND_ACC_PUBLIC) | |
| PHP_ME(FieldDescriptor, isRepeated, 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, hasPresence, 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, | |
| size_t 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; | |
| zval* custom_json_names = NULL; | |
| upb_Arena* arena; | |
| if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|bz", &data, &data_len, | |
| &use_nested_submsg, | |
| &custom_json_names) != SUCCESS) { | |
| return; | |
| } | |
| // custom_json_names is passed by generated PHP metadata for pure-PHP mode, | |
| // but is unused in the C extension because upb parses enum JSON names | |
| // directly from the descriptor data. | |
| (void)custom_json_names; | |
| 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, 1) | |
| ZEND_ARG_INFO(0, data) | |
| ZEND_ARG_INFO(0, use_nested_submsg) | |
| ZEND_ARG_INFO(0, custom_json_names) | |
| 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 | |
| } |