| 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 |
| 1 #include "protobuf.h" | 31 #include "protobuf.h" |
| 2 | 32 |
| 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 |
| 3 // ----------------------------------------------------------------------------- | 49 // ----------------------------------------------------------------------------- |
| 4 // Common Utilities | 50 // Common Utilities |
| 5 // ----------------------------------------------------------------------------- | 51 // ----------------------------------------------------------------------------- |
| 6 | 52 |
| 7 void check_upb_status(const upb_status* status, const char* msg) { | 53 static void check_upb_status(const upb_status* status, const char* msg) { |
| 8 if (!upb_ok(status)) { | 54 if (!upb_ok(status)) { |
| 9 zend_error("%s: %s\n", msg, upb_status_errmsg(status)); | 55 zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status)); |
| 10 } | 56 } |
| 11 } | 57 } |
| 12 | 58 |
| 13 | 59 static void upb_filedef_free(void *r) { |
| 14 static upb_def *check_notfrozen(const upb_def *def) { | 60 upb_filedef *f = *(upb_filedef **)r; |
| 15 if (upb_def_isfrozen(def)) { | 61 size_t i; |
| 16 zend_error(E_ERROR, | 62 |
| 17 "Attempt to modify a frozen descriptor. Once descriptors are " | 63 for (i = 0; i < upb_filedef_depcount(f); i++) { |
| 18 "added to the descriptor pool, they may not be modified."); | 64 upb_filedef_unref(upb_filedef_dep(f, i), f); |
| 19 } | 65 } |
| 20 return (upb_def *)def; | 66 |
| 21 } | 67 upb_inttable_uninit(&f->defs); |
| 22 | 68 upb_inttable_uninit(&f->deps); |
| 23 static upb_msgdef *check_msgdef_notfrozen(const upb_msgdef *def) { | 69 upb_gfree((void *)f->name); |
| 24 return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def *)def)); | 70 upb_gfree((void *)f->package); |
| 25 } | 71 upb_gfree(f); |
| 26 | 72 } |
| 27 static upb_fielddef *check_fielddef_notfrozen(const upb_fielddef *def) { | 73 |
| 28 return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def *)def)); | 74 // Camel-case the field name and append "Entry" for generated map entry name. |
| 29 } | 75 // e.g. map<KeyType, ValueType> foo_map => FooMapEntry |
| 30 | 76 static void append_map_entry_name(char *result, const char *field_name, |
| 31 #define PROTOBUF_WRAP_INTERN(wrapper, intern, intern_dtor) \ | 77 int pos) { |
| 32 Z_TYPE_P(wrapper) = IS_OBJECT; \ | 78 bool cap_next = true; |
| 33 Z_OBJVAL_P(wrapper) \ | 79 int i; |
| 34 .handle = zend_objects_store_put( \ | 80 |
| 35 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ | 81 for (i = 0; i < strlen(field_name); ++i) { |
| 36 intern_dtor, NULL TSRMLS_CC); \ | 82 if (field_name[i] == '_') { |
| 37 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); | 83 cap_next = true; |
| 38 | 84 } else if (cap_next) { |
| 39 #define PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ | 85 // Note: Do not use ctype.h due to locales. |
| 40 intern) \ | 86 if ('a' <= field_name[i] && field_name[i] <= 'z') { |
| 41 Z_TYPE_P(wrapper) = IS_OBJECT; \ | 87 result[pos++] = field_name[i] - 'a' + 'A'; |
| 42 class_name *intern = ALLOC(class_name); \ | 88 } else { |
| 43 memset(intern, 0, sizeof(class_name)); \ | 89 result[pos++] = field_name[i]; |
| 44 class_name_lower##_init_c_instance(intern TSRMLS_CC); \ | 90 } |
| 45 Z_OBJVAL_P(wrapper) \ | 91 cap_next = false; |
| 46 .handle = zend_objects_store_put(intern, NULL, class_name_lower##_free, \ | 92 } else { |
| 47 NULL TSRMLS_CC); \ | 93 result[pos++] = field_name[i]; |
| 48 Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); | 94 } |
| 49 | 95 } |
| 50 #define PROTOBUF_CREATE_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ | 96 strcat(result, "Entry"); |
| 51 intern) \ | 97 } |
| 52 MAKE_STD_ZVAL(wrapper); \ | 98 |
| 53 PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, intern); | 99 #define CHECK_UPB(code, msg) \ |
| 54 | 100 do { \ |
| 55 #define DEFINE_CLASS(name, name_lower, string_name) \ | 101 upb_status status = UPB_STATUS_INIT; \ |
| 56 zend_class_entry *name_lower##_type; \ | 102 code; \ |
| 103 check_upb_status(&status, msg); \ |
| 104 } while (0) |
| 105 |
| 106 // Define PHP class |
| 107 #define DEFINE_PROTOBUF_INIT_CLASS(name_lower, string_name) \ |
| 57 void name_lower##_init(TSRMLS_D) { \ | 108 void name_lower##_init(TSRMLS_D) { \ |
| 58 zend_class_entry class_type; \ | 109 zend_class_entry class_type; \ |
| 59 INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \ | 110 INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \ |
| 60 name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ | 111 name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ |
| 61 name_lower##_type->create_object = name_lower##_create; \ | 112 name_lower##_type->create_object = name_lower##_create; \ |
| 62 } \ | 113 } |
| 63 name *php_to_##name_lower(zval *val TSRMLS_DC) { \ | 114 |
| 64 return (name *)zend_object_store_get_object(val TSRMLS_CC); \ | 115 #define DEFINE_PROTOBUF_CREATE(name, name_lower) \ |
| 65 } \ | 116 static zend_object_value name_lower##_create( \ |
| 66 void name_lower##_free(void *object TSRMLS_DC) { \ | 117 zend_class_entry* ce TSRMLS_DC) { \ |
| 67 name *intern = (name *)object; \ | 118 zend_object_value return_value; \ |
| 68 name_lower##_free_c(intern TSRMLS_CC); \ | 119 name* intern = (name*)emalloc(sizeof(name)); \ |
| 69 efree(object); \ | 120 memset(intern, 0, sizeof(name)); \ |
| 70 } \ | 121 name_lower##_init_c_instance(intern TSRMLS_CC); \ |
| 71 zend_object_value name_lower##_create(zend_class_entry *ce TSRMLS_DC) { \ | 122 return_value.handle = zend_objects_store_put( \ |
| 72 zend_object_value return_value; \ | 123 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ |
| 73 name *intern = (name *)emalloc(sizeof(name)); \ | 124 name_lower##_free, NULL TSRMLS_CC); \ |
| 74 memset(intern, 0, sizeof(name)); \ | 125 return_value.handlers = zend_get_std_object_handlers(); \ |
| 75 name_lower##_init_c_instance(intern TSRMLS_CC); \ | 126 return return_value; \ |
| 76 return_value.handle = zend_objects_store_put( \ | 127 } |
| 77 intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ | 128 |
| 78 name_lower##_free, NULL TSRMLS_CC); \ | 129 #define DEFINE_PROTOBUF_FREE(name, name_lower) \ |
| 79 return_value.handlers = zend_get_std_object_handlers(); \ | 130 static void name_lower##_free(void* object TSRMLS_DC) { \ |
| 80 return return_value; \ | 131 name* intern = (name*)object; \ |
| 81 } | 132 name_lower##_free_c(intern TSRMLS_CC); \ |
| 82 | 133 efree(object); \ |
| 83 // ----------------------------------------------------------------------------- | 134 } |
| 84 // DescriptorPool | 135 |
| 85 // ----------------------------------------------------------------------------- | 136 #define DEFINE_CLASS(name, name_lower, string_name) \ |
| 86 | 137 zend_class_entry* name_lower##_type; \ |
| 87 static zend_function_entry descriptor_pool_methods[] = { | 138 DEFINE_PROTOBUF_FREE(name, name_lower) \ |
| 88 PHP_ME(DescriptorPool, addMessage, NULL, ZEND_ACC_PUBLIC) | 139 DEFINE_PROTOBUF_CREATE(name, name_lower) \ |
| 89 PHP_ME(DescriptorPool, finalize, NULL, ZEND_ACC_PUBLIC) | 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[] = { |
| 90 ZEND_FE_END | 149 ZEND_FE_END |
| 91 }; | 150 }; |
| 92 | 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 // ----------------------------------------------------------------------------- |
| 180 // DescriptorPool |
| 181 // ----------------------------------------------------------------------------- |
| 182 |
| 183 static zend_function_entry descriptor_pool_methods[] = { |
| 184 PHP_ME(DescriptorPool, getGeneratedPool, NULL, |
| 185 ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
| 186 PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) |
| 187 ZEND_FE_END |
| 188 }; |
| 189 |
| 93 DEFINE_CLASS(DescriptorPool, descriptor_pool, | 190 DEFINE_CLASS(DescriptorPool, descriptor_pool, |
| 94 "Google\\Protobuf\\DescriptorPool"); | 191 "Google\\Protobuf\\Internal\\DescriptorPool"); |
| 95 | 192 |
| 193 zval* generated_pool_php; // wrapper of generated pool |
| 96 DescriptorPool *generated_pool; // The actual generated pool | 194 DescriptorPool *generated_pool; // The actual generated pool |
| 97 | 195 |
| 98 ZEND_FUNCTION(get_generated_pool) { | 196 static void init_generated_pool_once(TSRMLS_D) { |
| 99 if (PROTOBUF_G(generated_pool) == NULL) { | 197 if (generated_pool_php == NULL) { |
| 100 MAKE_STD_ZVAL(PROTOBUF_G(generated_pool)); | 198 MAKE_STD_ZVAL(generated_pool_php); |
| 101 Z_TYPE_P(PROTOBUF_G(generated_pool)) = IS_OBJECT; | 199 Z_TYPE_P(generated_pool_php) = IS_OBJECT; |
| 102 generated_pool = ALLOC(DescriptorPool); | 200 generated_pool = ALLOC(DescriptorPool); |
| 103 descriptor_pool_init_c_instance(generated_pool TSRMLS_CC); | 201 descriptor_pool_init_c_instance(generated_pool TSRMLS_CC); |
| 104 Z_OBJ_HANDLE_P(PROTOBUF_G(generated_pool)) = zend_objects_store_put( | 202 Z_OBJ_HANDLE_P(generated_pool_php) = zend_objects_store_put( |
| 105 generated_pool, NULL, | 203 generated_pool, NULL, |
| 106 (zend_objects_free_object_storage_t)descriptor_pool_free, NULL TSRMLS_CC
); | 204 (zend_objects_free_object_storage_t)descriptor_pool_free, |
| 107 Z_OBJ_HT_P(PROTOBUF_G(generated_pool)) = zend_get_std_object_handlers(); | 205 NULL TSRMLS_CC); |
| 108 } | 206 Z_OBJ_HT_P(generated_pool_php) = zend_get_std_object_handlers(); |
| 109 RETURN_ZVAL(PROTOBUF_G(generated_pool), 1, 0); | 207 } |
| 110 } | 208 } |
| 111 | 209 |
| 112 void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC) { | 210 static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) { |
| 113 zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC); | 211 zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC); |
| 114 pool->symtab = upb_symtab_new(&pool->symtab); | 212 pool->symtab = upb_symtab_new(&pool->symtab); |
| 115 | 213 |
| 116 ALLOC_HASHTABLE(pool->pending_list); | 214 ALLOC_HASHTABLE(pool->pending_list); |
| 117 zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); | 215 zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); |
| 118 } | 216 } |
| 119 | 217 |
| 120 void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { | 218 static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { |
| 121 upb_symtab_unref(pool->symtab, &pool->symtab); | 219 upb_symtab_unref(pool->symtab, &pool->symtab); |
| 220 |
| 122 zend_hash_destroy(pool->pending_list); | 221 zend_hash_destroy(pool->pending_list); |
| 123 FREE_HASHTABLE(pool->pending_list); | 222 FREE_HASHTABLE(pool->pending_list); |
| 124 } | 223 } |
| 125 | 224 |
| 126 PHP_METHOD(DescriptorPool, addMessage) { | 225 static void validate_enumdef(const upb_enumdef *enumdef) { |
| 127 char *name = NULL; | 226 // Verify that an entry exists with integer value 0. (This is the default |
| 128 int str_len; | 227 // value.) |
| 129 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &str_len) == | 228 const char *lookup = upb_enumdef_iton(enumdef, 0); |
| 130 FAILURE) { | 229 if (lookup == NULL) { |
| 131 return; | 230 zend_error(E_USER_ERROR, |
| 231 "Enum definition does not contain a value for '0'."); |
| 132 } | 232 } |
| 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); | |
| 145 } | 233 } |
| 146 | 234 |
| 147 static void validate_msgdef(const upb_msgdef* msgdef) { | 235 static void validate_msgdef(const upb_msgdef* msgdef) { |
| 148 // Verify that no required fields exist. proto3 does not support these. | 236 // Verify that no required fields exist. proto3 does not support these. |
| 149 upb_msg_field_iter it; | 237 upb_msg_field_iter it; |
| 150 for (upb_msg_field_begin(&it, msgdef); | 238 for (upb_msg_field_begin(&it, msgdef); |
| 151 !upb_msg_field_done(&it); | 239 !upb_msg_field_done(&it); |
| 152 upb_msg_field_next(&it)) { | 240 upb_msg_field_next(&it)) { |
| 153 const upb_fielddef* field = upb_msg_iter_field(&it); | 241 const upb_fielddef* field = upb_msg_iter_field(&it); |
| 154 if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { | 242 if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { |
| 155 zend_error(E_ERROR, "Required fields are unsupported in proto3."); | 243 zend_error(E_ERROR, "Required fields are unsupported in proto3."); |
| 156 } | 244 } |
| 157 } | 245 } |
| 158 } | 246 } |
| 159 | 247 |
| 160 PHP_METHOD(DescriptorPool, finalize) { | 248 PHP_METHOD(DescriptorPool, getGeneratedPool) { |
| 161 DescriptorPool *self = php_to_descriptor_pool(getThis() TSRMLS_CC); | 249 init_generated_pool_once(TSRMLS_C); |
| 162 Bucket *temp; | 250 RETURN_ZVAL(generated_pool_php, 1, 0); |
| 163 int i, num; | 251 } |
| 164 | 252 |
| 165 num = zend_hash_num_elements(self->pending_list); | 253 static void convert_to_class_name_inplace(char *class_name, |
| 166 upb_def **defs = emalloc(sizeof(upb_def *) * num); | 254 const char* fullname, |
| 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); |
| 167 | 259 |
| 168 for (i = 0, temp = self->pending_list->pListHead; temp != NULL; | 260 // In php, class name cannot be Empty. |
| 169 temp = temp->pListNext) { | 261 if (strcmp("google.protobuf.Empty", fullname) == 0) { |
| 170 zval *def_php = *(zval **)temp->pData; | 262 fullname = "google.protobuf.GPBEmpty"; |
| 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++]); | |
| 174 } | 263 } |
| 175 | 264 |
| 176 CHECK_UPB(upb_symtab_add(self->symtab, (upb_def **)defs, num, NULL, &status), | 265 if (pkg_name_len == 0) { |
| 177 "Unable to add defs to DescriptorPool"); | 266 strcpy(class_name, fullname); |
| 178 | 267 } else { |
| 179 for (temp = self->pending_list->pListHead; temp != NULL; | 268 class_name[0] = '.'; |
| 180 temp = temp->pListNext) { | 269 strcpy(&class_name[1], fullname); |
| 181 // zval *def_php = *(zval **)temp->pData; | 270 for (i = 0; i <= pkg_name_len + 1; i++) { |
| 182 // Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC); | 271 // PHP package uses camel case. |
| 183 build_class_from_descriptor((zval *)temp->pDataPtr TSRMLS_CC); | 272 if (!first_char && class_name[i] != '.') { |
| 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 } |
| 184 } | 282 } |
| 185 | 283 |
| 186 FREE(defs); | 284 // Submessage is concatenated with its containing messages by '_'. |
| 187 zend_hash_destroy(self->pending_list); | 285 for (i = pkg_name_len; i < strlen(class_name); i++) { |
| 188 zend_hash_init(self->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); | 286 if (class_name[i] == '.') { |
| 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); |
| 189 } | 379 } |
| 190 | 380 |
| 191 // ----------------------------------------------------------------------------- | 381 // ----------------------------------------------------------------------------- |
| 192 // Descriptor | 382 // Descriptor |
| 193 // ----------------------------------------------------------------------------- | 383 // ----------------------------------------------------------------------------- |
| 194 | 384 |
| 195 static zend_function_entry descriptor_methods[] = { | 385 static zend_function_entry descriptor_methods[] = { |
| 196 ZEND_FE_END | 386 ZEND_FE_END |
| 197 }; | 387 }; |
| 198 | 388 |
| 199 DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor"); | 389 DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Internal\\Descriptor"); |
| 200 | 390 |
| 201 void descriptor_free_c(Descriptor *self TSRMLS_DC) { | 391 static 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); | |
| 210 if (self->layout) { | 392 if (self->layout) { |
| 211 free_layout(self->layout); | 393 free_layout(self->layout); |
| 212 } | 394 } |
| 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 } |
| 213 } | 405 } |
| 214 | 406 |
| 215 static void descriptor_add_field(Descriptor *desc, | 407 static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) { |
| 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) { | |
| 225 zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC); | 408 zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC); |
| 226 desc->msgdef = upb_msgdef_new(&desc->msgdef); | 409 desc->msgdef = NULL; |
| 227 desc->layout = NULL; | 410 desc->layout = NULL; |
| 228 // MAKE_STD_ZVAL(intern->klass); | 411 desc->klass = NULL; |
| 229 // ZVAL_NULL(intern->klass); | 412 desc->fill_handlers = NULL; |
| 413 desc->fill_method = NULL; |
| 230 desc->pb_serialize_handlers = NULL; | 414 desc->pb_serialize_handlers = NULL; |
| 231 } | 415 } |
| 232 | 416 |
| 233 void Descriptor_name_set(Descriptor *desc, const char *name) { | 417 // ----------------------------------------------------------------------------- |
| 234 upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef); | 418 // EnumDescriptor |
| 235 CHECK_UPB(upb_msgdef_setfullname(mut_def, name, &status), | 419 // ----------------------------------------------------------------------------- |
| 236 "Error setting Descriptor name"); | 420 |
| 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; |
| 237 } | 435 } |
| 238 | 436 |
| 239 // ----------------------------------------------------------------------------- | 437 // ----------------------------------------------------------------------------- |
| 240 // FieldDescriptor | 438 // FieldDescriptor |
| 241 // ----------------------------------------------------------------------------- | 439 // ----------------------------------------------------------------------------- |
| 242 | 440 |
| 243 static void field_descriptor_name_set(const upb_fielddef* fielddef, | 441 upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { |
| 244 const char *name) { | 442 switch (type) { |
| 245 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); | 443 #define CASE(descriptor_type, type) \ |
| 246 CHECK_UPB(upb_fielddef_setname(mut_def, name, &status), | 444 case UPB_DESCRIPTOR_TYPE_##descriptor_type: \ |
| 247 "Error setting FieldDescriptor name"); | 445 return UPB_TYPE_##type; |
| 248 } | |
| 249 | 446 |
| 250 static void field_descriptor_label_set(const upb_fielddef* fielddef, | 447 CASE(FLOAT, FLOAT); |
| 251 upb_label_t upb_label) { | 448 CASE(DOUBLE, DOUBLE); |
| 252 upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); | 449 CASE(BOOL, BOOL); |
| 253 upb_fielddef_setlabel(mut_def, upb_label); | 450 CASE(STRING, STRING); |
| 254 } | 451 CASE(BYTES, BYTES); |
| 255 | 452 CASE(MESSAGE, MESSAGE); |
| 256 upb_fieldtype_t string_to_descriptortype(const char *type) { | 453 CASE(GROUP, MESSAGE); |
| 257 #define CONVERT(upb, str) \ | 454 CASE(ENUM, ENUM); |
| 258 if (!strcmp(type, str)) { \ | 455 CASE(INT32, INT32); |
| 259 return UPB_DESCRIPTOR_TYPE_##upb; \ | 456 CASE(INT64, INT64); |
| 260 } | 457 CASE(UINT32, UINT32); |
| 261 | 458 CASE(UINT64, UINT64); |
| 262 CONVERT(FLOAT, "float"); | 459 CASE(SINT32, INT32); |
| 263 CONVERT(DOUBLE, "double"); | 460 CASE(SINT64, INT64); |
| 264 CONVERT(BOOL, "bool"); | 461 CASE(FIXED32, UINT32); |
| 265 CONVERT(STRING, "string"); | 462 CASE(FIXED64, UINT64); |
| 266 CONVERT(BYTES, "bytes"); | 463 CASE(SFIXED32, INT32); |
| 267 CONVERT(MESSAGE, "message"); | 464 CASE(SFIXED64, INT64); |
| 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"); | |
| 280 | 465 |
| 281 #undef CONVERT | 466 #undef CONVERT |
| 282 | 467 |
| 468 } |
| 469 |
| 283 zend_error(E_ERROR, "Unknown field type."); | 470 zend_error(E_ERROR, "Unknown field type."); |
| 284 return 0; | 471 return 0; |
| 285 } | 472 } |
| 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 |