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 |