• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "protobuf.h"
2 
3 // -----------------------------------------------------------------------------
4 // Common Utilities
5 // -----------------------------------------------------------------------------
6 
check_upb_status(const upb_status * status,const char * msg)7 void check_upb_status(const upb_status* status, const char* msg) {
8   if (!upb_ok(status)) {
9     zend_error("%s: %s\n", msg, upb_status_errmsg(status));
10   }
11 }
12 
13 
check_notfrozen(const upb_def * def)14 static upb_def *check_notfrozen(const upb_def *def) {
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.");
19   }
20   return (upb_def *)def;
21 }
22 
check_msgdef_notfrozen(const upb_msgdef * def)23 static upb_msgdef *check_msgdef_notfrozen(const upb_msgdef *def) {
24   return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def *)def));
25 }
26 
check_fielddef_notfrozen(const upb_fielddef * def)27 static upb_fielddef *check_fielddef_notfrozen(const upb_fielddef *def) {
28   return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def *)def));
29 }
30 
31 #define PROTOBUF_WRAP_INTERN(wrapper, intern, intern_dtor)            \
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;                                       \
57   void name_lower##_init(TSRMLS_D) {                                         \
58     zend_class_entry class_type;                                             \
59     INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods);         \
60     name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
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;                                                     \
81   }
82 
83 // -----------------------------------------------------------------------------
84 // DescriptorPool
85 // -----------------------------------------------------------------------------
86 
87 static zend_function_entry descriptor_pool_methods[] = {
88   PHP_ME(DescriptorPool, addMessage, NULL, ZEND_ACC_PUBLIC)
89   PHP_ME(DescriptorPool, finalize, NULL, ZEND_ACC_PUBLIC)
90   ZEND_FE_END
91 };
92 
93 DEFINE_CLASS(DescriptorPool, descriptor_pool,
94              "Google\\Protobuf\\DescriptorPool");
95 
96 DescriptorPool *generated_pool;  // The actual generated pool
97 
ZEND_FUNCTION(get_generated_pool)98 ZEND_FUNCTION(get_generated_pool) {
99   if (PROTOBUF_G(generated_pool) == NULL) {
100     MAKE_STD_ZVAL(PROTOBUF_G(generated_pool));
101     Z_TYPE_P(PROTOBUF_G(generated_pool)) = IS_OBJECT;
102     generated_pool = ALLOC(DescriptorPool);
103     descriptor_pool_init_c_instance(generated_pool TSRMLS_CC);
104     Z_OBJ_HANDLE_P(PROTOBUF_G(generated_pool)) = zend_objects_store_put(
105         generated_pool, NULL,
106         (zend_objects_free_object_storage_t)descriptor_pool_free, NULL TSRMLS_CC);
107     Z_OBJ_HT_P(PROTOBUF_G(generated_pool)) = zend_get_std_object_handlers();
108   }
109   RETURN_ZVAL(PROTOBUF_G(generated_pool), 1, 0);
110 }
111 
descriptor_pool_init_c_instance(DescriptorPool * pool TSRMLS_DC)112 void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC) {
113   zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC);
114   pool->symtab = upb_symtab_new(&pool->symtab);
115 
116   ALLOC_HASHTABLE(pool->pending_list);
117   zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
118 }
119 
descriptor_pool_free_c(DescriptorPool * pool TSRMLS_DC)120 void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) {
121   upb_symtab_unref(pool->symtab, &pool->symtab);
122   zend_hash_destroy(pool->pending_list);
123   FREE_HASHTABLE(pool->pending_list);
124 }
125 
PHP_METHOD(DescriptorPool,addMessage)126 PHP_METHOD(DescriptorPool, addMessage) {
127   char *name = NULL;
128   int str_len;
129   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &str_len) ==
130       FAILURE) {
131     return;
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);
145 }
146 
validate_msgdef(const upb_msgdef * msgdef)147 static void validate_msgdef(const upb_msgdef* msgdef) {
148   // Verify that no required fields exist. proto3 does not support these.
149   upb_msg_field_iter it;
150   for (upb_msg_field_begin(&it, msgdef);
151        !upb_msg_field_done(&it);
152        upb_msg_field_next(&it)) {
153     const upb_fielddef* field = upb_msg_iter_field(&it);
154     if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
155       zend_error(E_ERROR, "Required fields are unsupported in proto3.");
156     }
157   }
158 }
159 
PHP_METHOD(DescriptorPool,finalize)160 PHP_METHOD(DescriptorPool, finalize) {
161   DescriptorPool *self = php_to_descriptor_pool(getThis() TSRMLS_CC);
162   Bucket *temp;
163   int i, num;
164 
165   num = zend_hash_num_elements(self->pending_list);
166   upb_def **defs = emalloc(sizeof(upb_def *) * num);
167 
168   for (i = 0, temp = self->pending_list->pListHead; temp != NULL;
169        temp = temp->pListNext) {
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++]);
174   }
175 
176   CHECK_UPB(upb_symtab_add(self->symtab, (upb_def **)defs, num, NULL, &status),
177             "Unable to add defs to DescriptorPool");
178 
179   for (temp = self->pending_list->pListHead; temp != NULL;
180        temp = temp->pListNext) {
181     // zval *def_php = *(zval **)temp->pData;
182     // Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC);
183     build_class_from_descriptor((zval *)temp->pDataPtr TSRMLS_CC);
184   }
185 
186   FREE(defs);
187   zend_hash_destroy(self->pending_list);
188   zend_hash_init(self->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
189 }
190 
191 // -----------------------------------------------------------------------------
192 // Descriptor
193 // -----------------------------------------------------------------------------
194 
195 static zend_function_entry descriptor_methods[] = {
196   ZEND_FE_END
197 };
198 
199 DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor");
200 
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);
210   if (self->layout) {
211     free_layout(self->layout);
212   }
213 }
214 
descriptor_add_field(Descriptor * desc,const upb_fielddef * fielddef)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 
descriptor_init_c_instance(Descriptor * desc TSRMLS_DC)224 void descriptor_init_c_instance(Descriptor* desc TSRMLS_DC) {
225   zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC);
226   desc->msgdef = upb_msgdef_new(&desc->msgdef);
227   desc->layout = NULL;
228   // MAKE_STD_ZVAL(intern->klass);
229   // ZVAL_NULL(intern->klass);
230   desc->pb_serialize_handlers = NULL;
231 }
232 
Descriptor_name_set(Descriptor * desc,const char * name)233 void Descriptor_name_set(Descriptor *desc, const char *name) {
234   upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef);
235   CHECK_UPB(upb_msgdef_setfullname(mut_def, name, &status),
236             "Error setting Descriptor name");
237 }
238 
239 // -----------------------------------------------------------------------------
240 // FieldDescriptor
241 // -----------------------------------------------------------------------------
242 
field_descriptor_name_set(const upb_fielddef * fielddef,const char * name)243 static void field_descriptor_name_set(const upb_fielddef* fielddef,
244                                       const char *name) {
245   upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
246   CHECK_UPB(upb_fielddef_setname(mut_def, name, &status),
247             "Error setting FieldDescriptor name");
248 }
249 
field_descriptor_label_set(const upb_fielddef * fielddef,upb_label_t upb_label)250 static void field_descriptor_label_set(const upb_fielddef* fielddef,
251                                        upb_label_t upb_label) {
252   upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef);
253   upb_fielddef_setlabel(mut_def, upb_label);
254 }
255 
string_to_descriptortype(const char * type)256 upb_fieldtype_t string_to_descriptortype(const char *type) {
257 #define CONVERT(upb, str)   \
258   if (!strcmp(type, str)) { \
259     return UPB_DESCRIPTOR_TYPE_##upb;  \
260   }
261 
262   CONVERT(FLOAT, "float");
263   CONVERT(DOUBLE, "double");
264   CONVERT(BOOL, "bool");
265   CONVERT(STRING, "string");
266   CONVERT(BYTES, "bytes");
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");
280 
281 #undef CONVERT
282 
283   zend_error(E_ERROR, "Unknown field type.");
284   return 0;
285 }
286 
field_descriptor_type_set(const upb_fielddef * fielddef,const char * type)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 
field_descriptor_number_set(const upb_fielddef * fielddef,int number)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 
message_builder_context_free_c(MessageBuilderContext * context TSRMLS_DC)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 
message_builder_context_init_c_instance(MessageBuilderContext * context TSRMLS_DC)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 
msgdef_add_field(Descriptor * desc,upb_label_t upb_label,const char * name,const char * type,int number,const char * type_class)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 
PHP_METHOD(MessageBuilderContext,optional)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) == FAILURE) {
356       return;
357     }
358   } else {
359     if (zend_parse_parameters(4 TSRMLS_CC, "ssls", &name,
360                               &name_str_len, &type, &type_str_len, &number, &type_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 
PHP_METHOD(MessageBuilderContext,finalizeToPool)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 }
382