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 |