| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #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_ok(status)) { |
| zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(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. |
| } |
| |
| |
| // ----------------------------------------------------------------------------- |
| // 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); |
| } |
| |
| static zend_function_entry EnumValueDescriptor_methods[] = { |
| PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // EnumDescriptor |
| // ----------------------------------------------------------------------------- |
| |
| typedef struct { |
| zend_object std; |
| const upb_enumdef *enumdef; |
| } EnumDescriptor; |
| |
| zend_class_entry *EnumDescriptor_class_entry; |
| static zend_object_handlers EnumDescriptor_object_handlers; |
| |
| 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; |
| ObjCache_Add(key, &ret->std); |
| |
| // Prevent this from ever being collected (within a request). |
| GC_ADDREF(&ret->std); |
| |
| ZVAL_OBJ(val, &ret->std); |
| } |
| } |
| |
| 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)); |
| 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() TSRMLS_CC, "l", &index) == |
| FAILURE) { |
| zend_error(E_USER_ERROR, "Expect integer for index.\n"); |
| return; |
| } |
| |
| int field_num = upb_enumdef_numvals(intern->enumdef); |
| if (index < 0 || index >= field_num) { |
| zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); |
| return; |
| } |
| |
| upb_enum_iter iter; |
| int i; |
| for(upb_enum_begin(&iter, intern->enumdef), i = 0; |
| !upb_enum_done(&iter) && i < index; |
| upb_enum_next(&iter), i++); |
| |
| EnumValueDescriptor_Make(&ret, upb_enum_iter_name(&iter), |
| upb_enum_iter_number(&iter)); |
| RETURN_ZVAL(&ret, 0, 1); |
| } |
| |
| /* |
| * 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_numvals(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_ZVAL(getThis(), 1, 0); |
| } |
| |
| static zend_function_entry EnumDescriptor_methods[] = { |
| PHP_ME(EnumDescriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // 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_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); |
| |
| // Prevent this from ever being collected (within a request). |
| GC_ADDREF(&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() TSRMLS_CC, "l", &index) == |
| FAILURE) { |
| zend_error(E_USER_ERROR, "Expect integer for index.\n"); |
| return; |
| } |
| |
| int field_num = upb_oneofdef_numfields(intern->oneofdef); |
| if (index < 0 || index >= field_num) { |
| zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); |
| return; |
| } |
| |
| upb_oneof_iter iter; |
| int i; |
| for(upb_oneof_begin(&iter, intern->oneofdef), i = 0; |
| !upb_oneof_done(&iter) && i < index; |
| upb_oneof_next(&iter), i++); |
| const upb_fielddef *field = upb_oneof_iter_field(&iter); |
| |
| FieldDescriptor_FromFieldDef(&ret, field); |
| RETURN_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * 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_numfields(intern->oneofdef)); |
| } |
| |
| static zend_function_entry OneofDescriptor_methods[] = { |
| PHP_ME(OneofDescriptor, getName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(OneofDescriptor, getField, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(OneofDescriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // 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_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); |
| |
| // Prevent this from ever being collected (within a request). |
| GC_ADDREF(&ret->std); |
| |
| ZVAL_OBJ(val, &ret->std); |
| } |
| } |
| |
| upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { |
| switch (type) { |
| #define CASE(descriptor_type, type) \ |
| case UPB_DESCRIPTOR_TYPE_##descriptor_type: \ |
| return UPB_TYPE_##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_descriptortype(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_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * 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); |
| zval ret; |
| |
| if (!desc) { |
| zend_throw_exception_ex( |
| NULL, 0, "Cannot get message type for non-message field '%s'", |
| upb_fielddef_name(intern->fielddef)); |
| return; |
| } |
| |
| ZVAL_OBJ(&ret, &desc->std); |
| RETURN_ZVAL(&ret, 1, 0); |
| } |
| |
| static zend_function_entry FieldDescriptor_methods[] = { |
| PHP_ME(FieldDescriptor, getName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, getLabel, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, getType, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, isMap, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // 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. |
| } |
| |
| // C Functions from def.h ////////////////////////////////////////////////////// |
| |
| // These are documented in the header file. |
| |
| void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) { |
| if (ce == NULL) { |
| ZVAL_NULL(val); |
| return; |
| } |
| |
| if (!ObjCache_Get(ce, val)) { |
| const upb_msgdef *msgdef = NameMap_GetMessage(ce); |
| if (!msgdef) { |
| 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 = msgdef; |
| ObjCache_Add(ce, &ret->std); |
| |
| // Prevent this from ever being collected (within a request). |
| GC_ADDREF(&ret->std); |
| |
| ZVAL_OBJ(val, &ret->std); |
| } |
| } |
| |
| Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) { |
| zval desc; |
| Descriptor_FromClassEntry(&desc, ce); |
| if (Z_TYPE_P(&desc) == IS_NULL) { |
| return NULL; |
| } else { |
| return (Descriptor*)Z_OBJ_P(&desc); |
| } |
| } |
| |
| Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) { |
| if (m) { |
| if (upb_msgdef_mapentry(m)) { |
| // A bit of a hack, since map entries don't have classes. |
| Descriptor* ret = emalloc(sizeof(Descriptor)); |
| zend_object_std_init(&ret->std, Descriptor_class_entry); |
| ret->std.handlers = &Descriptor_object_handlers; |
| ret->class_entry = NULL; |
| ret->msgdef = m; |
| |
| // Prevent this from ever being collected (within a request). |
| GC_ADDREF(&ret->std); |
| |
| return ret; |
| } |
| |
| char *classname = |
| GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); |
| 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); |
| return Descriptor_GetFromClassEntry(ce); |
| } else { |
| return NULL; |
| } |
| } |
| |
| Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) { |
| return Descriptor_GetFromMessageDef(upb_fielddef_msgsubdef(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_ZVAL(getThis(), 1, 0); |
| } |
| |
| /* |
| * Descriptor::getFullName() |
| * |
| * Returns the full name for this message type. |
| */ |
| PHP_METHOD(Descriptor, getFullName) { |
| Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); |
| RETURN_STRING(upb_msgdef_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_msgdef_numfields(intern->msgdef); |
| zval ret; |
| zend_long index; |
| |
| if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "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; |
| } |
| |
| upb_msg_field_iter iter; |
| int i; |
| for(upb_msg_field_begin(&iter, intern->msgdef), i = 0; |
| !upb_msg_field_done(&iter) && i < index; |
| upb_msg_field_next(&iter), i++); |
| const upb_fielddef *field = upb_msg_iter_field(&iter); |
| |
| FieldDescriptor_FromFieldDef(&ret, field); |
| RETURN_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * Descriptor::getFieldCount() |
| * |
| * Returns the number of fields in this message. |
| */ |
| PHP_METHOD(Descriptor, getFieldCount) { |
| Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); |
| RETURN_LONG(upb_msgdef_numfields(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() TSRMLS_CC, "l", &index) == |
| FAILURE) { |
| zend_error(E_USER_ERROR, "Expect integer for index.\n"); |
| return; |
| } |
| |
| int field_num = upb_msgdef_numoneofs(intern->msgdef); |
| if (index < 0 || index >= field_num) { |
| zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); |
| return; |
| } |
| |
| upb_msg_oneof_iter iter; |
| int i; |
| for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0; |
| !upb_msg_oneof_done(&iter) && i < index; |
| upb_msg_oneof_next(&iter), i++); |
| const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter); |
| |
| OneofDescriptor_FromOneofDef(&ret, oneof); |
| RETURN_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * Descriptor::getOneofDeclCount() |
| * |
| * Returns the number of oneofs in this message. |
| */ |
| PHP_METHOD(Descriptor, getOneofDeclCount) { |
| Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); |
| RETURN_LONG(upb_msgdef_numoneofs(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); |
| } |
| |
| |
| static zend_function_entry Descriptor_methods[] = { |
| PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(Descriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // DescriptorPool |
| // ----------------------------------------------------------------------------- |
| |
| typedef struct DescriptorPool { |
| zend_object std; |
| upb_symtab *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 create an DescriptorPool. |
| */ |
| static zend_object* DescriptorPool_create(zend_class_entry *class_type) { |
| DescriptorPool *intern = emalloc(sizeof(DescriptorPool)); |
| zend_object_std_init(&intern->std, class_type); |
| intern->std.handlers = &DescriptorPool_object_handlers; |
| intern->symtab = upb_symtab_new(); |
| // Skip object_properties_init(), we don't allow derived classes. |
| return &intern->std; |
| } |
| |
| /** |
| * Object handler to free an DescriptorPool. |
| */ |
| static void DescriptorPool_destructor(zend_object* obj) { |
| DescriptorPool* intern = (DescriptorPool*)obj; |
| if (intern->symtab) { |
| upb_symtab_free(intern->symtab); |
| } |
| intern->symtab = NULL; |
| zend_object_std_dtor(&intern->std); |
| } |
| |
| void DescriptorPool_CreateWithSymbolTable(zval *zv, upb_symtab *symtab) { |
| ZVAL_OBJ(zv, DescriptorPool_create(DescriptorPool_class_entry)); |
| |
| if (symtab) { |
| DescriptorPool *intern = GetPool(zv); |
| upb_symtab_free(intern->symtab); |
| intern->symtab = symtab; |
| } |
| } |
| |
| upb_symtab *DescriptorPool_Steal(zval *zv) { |
| DescriptorPool *intern = GetPool(zv); |
| upb_symtab *ret = intern->symtab; |
| intern->symtab = NULL; |
| return ret; |
| } |
| |
| upb_symtab *DescriptorPool_GetSymbolTable() { |
| DescriptorPool *intern = GetPool(get_generated_pool()); |
| return intern->symtab; |
| } |
| |
| /* |
| * DescriptorPool::getGeneratedPool() |
| * |
| * Returns the generated DescriptorPool. |
| */ |
| PHP_METHOD(DescriptorPool, getGeneratedPool) { |
| zval ret; |
| ZVAL_COPY(&ret, get_generated_pool()); |
| RETURN_ZVAL(&ret, 0, 1); |
| } |
| |
| /* |
| * 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() TSRMLS_CC, "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_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * 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() TSRMLS_CC, "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_ZVAL(&ret, 1, 0); |
| } |
| |
| /* |
| * 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_msgdef *m; |
| |
| if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protoname, |
| &protoname_len) == FAILURE) { |
| return; |
| } |
| |
| if (*protoname == '.') protoname++; |
| |
| m = upb_symtab_lookupmsg(intern->symtab, protoname); |
| |
| if (m) { |
| zval ret; |
| ZVAL_OBJ(&ret, &Descriptor_GetFromMessageDef(m)->std); |
| RETURN_ZVAL(&ret, 1, 0); |
| } 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_strview *deps; |
| upb_strview name = upb_strview_makez("google/protobuf/descriptor.proto"); |
| size_t i, n; |
| |
| deps = google_protobuf_FileDescriptorProto_dependency(file, &n); |
| for (i = 0; i < n; i++) { |
| if (upb_strview_eql(deps[i], name)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /* |
| * add_name_mappings() |
| * |
| * Adds the messages and enums in this file to the NameMap. |
| */ |
| static void add_name_mappings(const upb_filedef *file) { |
| size_t i; |
| for (i = 0; i < upb_filedef_msgcount(file); i++) { |
| NameMap_AddMessage(upb_filedef_msg(file, i)); |
| } |
| |
| for (i = 0; i < upb_filedef_enumcount(file); i++) { |
| NameMap_AddEnum(upb_filedef_enum(file, i)); |
| } |
| } |
| |
| /* |
| * add_name_mappings() |
| * |
| * Adds the given descriptor data to this DescriptorPool. |
| */ |
| static void add_descriptor(DescriptorPool *pool, 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]; |
| upb_strview name = google_protobuf_FileDescriptorProto_name(file); |
| upb_status status; |
| const upb_filedef *file_def; |
| upb_status_clear(&status); |
| |
| if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) { |
| // Already added. |
| continue; |
| } |
| |
| // 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(pool->symtab); |
| } |
| |
| file_def = upb_symtab_addfile(pool->symtab, file, &status); |
| CheckUpbStatus(&status, "Unable to load descriptor"); |
| add_name_mappings(file_def); |
| } |
| } |
| |
| /* |
| * 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(intern, data, data_len, arena); |
| upb_arena_free(arena); |
| } |
| |
| static zend_function_entry DescriptorPool_methods[] = { |
| PHP_ME(DescriptorPool, getGeneratedPool, NULL, |
| ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
| PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(DescriptorPool, getDescriptorByProtoName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) |
| PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) |
| ZEND_FE_END |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // 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)); |
| |
| 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)); |
| |
| 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)); |
| |
| INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\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 = DescriptorPool_create; |
| h = &DescriptorPool_object_handlers; |
| memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); |
| h->dtor_obj = DescriptorPool_destructor; |
| |
| // 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 |
| } |