| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | |
| 2 // Copyright 2008 Google Inc. All rights reserved. | |
| 3 // https://developers.google.com/protocol-buffers/ | |
| 4 // | |
| 5 // Redistribution and use in source and binary forms, with or without | |
| 6 // modification, are permitted provided that the following conditions are | |
| 7 // met: | |
| 8 // | |
| 9 // * Redistributions of source code must retain the above copyright | |
| 10 // notice, this list of conditions and the following disclaimer. | |
| 11 // * Redistributions in binary form must reproduce the above | |
| 12 // copyright notice, this list of conditions and the following disclaimer | |
| 13 // in the documentation and/or other materials provided with the | |
| 14 // distribution. | |
| 15 // * Neither the name of Google Inc. nor the names of its | |
| 16 // contributors may be used to endorse or promote products derived from | |
| 17 // this software without specific prior written permission. | |
| 18 // | |
| 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 | |
| 31 #include "protobuf.h" | 1 #include "protobuf.h" |
| 32 | 2 |
| 33 // Forward declare. | |
| 34 static zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC); | |
| 35 static void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC); | |
| 36 static void descriptor_free_c(Descriptor* object TSRMLS_DC); | |
| 37 static void descriptor_free(void* object TSRMLS_DC); | |
| 38 | |
| 39 static zend_object_value enum_descriptor_create(zend_class_entry *ce TSRMLS_DC); | |
| 40 static void enum_descriptor_init_c_instance(EnumDescriptor* intern TSRMLS_DC); | |
| 41 static void enum_descriptor_free_c(EnumDescriptor* object TSRMLS_DC); | |
| 42 static void enum_descriptor_free(void* object TSRMLS_DC); | |
| 43 | |
| 44 static zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC); | |
| 45 static void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC); | |
| 46 static void descriptor_pool_free(void* object TSRMLS_DC); | |
| 47 static void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC); | |
| 48 | |
| 49 // ----------------------------------------------------------------------------- | 3 // ----------------------------------------------------------------------------- |
| 50 // Common Utilities | 4 // Common Utilities |
| 51 // ----------------------------------------------------------------------------- | 5 // ----------------------------------------------------------------------------- |
| 52 | 6 |
| 53 static void check_upb_status(const upb_status* status, const char* msg) { | 7 void check_upb_status(const upb_status* status, const char* msg) { |
| 54 if (!upb_ok(status)) { | 8 if (!upb_ok(status)) { |
| 55 zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status)); | 9 zend_error("%s: %s\n", msg, upb_status_errmsg(status)); |
| 56 } | 10 } |
| 57 } | 11 } |
| 58 | 12 |
| 59 static void upb_filedef_free(void *r) { | |
| 60 upb_filedef *f = *(upb_filedef **)r; | |
| 61 size_t i; | |
| 62 | 13 |
| 63 for (i = 0; i < upb_filedef_depcount(f); i++) { | 14 static upb_def *check_notfrozen(const upb_def *def) { |
| 64 upb_filedef_unref(upb_filedef_dep(f, i), f); | 15 if (upb_def_isfrozen(def)) { |
| 16 zend_error(E_ERROR, |
| 17 "Attempt to modify a frozen descriptor. Once descriptors are " |
| 18 "added to the descriptor pool, they may not be modified."); |
| 65 } | 19 } |
| 66 | 20 return (upb_def *)def; |
| 67 upb_inttable_uninit(&f->defs); | |
| 68 upb_inttable_uninit(&f->deps); | |
| 69 upb_gfree((void *)f->name); | |
| 70 upb_gfree((void *)f->package); | |
| 71 upb_gfree(f); | |
| 72 } | 21 } |
| 73 | 22 |
| 74 // Camel-case the field name and append "Entry" for generated map entry name. | 23 static upb_msgdef *check_msgdef_notfrozen(const upb_msgdef *def) { |
| 75 // e.g. map<KeyType, ValueType> foo_map => FooMapEntry | 24 return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def *)def)); |
| 76 static void append_map_entry_name(char *result, const char *field_name, | |
| 77 int pos) { | |
| 78 bool cap_next = true; | |
| 79 int i; | |
| 80 | |
| 81 for (i = 0; i < strlen(field_name); ++i) { | |
| 82 if (field_name[i] == '_') { | |
| 83 cap_next = true; | |
| 84 } else if (cap_next) { | |
| 85 // Note: Do not use ctype.h due to locales. | |
| 86 if ('a' <= field_name[i] && field_name[i] <= 'z') { | |
| 87 result[pos++] = field_name[i] - 'a' + 'A'; | |
| 88 } else { | |
| 89 result[pos++] = field_name[i]; | |
| 90 } | |
| 91 cap_next = false; | |
| 92 } else { | |
| 93 result[pos++] = field_name[i]; | |
| 94 } | |
| 95 } | |
| 96 strcat(result, "Entry"); | |
| 97 } | 25 } |
| 98 | 26 |
| 99 #define CHECK_UPB(code, msg) \ | 27 static upb_fielddef *check_fielddef_notfrozen(const upb_fielddef *def) { |
| 100 do { \ | 28 return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def *)def)); |
| 101 upb_status status = UPB_STATUS_INIT; \ | 29 } |
| 102 code; \ | |
| 103 check_upb_status(&status, msg); \ | |
| 104 } while (0) | |
| 105 | 30 |
| 106 // Define PHP class | 31 #define PROTOBUF_WRAP_INTERN(wrapper, intern, intern_dtor) \ |
| 107 #define DEFINE_PROTOBUF_INIT_CLASS(name_lower, string_name) \ | 32 Z_TYPE_P(wrapper) = IS_OBJECT; \ |
| 33 Z_OBJVAL_P(wrapper) \ |
| 34 .handle = zend_objects_store_put( \ |
| 35 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ |
| 36 intern_dtor, NULL TSRMLS_CC); \ |
| 37 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); |
| 38 |
| 39 #define PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ |
| 40 intern) \ |
| 41 Z_TYPE_P(wrapper) = IS_OBJECT; \ |
| 42 class_name *intern = ALLOC(class_name); \ |
| 43 memset(intern, 0, sizeof(class_name)); \ |
| 44 class_name_lower##_init_c_instance(intern TSRMLS_CC); \ |
| 45 Z_OBJVAL_P(wrapper) \ |
| 46 .handle = zend_objects_store_put(intern, NULL, class_name_lower##_free, \ |
| 47 NULL TSRMLS_CC); \ |
| 48 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); |
| 49 |
| 50 #define PROTOBUF_CREATE_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ |
| 51 intern) \ |
| 52 MAKE_STD_ZVAL(wrapper); \ |
| 53 PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, intern); |
| 54 |
| 55 #define DEFINE_CLASS(name, name_lower, string_name) \ |
| 56 zend_class_entry *name_lower##_type; \ |
| 108 void name_lower##_init(TSRMLS_D) { \ | 57 void name_lower##_init(TSRMLS_D) { \ |
| 109 zend_class_entry class_type; \ | 58 zend_class_entry class_type; \ |
| 110 INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \ | 59 INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \ |
| 111 name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ | 60 name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ |
| 112 name_lower##_type->create_object = name_lower##_create; \ | 61 name_lower##_type->create_object = name_lower##_create; \ |
| 62 } \ |
| 63 name *php_to_##name_lower(zval *val TSRMLS_DC) { \ |
| 64 return (name *)zend_object_store_get_object(val TSRMLS_CC); \ |
| 65 } \ |
| 66 void name_lower##_free(void *object TSRMLS_DC) { \ |
| 67 name *intern = (name *)object; \ |
| 68 name_lower##_free_c(intern TSRMLS_CC); \ |
| 69 efree(object); \ |
| 70 } \ |
| 71 zend_object_value name_lower##_create(zend_class_entry *ce TSRMLS_DC) { \ |
| 72 zend_object_value return_value; \ |
| 73 name *intern = (name *)emalloc(sizeof(name)); \ |
| 74 memset(intern, 0, sizeof(name)); \ |
| 75 name_lower##_init_c_instance(intern TSRMLS_CC); \ |
| 76 return_value.handle = zend_objects_store_put( \ |
| 77 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ |
| 78 name_lower##_free, NULL TSRMLS_CC); \ |
| 79 return_value.handlers = zend_get_std_object_handlers(); \ |
| 80 return return_value; \ |
| 113 } | 81 } |
| 114 | 82 |
| 115 #define DEFINE_PROTOBUF_CREATE(name, name_lower) \ | |
| 116 static zend_object_value name_lower##_create( \ | |
| 117 zend_class_entry* ce TSRMLS_DC) { \ | |
| 118 zend_object_value return_value; \ | |
| 119 name* intern = (name*)emalloc(sizeof(name)); \ | |
| 120 memset(intern, 0, sizeof(name)); \ | |
| 121 name_lower##_init_c_instance(intern TSRMLS_CC); \ | |
| 122 return_value.handle = zend_objects_store_put( \ | |
| 123 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ | |
| 124 name_lower##_free, NULL TSRMLS_CC); \ | |
| 125 return_value.handlers = zend_get_std_object_handlers(); \ | |
| 126 return return_value; \ | |
| 127 } | |
| 128 | |
| 129 #define DEFINE_PROTOBUF_FREE(name, name_lower) \ | |
| 130 static void name_lower##_free(void* object TSRMLS_DC) { \ | |
| 131 name* intern = (name*)object; \ | |
| 132 name_lower##_free_c(intern TSRMLS_CC); \ | |
| 133 efree(object); \ | |
| 134 } | |
| 135 | |
| 136 #define DEFINE_CLASS(name, name_lower, string_name) \ | |
| 137 zend_class_entry* name_lower##_type; \ | |
| 138 DEFINE_PROTOBUF_FREE(name, name_lower) \ | |
| 139 DEFINE_PROTOBUF_CREATE(name, name_lower) \ | |
| 140 DEFINE_PROTOBUF_INIT_CLASS(name_lower, string_name) | |
| 141 | |
| 142 // ----------------------------------------------------------------------------- | |
| 143 // GPBType | |
| 144 // ----------------------------------------------------------------------------- | |
| 145 | |
| 146 zend_class_entry* gpb_type_type; | |
| 147 | |
| 148 static zend_function_entry gpb_type_methods[] = { | |
| 149 ZEND_FE_END | |
| 150 }; | |
| 151 | |
| 152 void gpb_type_init(TSRMLS_D) { | |
| 153 zend_class_entry class_type; | |
| 154 INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType", | |
| 155 gpb_type_methods); | |
| 156 gpb_type_type = zend_register_internal_class(&class_type TSRMLS_CC); | |
| 157 zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1 TSRMLS_CC); | |
| 158 zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2 TSRMLS_CC); | |
| 159 zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3 TSRMLS_CC); | |
| 160 zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4 TSRMLS_CC); | |
| 161 zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5 TSRMLS_CC); | |
| 162 zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6 TSRMLS_CC); | |
| 163 zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7 TSRMLS_CC); | |
| 164 zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8 TSRMLS_CC); | |
| 165 zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9 TSRMLS_CC); | |
| 166 zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10 TSRMLS_CC); | |
| 167 zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11 TSRMLS_CC); | |
| 168 zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12 TSRMLS_CC); | |
| 169 zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13 TSRMLS_CC); | |
| 170 zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14 TSRMLS_CC); | |
| 171 zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), | |
| 172 15 TSRMLS_CC); | |
| 173 zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), | |
| 174 16 TSRMLS_CC); | |
| 175 zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17 TSRMLS_CC); | |
| 176 zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18 TSRMLS_CC); | |
| 177 } | |
| 178 | |
| 179 // ----------------------------------------------------------------------------- | 83 // ----------------------------------------------------------------------------- |
| 180 // DescriptorPool | 84 // DescriptorPool |
| 181 // ----------------------------------------------------------------------------- | 85 // ----------------------------------------------------------------------------- |
| 182 | 86 |
| 183 static zend_function_entry descriptor_pool_methods[] = { | 87 static zend_function_entry descriptor_pool_methods[] = { |
| 184 PHP_ME(DescriptorPool, getGeneratedPool, NULL, | 88 PHP_ME(DescriptorPool, addMessage, NULL, ZEND_ACC_PUBLIC) |
| 185 ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) | 89 PHP_ME(DescriptorPool, finalize, NULL, ZEND_ACC_PUBLIC) |
| 186 PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) | |
| 187 ZEND_FE_END | 90 ZEND_FE_END |
| 188 }; | 91 }; |
| 189 | 92 |
| 190 DEFINE_CLASS(DescriptorPool, descriptor_pool, | 93 DEFINE_CLASS(DescriptorPool, descriptor_pool, |
| 191 "Google\\Protobuf\\Internal\\DescriptorPool"); | 94 "Google\\Protobuf\\DescriptorPool"); |
| 192 | 95 |
| 193 zval* generated_pool_php; // wrapper of generated pool | |
| 194 DescriptorPool *generated_pool; // The actual generated pool | 96 DescriptorPool *generated_pool; // The actual generated pool |
| 195 | 97 |
| 196 static void init_generated_pool_once(TSRMLS_D) { | 98 ZEND_FUNCTION(get_generated_pool) { |
| 197 if (generated_pool_php == NULL) { | 99 if (PROTOBUF_G(generated_pool) == NULL) { |
| 198 MAKE_STD_ZVAL(generated_pool_php); | 100 MAKE_STD_ZVAL(PROTOBUF_G(generated_pool)); |
| 199 Z_TYPE_P(generated_pool_php) = IS_OBJECT; | 101 Z_TYPE_P(PROTOBUF_G(generated_pool)) = IS_OBJECT; |
| 200 generated_pool = ALLOC(DescriptorPool); | 102 generated_pool = ALLOC(DescriptorPool); |
| 201 descriptor_pool_init_c_instance(generated_pool TSRMLS_CC); | 103 descriptor_pool_init_c_instance(generated_pool TSRMLS_CC); |
| 202 Z_OBJ_HANDLE_P(generated_pool_php) = zend_objects_store_put( | 104 Z_OBJ_HANDLE_P(PROTOBUF_G(generated_pool)) = zend_objects_store_put( |
| 203 generated_pool, NULL, | 105 generated_pool, NULL, |
| 204 (zend_objects_free_object_storage_t)descriptor_pool_free, | 106 (zend_objects_free_object_storage_t)descriptor_pool_free, NULL TSRMLS_CC
); |
| 205 NULL TSRMLS_CC); | 107 Z_OBJ_HT_P(PROTOBUF_G(generated_pool)) = zend_get_std_object_handlers(); |
| 206 Z_OBJ_HT_P(generated_pool_php) = zend_get_std_object_handlers(); | |
| 207 } | 108 } |
| 109 RETURN_ZVAL(PROTOBUF_G(generated_pool), 1, 0); |
| 208 } | 110 } |
| 209 | 111 |
| 210 static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) { | 112 void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC) { |
| 211 zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC); | 113 zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC); |
| 212 pool->symtab = upb_symtab_new(&pool->symtab); | 114 pool->symtab = upb_symtab_new(&pool->symtab); |
| 213 | 115 |
| 214 ALLOC_HASHTABLE(pool->pending_list); | 116 ALLOC_HASHTABLE(pool->pending_list); |
| 215 zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); | 117 zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); |
| 216 } | 118 } |
| 217 | 119 |
| 218 static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { | 120 void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { |
| 219 upb_symtab_unref(pool->symtab, &pool->symtab); | 121 upb_symtab_unref(pool->symtab, &pool->symtab); |
| 220 | |
| 221 zend_hash_destroy(pool->pending_list); | 122 zend_hash_destroy(pool->pending_list); |
| 222 FREE_HASHTABLE(pool->pending_list); | 123 FREE_HASHTABLE(pool->pending_list); |
| 223 } | 124 } |
| 224 | 125 |
| 225 static void validate_enumdef(const upb_enumdef *enumdef) { | 126 PHP_METHOD(DescriptorPool, addMessage) { |
| 226 // Verify that an entry exists with integer value 0. (This is the default | 127 char *name = NULL; |
| 227 // value.) | 128 int str_len; |
| 228 const char *lookup = upb_enumdef_iton(enumdef, 0); | 129 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &str_len) == |
| 229 if (lookup == NULL) { | 130 FAILURE) { |
| 230 zend_error(E_USER_ERROR, | 131 return; |
| 231 "Enum definition does not contain a value for '0'."); | |
| 232 } | 132 } |
| 133 |
| 134 zval* retval = NULL; |
| 135 PROTOBUF_CREATE_ZEND_WRAPPER(MessageBuilderContext, message_builder_context, |
| 136 retval, context); |
| 137 |
| 138 MAKE_STD_ZVAL(context->pool); |
| 139 ZVAL_ZVAL(context->pool, getThis(), 1, 0); |
| 140 |
| 141 Descriptor *desc = php_to_descriptor(context->descriptor TSRMLS_CC); |
| 142 Descriptor_name_set(desc, name); |
| 143 |
| 144 RETURN_ZVAL(retval, 0, 1); |
| 233 } | 145 } |
| 234 | 146 |
| 235 static void validate_msgdef(const upb_msgdef* msgdef) { | 147 static void validate_msgdef(const upb_msgdef* msgdef) { |
| 236 // Verify that no required fields exist. proto3 does not support these. | 148 // Verify that no required fields exist. proto3 does not support these. |
| 237 upb_msg_field_iter it; | 149 upb_msg_field_iter it; |
| 238 for (upb_msg_field_begin(&it, msgdef); | 150 for (upb_msg_field_begin(&it, msgdef); |
| 239 !upb_msg_field_done(&it); | 151 !upb_msg_field_done(&it); |
| 240 upb_msg_field_next(&it)) { | 152 upb_msg_field_next(&it)) { |
| 241 const upb_fielddef* field = upb_msg_iter_field(&it); | 153 const upb_fielddef* field = upb_msg_iter_field(&it); |
| 242 if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { | 154 if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { |
| 243 zend_error(E_ERROR, "Required fields are unsupported in proto3."); | 155 zend_error(E_ERROR, "Required fields are unsupported in proto3."); |
| 244 } | 156 } |
| 245 } | 157 } |
| 246 } | 158 } |
| 247 | 159 |
| 248 PHP_METHOD(DescriptorPool, getGeneratedPool) { | 160 PHP_METHOD(DescriptorPool, finalize) { |
| 249 init_generated_pool_once(TSRMLS_C); | 161 DescriptorPool *self = php_to_descriptor_pool(getThis() TSRMLS_CC); |
| 250 RETURN_ZVAL(generated_pool_php, 1, 0); | 162 Bucket *temp; |
| 251 } | 163 int i, num; |
| 252 | 164 |
| 253 static void convert_to_class_name_inplace(char *class_name, | 165 num = zend_hash_num_elements(self->pending_list); |
| 254 const char* fullname, | 166 upb_def **defs = emalloc(sizeof(upb_def *) * num); |
| 255 const char* package_name) { | |
| 256 size_t i; | |
| 257 bool first_char = false; | |
| 258 size_t pkg_name_len = package_name == NULL ? 0 : strlen(package_name); | |
| 259 | 167 |
| 260 // In php, class name cannot be Empty. | 168 for (i = 0, temp = self->pending_list->pListHead; temp != NULL; |
| 261 if (strcmp("google.protobuf.Empty", fullname) == 0) { | 169 temp = temp->pListNext) { |
| 262 fullname = "google.protobuf.GPBEmpty"; | 170 zval *def_php = *(zval **)temp->pData; |
| 171 Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC); |
| 172 defs[i] = (upb_def *)desc->msgdef; |
| 173 validate_msgdef((const upb_msgdef *)defs[i++]); |
| 263 } | 174 } |
| 264 | 175 |
| 265 if (pkg_name_len == 0) { | 176 CHECK_UPB(upb_symtab_add(self->symtab, (upb_def **)defs, num, NULL, &status), |
| 266 strcpy(class_name, fullname); | 177 "Unable to add defs to DescriptorPool"); |
| 267 } else { | 178 |
| 268 class_name[0] = '.'; | 179 for (temp = self->pending_list->pListHead; temp != NULL; |
| 269 strcpy(&class_name[1], fullname); | 180 temp = temp->pListNext) { |
| 270 for (i = 0; i <= pkg_name_len + 1; i++) { | 181 // zval *def_php = *(zval **)temp->pData; |
| 271 // PHP package uses camel case. | 182 // Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC); |
| 272 if (!first_char && class_name[i] != '.') { | 183 build_class_from_descriptor((zval *)temp->pDataPtr TSRMLS_CC); |
| 273 first_char = true; | |
| 274 class_name[i] += 'A' - 'a'; | |
| 275 } | |
| 276 // php packages are divided by '\'. | |
| 277 if (class_name[i] == '.') { | |
| 278 first_char = false; | |
| 279 class_name[i] = '\\'; | |
| 280 } | |
| 281 } | |
| 282 } | 184 } |
| 283 | 185 |
| 284 // Submessage is concatenated with its containing messages by '_'. | 186 FREE(defs); |
| 285 for (i = pkg_name_len; i < strlen(class_name); i++) { | 187 zend_hash_destroy(self->pending_list); |
| 286 if (class_name[i] == '.') { | 188 zend_hash_init(self->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); |
| 287 class_name[i] = '_'; | |
| 288 } | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 PHP_METHOD(DescriptorPool, internalAddGeneratedFile) { | |
| 293 char *data = NULL; | |
| 294 int data_len; | |
| 295 upb_filedef **files; | |
| 296 size_t i; | |
| 297 | |
| 298 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == | |
| 299 FAILURE) { | |
| 300 return; | |
| 301 } | |
| 302 | |
| 303 DescriptorPool *pool = UNBOX(DescriptorPool, getThis()); | |
| 304 CHECK_UPB(files = upb_loaddescriptor(data, data_len, &pool, &status), | |
| 305 "Parse binary descriptors to internal descriptors failed"); | |
| 306 | |
| 307 // This method is called only once in each file. | |
| 308 assert(files[0] != NULL); | |
| 309 assert(files[1] == NULL); | |
| 310 | |
| 311 CHECK_UPB(upb_symtab_addfile(pool->symtab, files[0], &status), | |
| 312 "Unable to add file to DescriptorPool"); | |
| 313 | |
| 314 // For each enum/message, we need its PHP class, upb descriptor and its PHP | |
| 315 // wrapper. These information are needed later for encoding, decoding and type | |
| 316 // checking. However, sometimes we just have one of them. In order to find | |
| 317 // them quickly, here, we store the mapping for them. | |
| 318 for (i = 0; i < upb_filedef_defcount(files[0]); i++) { | |
| 319 const upb_def *def = upb_filedef_def(files[0], i); | |
| 320 switch (upb_def_type(def)) { | |
| 321 #define CASE_TYPE(def_type, def_type_lower, desc_type, desc_type_lower) \ | |
| 322 case UPB_DEF_##def_type: { \ | |
| 323 desc_type *desc; \ | |
| 324 zval *desc_php; \ | |
| 325 CREATE(desc_type, desc, desc_type_lower##_init_c_instance); \ | |
| 326 BOX(desc_type, desc_php, desc, desc_type_lower##_free); \ | |
| 327 Z_DELREF_P(desc_php); \ | |
| 328 const upb_##def_type_lower *def_type_lower = \ | |
| 329 upb_downcast_##def_type_lower(def); \ | |
| 330 desc->def_type_lower = def_type_lower; \ | |
| 331 add_def_obj(desc->def_type_lower, desc_php); \ | |
| 332 /* Unlike other messages, MapEntry is shared by all map fields and doesn't \ | |
| 333 * have generated PHP class.*/ \ | |
| 334 if (upb_def_type(def) == UPB_DEF_MSG && \ | |
| 335 upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \ | |
| 336 break; \ | |
| 337 } \ | |
| 338 /* Prepend '.' to package name to make it absolute. In the 5 additional \ | |
| 339 * bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if \ | |
| 340 * given message is google.protobuf.Empty.*/ \ | |
| 341 const char *fullname = upb_##def_type_lower##_fullname(def_type_lower); \ | |
| 342 char *klass_name = ecalloc(sizeof(char), 5 + strlen(fullname)); \ | |
| 343 convert_to_class_name_inplace(klass_name, fullname, \ | |
| 344 upb_filedef_package(files[0])); \ | |
| 345 zend_class_entry **pce; \ | |
| 346 if (zend_lookup_class(klass_name, strlen(klass_name), &pce TSRMLS_CC) == \ | |
| 347 FAILURE) { \ | |
| 348 zend_error(E_ERROR, "Generated message class %s hasn't been defined", \ | |
| 349 klass_name); \ | |
| 350 return; \ | |
| 351 } else { \ | |
| 352 desc->klass = *pce; \ | |
| 353 } \ | |
| 354 add_ce_obj(desc->klass, desc_php); \ | |
| 355 efree(klass_name); \ | |
| 356 break; \ | |
| 357 } | |
| 358 | |
| 359 CASE_TYPE(MSG, msgdef, Descriptor, descriptor) | |
| 360 CASE_TYPE(ENUM, enumdef, EnumDescriptor, enum_descriptor) | |
| 361 #undef CASE_TYPE | |
| 362 | |
| 363 default: | |
| 364 break; | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 for (i = 0; i < upb_filedef_defcount(files[0]); i++) { | |
| 369 const upb_def *def = upb_filedef_def(files[0], i); | |
| 370 if (upb_def_type(def) == UPB_DEF_MSG) { | |
| 371 const upb_msgdef *msgdef = upb_downcast_msgdef(def); | |
| 372 zval *desc_php = get_def_obj(msgdef); | |
| 373 build_class_from_descriptor(desc_php TSRMLS_CC); | |
| 374 } | |
| 375 } | |
| 376 | |
| 377 upb_filedef_unref(files[0], &pool); | |
| 378 upb_gfree(files); | |
| 379 } | 189 } |
| 380 | 190 |
| 381 // ----------------------------------------------------------------------------- | 191 // ----------------------------------------------------------------------------- |
| 382 // Descriptor | 192 // Descriptor |
| 383 // ----------------------------------------------------------------------------- | 193 // ----------------------------------------------------------------------------- |
| 384 | 194 |
| 385 static zend_function_entry descriptor_methods[] = { | 195 static zend_function_entry descriptor_methods[] = { |
| 386 ZEND_FE_END | 196 ZEND_FE_END |
| 387 }; | 197 }; |
| 388 | 198 |
| 389 DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Internal\\Descriptor"); | 199 DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor"); |
| 390 | 200 |
| 391 static void descriptor_free_c(Descriptor *self TSRMLS_DC) { | 201 void descriptor_free_c(Descriptor *self TSRMLS_DC) { |
| 202 upb_msg_field_iter iter; |
| 203 upb_msg_field_begin(&iter, self->msgdef); |
| 204 while (!upb_msg_field_done(&iter)) { |
| 205 upb_fielddef *fielddef = upb_msg_iter_field(&iter); |
| 206 upb_fielddef_unref(fielddef, &fielddef); |
| 207 upb_msg_field_next(&iter); |
| 208 } |
| 209 upb_msgdef_unref(self->msgdef, &self->msgdef); |
| 392 if (self->layout) { | 210 if (self->layout) { |
| 393 free_layout(self->layout); | 211 free_layout(self->layout); |
| 394 } | 212 } |
| 395 if (self->fill_handlers) { | |
| 396 upb_handlers_unref(self->fill_handlers, &self->fill_handlers); | |
| 397 } | |
| 398 if (self->fill_method) { | |
| 399 upb_pbdecodermethod_unref(self->fill_method, &self->fill_method); | |
| 400 } | |
| 401 if (self->pb_serialize_handlers) { | |
| 402 upb_handlers_unref(self->pb_serialize_handlers, | |
| 403 &self->pb_serialize_handlers); | |
| 404 } | |
| 405 } | 213 } |
| 406 | 214 |
| 407 static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) { | 215 static void descriptor_add_field(Descriptor *desc, |
| 216 const upb_fielddef *fielddef) { |
| 217 upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef); |
| 218 upb_fielddef *mut_field_def = check_fielddef_notfrozen(fielddef); |
| 219 CHECK_UPB(upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status), |
| 220 "Adding field to Descriptor failed"); |
| 221 // add_def_obj(fielddef, obj); |
| 222 } |
| 223 |
| 224 void descriptor_init_c_instance(Descriptor* desc TSRMLS_DC) { |
| 408 zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC); | 225 zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC); |
| 409 desc->msgdef = NULL; | 226 desc->msgdef = upb_msgdef_new(&desc->msgdef); |
| 410 desc->layout = NULL; | 227 desc->layout = NULL; |
| 411 desc->klass = NULL; | 228 // MAKE_STD_ZVAL(intern->klass); |
| 412 desc->fill_handlers = NULL; | 229 // ZVAL_NULL(intern->klass); |
| 413 desc->fill_method = NULL; | |
| 414 desc->pb_serialize_handlers = NULL; | 230 desc->pb_serialize_handlers = NULL; |
| 415 } | 231 } |
| 416 | 232 |
| 417 // ----------------------------------------------------------------------------- | 233 void Descriptor_name_set(Descriptor *desc, const char *name) { |
| 418 // EnumDescriptor | 234 upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef); |
| 419 // ----------------------------------------------------------------------------- | 235 CHECK_UPB(upb_msgdef_setfullname(mut_def, name, &status), |
| 420 | 236 "Error setting Descriptor name"); |
| 421 static zend_function_entry enum_descriptor_methods[] = { | |
| 422 ZEND_FE_END | |
| 423 }; | |
| 424 | |
| 425 DEFINE_CLASS(EnumDescriptor, enum_descriptor, | |
| 426 "Google\\Protobuf\\Internal\\EnumDescriptor"); | |
| 427 | |
| 428 static void enum_descriptor_free_c(EnumDescriptor *self TSRMLS_DC) { | |
| 429 } | |
| 430 | |
| 431 static void enum_descriptor_init_c_instance(EnumDescriptor *self TSRMLS_DC) { | |
| 432 zend_object_std_init(&self->std, enum_descriptor_type TSRMLS_CC); | |
| 433 self->enumdef = NULL; | |
| 434 self->klass = NULL; | |
| 435 } | 237 } |
| 436 | 238 |
| 437 // ----------------------------------------------------------------------------- | 239 // ----------------------------------------------------------------------------- |
| 438 // FieldDescriptor | 240 // FieldDescriptor |
| 439 // ----------------------------------------------------------------------------- | 241 // ----------------------------------------------------------------------------- |
| 440 | 242 |
| 441 upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { | 243 static void field_descriptor_name_set(const upb_fielddef* fielddef, |
| 442 switch (type) { | 244 const char *name) { |
| 443 #define CASE(descriptor_type, type) \ | 245 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); |
| 444 case UPB_DESCRIPTOR_TYPE_##descriptor_type: \ | 246 CHECK_UPB(upb_fielddef_setname(mut_def, name, &status), |
| 445 return UPB_TYPE_##type; | 247 "Error setting FieldDescriptor name"); |
| 248 } |
| 446 | 249 |
| 447 CASE(FLOAT, FLOAT); | 250 static void field_descriptor_label_set(const upb_fielddef* fielddef, |
| 448 CASE(DOUBLE, DOUBLE); | 251 upb_label_t upb_label) { |
| 449 CASE(BOOL, BOOL); | 252 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); |
| 450 CASE(STRING, STRING); | 253 upb_fielddef_setlabel(mut_def, upb_label); |
| 451 CASE(BYTES, BYTES); | 254 } |
| 452 CASE(MESSAGE, MESSAGE); | 255 |
| 453 CASE(GROUP, MESSAGE); | 256 upb_fieldtype_t string_to_descriptortype(const char *type) { |
| 454 CASE(ENUM, ENUM); | 257 #define CONVERT(upb, str) \ |
| 455 CASE(INT32, INT32); | 258 if (!strcmp(type, str)) { \ |
| 456 CASE(INT64, INT64); | 259 return UPB_DESCRIPTOR_TYPE_##upb; \ |
| 457 CASE(UINT32, UINT32); | 260 } |
| 458 CASE(UINT64, UINT64); | 261 |
| 459 CASE(SINT32, INT32); | 262 CONVERT(FLOAT, "float"); |
| 460 CASE(SINT64, INT64); | 263 CONVERT(DOUBLE, "double"); |
| 461 CASE(FIXED32, UINT32); | 264 CONVERT(BOOL, "bool"); |
| 462 CASE(FIXED64, UINT64); | 265 CONVERT(STRING, "string"); |
| 463 CASE(SFIXED32, INT32); | 266 CONVERT(BYTES, "bytes"); |
| 464 CASE(SFIXED64, INT64); | 267 CONVERT(MESSAGE, "message"); |
| 268 CONVERT(GROUP, "group"); |
| 269 CONVERT(ENUM, "enum"); |
| 270 CONVERT(INT32, "int32"); |
| 271 CONVERT(INT64, "int64"); |
| 272 CONVERT(UINT32, "uint32"); |
| 273 CONVERT(UINT64, "uint64"); |
| 274 CONVERT(SINT32, "sint32"); |
| 275 CONVERT(SINT64, "sint64"); |
| 276 CONVERT(FIXED32, "fixed32"); |
| 277 CONVERT(FIXED64, "fixed64"); |
| 278 CONVERT(SFIXED32, "sfixed32"); |
| 279 CONVERT(SFIXED64, "sfixed64"); |
| 465 | 280 |
| 466 #undef CONVERT | 281 #undef CONVERT |
| 467 | 282 |
| 468 } | |
| 469 | |
| 470 zend_error(E_ERROR, "Unknown field type."); | 283 zend_error(E_ERROR, "Unknown field type."); |
| 471 return 0; | 284 return 0; |
| 472 } | 285 } |
| 286 |
| 287 static void field_descriptor_type_set(const upb_fielddef* fielddef, |
| 288 const char *type) { |
| 289 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); |
| 290 upb_fielddef_setdescriptortype(mut_def, string_to_descriptortype(type)); |
| 291 } |
| 292 |
| 293 static void field_descriptor_number_set(const upb_fielddef* fielddef, |
| 294 int number) { |
| 295 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); |
| 296 CHECK_UPB(upb_fielddef_setnumber(mut_def, number, &status), |
| 297 "Error setting field number"); |
| 298 } |
| 299 |
| 300 // ----------------------------------------------------------------------------- |
| 301 // MessageBuilderContext |
| 302 // ----------------------------------------------------------------------------- |
| 303 |
| 304 static zend_function_entry message_builder_context_methods[] = { |
| 305 PHP_ME(MessageBuilderContext, finalizeToPool, NULL, ZEND_ACC_PUBLIC) |
| 306 PHP_ME(MessageBuilderContext, optional, NULL, ZEND_ACC_PUBLIC) |
| 307 {NULL, NULL, NULL} |
| 308 }; |
| 309 |
| 310 DEFINE_CLASS(MessageBuilderContext, message_builder_context, |
| 311 "Google\\Protobuf\\Internal\\MessageBuilderContext"); |
| 312 |
| 313 void message_builder_context_free_c(MessageBuilderContext *context TSRMLS_DC) { |
| 314 zval_ptr_dtor(&context->descriptor); |
| 315 zval_ptr_dtor(&context->pool); |
| 316 } |
| 317 |
| 318 void message_builder_context_init_c_instance( |
| 319 MessageBuilderContext *context TSRMLS_DC) { |
| 320 zend_object_std_init(&context->std, message_builder_context_type TSRMLS_CC); |
| 321 PROTOBUF_CREATE_ZEND_WRAPPER(Descriptor, descriptor, context->descriptor, |
| 322 desc); |
| 323 } |
| 324 |
| 325 static void msgdef_add_field(Descriptor *desc, upb_label_t upb_label, |
| 326 const char *name, const char *type, int number, |
| 327 const char *type_class) { |
| 328 upb_fielddef *fielddef = upb_fielddef_new(&fielddef); |
| 329 upb_fielddef_setpacked(fielddef, false); |
| 330 |
| 331 field_descriptor_label_set(fielddef, upb_label); |
| 332 field_descriptor_name_set(fielddef, name); |
| 333 field_descriptor_type_set(fielddef, type); |
| 334 field_descriptor_number_set(fielddef, number); |
| 335 |
| 336 // // if (type_class != Qnil) { |
| 337 // // if (TYPE(type_class) != T_STRING) { |
| 338 // // rb_raise(rb_eArgError, "Expected string for type class"); |
| 339 // // } |
| 340 // // // Make it an absolute type name by prepending a dot. |
| 341 // // type_class = rb_str_append(rb_str_new2("."), type_class); |
| 342 // // rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class); |
| 343 // // } |
| 344 descriptor_add_field(desc, fielddef); |
| 345 } |
| 346 |
| 347 PHP_METHOD(MessageBuilderContext, optional) { |
| 348 MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_
CC); |
| 349 Descriptor *desc = php_to_descriptor(self->descriptor TSRMLS_CC); |
| 350 // VALUE name, type, number, type_class; |
| 351 const char *name, *type, *type_class; |
| 352 int number, name_str_len, type_str_len, type_class_str_len; |
| 353 if (ZEND_NUM_ARGS() == 3) { |
| 354 if (zend_parse_parameters(3 TSRMLS_CC, "ssl", &name, |
| 355 &name_str_len, &type, &type_str_len, &number) == F
AILURE) { |
| 356 return; |
| 357 } |
| 358 } else { |
| 359 if (zend_parse_parameters(4 TSRMLS_CC, "ssls", &name, |
| 360 &name_str_len, &type, &type_str_len, &number, &typ
e_class, |
| 361 &type_class_str_len) == FAILURE) { |
| 362 return; |
| 363 } |
| 364 } |
| 365 |
| 366 msgdef_add_field(desc, UPB_LABEL_OPTIONAL, name, type, number, type_class); |
| 367 |
| 368 zval_copy_ctor(getThis()); |
| 369 RETURN_ZVAL(getThis(), 1, 0); |
| 370 } |
| 371 |
| 372 PHP_METHOD(MessageBuilderContext, finalizeToPool) { |
| 373 MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_
CC); |
| 374 DescriptorPool *pool = php_to_descriptor_pool(self->pool TSRMLS_CC); |
| 375 Descriptor* desc = php_to_descriptor(self->descriptor TSRMLS_CC); |
| 376 |
| 377 Z_ADDREF_P(self->descriptor); |
| 378 zend_hash_next_index_insert(pool->pending_list, &self->descriptor, |
| 379 sizeof(zval *), NULL); |
| 380 RETURN_ZVAL(self->pool, 1, 0); |
| 381 } |
| OLD | NEW |