• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "def.h"
32 
33 #include <php.h>
34 
35 // This is not self-contained: it must be after other Zend includes.
36 #include <Zend/zend_exceptions.h>
37 
38 #include "names.h"
39 #include "php-upb.h"
40 #include "protobuf.h"
41 
CheckUpbStatus(const upb_status * status,const char * msg)42 static void CheckUpbStatus(const upb_status* status, const char* msg) {
43   if (!upb_ok(status)) {
44     zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status));
45   }
46 }
47 
48 static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f);
49 
50 // We use this for objects that should not be created directly from PHP.
CreateHandler_ReturnNull(zend_class_entry * class_type)51 static zend_object *CreateHandler_ReturnNull(zend_class_entry *class_type) {
52   return NULL;  // Nobody should call this.
53 }
54 
55 
56 // -----------------------------------------------------------------------------
57 // EnumValueDescriptor
58 // -----------------------------------------------------------------------------
59 
60 typedef struct {
61   zend_object std;
62   const char *name;
63   int32_t number;
64 } EnumValueDescriptor;
65 
66 zend_class_entry *EnumValueDescriptor_class_entry;
67 static zend_object_handlers EnumValueDescriptor_object_handlers;
68 
69 /*
70  * EnumValueDescriptor_Make()
71  *
72  * Function to create an EnumValueDescriptor object from C.
73  */
EnumValueDescriptor_Make(zval * val,const char * name,int32_t number)74 static void EnumValueDescriptor_Make(zval *val, const char *name,
75                                      int32_t number) {
76   EnumValueDescriptor *intern = emalloc(sizeof(EnumValueDescriptor));
77   zend_object_std_init(&intern->std, EnumValueDescriptor_class_entry);
78   intern->std.handlers = &EnumValueDescriptor_object_handlers;
79   intern->name = name;
80   intern->number = number;
81   // Skip object_properties_init(), we don't allow derived classes.
82   ZVAL_OBJ(val, &intern->std);
83 }
84 
85 /*
86  * EnumValueDescriptor::getName()
87  *
88  * Returns the name for this enum value.
89  */
PHP_METHOD(EnumValueDescriptor,getName)90 PHP_METHOD(EnumValueDescriptor, getName) {
91   EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis());
92   RETURN_STRING(intern->name);
93 }
94 
95 /*
96  * EnumValueDescriptor::getNumber()
97  *
98  * Returns the number for this enum value.
99  */
PHP_METHOD(EnumValueDescriptor,getNumber)100 PHP_METHOD(EnumValueDescriptor, getNumber) {
101   EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis());
102   RETURN_LONG(intern->number);
103 }
104 
105 static zend_function_entry EnumValueDescriptor_methods[] = {
106   PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC)
107   PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
108   ZEND_FE_END
109 };
110 
111 // -----------------------------------------------------------------------------
112 // EnumDescriptor
113 // -----------------------------------------------------------------------------
114 
115 typedef struct {
116   zend_object std;
117   const upb_enumdef *enumdef;
118 } EnumDescriptor;
119 
120 zend_class_entry *EnumDescriptor_class_entry;
121 static zend_object_handlers EnumDescriptor_object_handlers;
122 
EnumDescriptor_FromClassEntry(zval * val,zend_class_entry * ce)123 void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) {
124   // To differentiate enums from classes, we pointer-tag the class entry.
125   void* key = (void*)((uintptr_t)ce | 1);
126   PBPHP_ASSERT(key != ce);
127 
128   if (ce == NULL) {
129     ZVAL_NULL(val);
130     return;
131   }
132 
133   if (!ObjCache_Get(key, val)) {
134     const upb_enumdef *e = NameMap_GetEnum(ce);
135     if (!e) {
136       ZVAL_NULL(val);
137       return;
138     }
139     EnumDescriptor* ret = emalloc(sizeof(EnumDescriptor));
140     zend_object_std_init(&ret->std, EnumDescriptor_class_entry);
141     ret->std.handlers = &EnumDescriptor_object_handlers;
142     ret->enumdef = e;
143     ObjCache_Add(key, &ret->std);
144 
145     // Prevent this from ever being collected (within a request).
146     GC_ADDREF(&ret->std);
147 
148     ZVAL_OBJ(val, &ret->std);
149   }
150 }
151 
EnumDescriptor_FromEnumDef(zval * val,const upb_enumdef * m)152 void EnumDescriptor_FromEnumDef(zval *val, const upb_enumdef *m) {
153   if (!m) {
154     ZVAL_NULL(val);
155   } else {
156     char *classname =
157         GetPhpClassname(upb_enumdef_file(m), upb_enumdef_fullname(m));
158     zend_string *str = zend_string_init(classname, strlen(classname), 0);
159     zend_class_entry *ce = zend_lookup_class(str);  // May autoload the class.
160 
161     zend_string_release (str);
162 
163     if (!ce) {
164       zend_error(E_ERROR, "Couldn't load generated class %s", classname);
165     }
166 
167     free(classname);
168     EnumDescriptor_FromClassEntry(val, ce);
169   }
170 }
171 
172 /*
173  * EnumDescriptor::getValue()
174  *
175  * Returns an EnumValueDescriptor for this index. Note: we are not looking
176  * up by numeric enum value, but by the index in the list of enum values.
177  */
PHP_METHOD(EnumDescriptor,getValue)178 PHP_METHOD(EnumDescriptor, getValue) {
179   EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis());
180   zend_long index;
181   zval ret;
182 
183   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
184     zend_error(E_USER_ERROR, "Expect integer for index.\n");
185     return;
186   }
187 
188   int field_num = upb_enumdef_numvals(intern->enumdef);
189   if (index < 0 || index >= field_num) {
190     zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
191     return;
192   }
193 
194   upb_enum_iter iter;
195   int i;
196   for(upb_enum_begin(&iter, intern->enumdef), i = 0;
197       !upb_enum_done(&iter) && i < index;
198       upb_enum_next(&iter), i++);
199 
200   EnumValueDescriptor_Make(&ret, upb_enum_iter_name(&iter),
201                            upb_enum_iter_number(&iter));
202   RETURN_ZVAL(&ret, 0, 1);
203 }
204 
205 /*
206  * EnumDescriptor::getValueCount()
207  *
208  * Returns the number of values in this enum.
209  */
PHP_METHOD(EnumDescriptor,getValueCount)210 PHP_METHOD(EnumDescriptor, getValueCount) {
211   EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis());
212   RETURN_LONG(upb_enumdef_numvals(intern->enumdef));
213 }
214 
215 /*
216  * EnumDescriptor::getPublicDescriptor()
217  *
218  * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not
219  * have two separate EnumDescriptor classes. We use a single class for both
220  * the public and private descriptor.
221  */
PHP_METHOD(EnumDescriptor,getPublicDescriptor)222 PHP_METHOD(EnumDescriptor, getPublicDescriptor) {
223   RETURN_ZVAL(getThis(), 1, 0);
224 }
225 
226 static zend_function_entry EnumDescriptor_methods[] = {
227   PHP_ME(EnumDescriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC)
228   PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC)
229   PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC)
230   ZEND_FE_END
231 };
232 
233 // -----------------------------------------------------------------------------
234 // Oneof
235 // -----------------------------------------------------------------------------
236 
237 typedef struct {
238   zend_object std;
239   const upb_oneofdef *oneofdef;
240 } OneofDescriptor;
241 
242 zend_class_entry *OneofDescriptor_class_entry;
243 static zend_object_handlers OneofDescriptor_object_handlers;
244 
OneofDescriptor_FromOneofDef(zval * val,const upb_oneofdef * o)245 static void OneofDescriptor_FromOneofDef(zval *val, const upb_oneofdef *o) {
246   if (o == NULL) {
247     ZVAL_NULL(val);
248     return;
249   }
250 
251   if (!ObjCache_Get(o, val)) {
252     OneofDescriptor* ret = emalloc(sizeof(OneofDescriptor));
253     zend_object_std_init(&ret->std, OneofDescriptor_class_entry);
254     ret->std.handlers = &OneofDescriptor_object_handlers;
255     ret->oneofdef = o;
256     ObjCache_Add(o, &ret->std);
257 
258     // Prevent this from ever being collected (within a request).
259     GC_ADDREF(&ret->std);
260 
261     ZVAL_OBJ(val, &ret->std);
262   }
263 }
264 
265 /*
266  * OneofDescriptor::getName()
267  *
268  * Returns the name of this oneof.
269  */
PHP_METHOD(OneofDescriptor,getName)270 PHP_METHOD(OneofDescriptor, getName) {
271   OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis());
272   RETURN_STRING(upb_oneofdef_name(intern->oneofdef));
273 }
274 
275 /*
276  * OneofDescriptor::getField()
277  *
278  * Returns a field from this oneof. The given index must be in the range
279  *   [0, getFieldCount() - 1].
280  */
PHP_METHOD(OneofDescriptor,getField)281 PHP_METHOD(OneofDescriptor, getField) {
282   OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis());
283   zend_long index;
284   zval ret;
285 
286   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
287     zend_error(E_USER_ERROR, "Expect integer for index.\n");
288     return;
289   }
290 
291   int field_num = upb_oneofdef_numfields(intern->oneofdef);
292   if (index < 0 || index >= field_num) {
293     zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
294     return;
295   }
296 
297   upb_oneof_iter iter;
298   int i;
299   for(upb_oneof_begin(&iter, intern->oneofdef), i = 0;
300       !upb_oneof_done(&iter) && i < index;
301       upb_oneof_next(&iter), i++);
302   const upb_fielddef *field = upb_oneof_iter_field(&iter);
303 
304   FieldDescriptor_FromFieldDef(&ret, field);
305   RETURN_ZVAL(&ret, 1, 0);
306 }
307 
308 /*
309  * OneofDescriptor::getFieldCount()
310  *
311  * Returns the number of fields in this oneof.
312  */
PHP_METHOD(OneofDescriptor,getFieldCount)313 PHP_METHOD(OneofDescriptor, getFieldCount) {
314   OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis());
315   RETURN_LONG(upb_oneofdef_numfields(intern->oneofdef));
316 }
317 
318 static zend_function_entry OneofDescriptor_methods[] = {
319   PHP_ME(OneofDescriptor, getName,  NULL, ZEND_ACC_PUBLIC)
320   PHP_ME(OneofDescriptor, getField, NULL, ZEND_ACC_PUBLIC)
321   PHP_ME(OneofDescriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC)
322   ZEND_FE_END
323 };
324 
325 // -----------------------------------------------------------------------------
326 // FieldDescriptor
327 // -----------------------------------------------------------------------------
328 
329 typedef struct {
330   zend_object std;
331   const upb_fielddef *fielddef;
332 } FieldDescriptor;
333 
334 zend_class_entry *FieldDescriptor_class_entry;
335 static zend_object_handlers FieldDescriptor_object_handlers;
336 
FieldDescriptor_FromFieldDef(zval * val,const upb_fielddef * f)337 static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f) {
338   if (f == NULL) {
339     ZVAL_NULL(val);
340     return;
341   }
342 
343   if (!ObjCache_Get(f, val)) {
344     FieldDescriptor* ret = emalloc(sizeof(FieldDescriptor));
345     zend_object_std_init(&ret->std, FieldDescriptor_class_entry);
346     ret->std.handlers = &FieldDescriptor_object_handlers;
347     ret->fielddef = f;
348     ObjCache_Add(f, &ret->std);
349 
350     // Prevent this from ever being collected (within a request).
351     GC_ADDREF(&ret->std);
352 
353     ZVAL_OBJ(val, &ret->std);
354   }
355 }
356 
to_fieldtype(upb_descriptortype_t type)357 upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) {
358   switch (type) {
359 #define CASE(descriptor_type, type)           \
360   case UPB_DESCRIPTOR_TYPE_##descriptor_type: \
361     return UPB_TYPE_##type;
362 
363   CASE(FLOAT,    FLOAT);
364   CASE(DOUBLE,   DOUBLE);
365   CASE(BOOL,     BOOL);
366   CASE(STRING,   STRING);
367   CASE(BYTES,    BYTES);
368   CASE(MESSAGE,  MESSAGE);
369   CASE(GROUP,    MESSAGE);
370   CASE(ENUM,     ENUM);
371   CASE(INT32,    INT32);
372   CASE(INT64,    INT64);
373   CASE(UINT32,   UINT32);
374   CASE(UINT64,   UINT64);
375   CASE(SINT32,   INT32);
376   CASE(SINT64,   INT64);
377   CASE(FIXED32,  UINT32);
378   CASE(FIXED64,  UINT64);
379   CASE(SFIXED32, INT32);
380   CASE(SFIXED64, INT64);
381 
382 #undef CONVERT
383 
384   }
385 
386   zend_error(E_ERROR, "Unknown field type.");
387   return 0;
388 }
389 
390 /*
391  * FieldDescriptor::getName()
392  *
393  * Returns the name of this field.
394  */
PHP_METHOD(FieldDescriptor,getName)395 PHP_METHOD(FieldDescriptor, getName) {
396   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
397   RETURN_STRING(upb_fielddef_name(intern->fielddef));
398 }
399 
400 /*
401  * FieldDescriptor::getNumber()
402  *
403  * Returns the number of this field.
404  */
PHP_METHOD(FieldDescriptor,getNumber)405 PHP_METHOD(FieldDescriptor, getNumber) {
406   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
407   RETURN_LONG(upb_fielddef_number(intern->fielddef));
408 }
409 
410 /*
411  * FieldDescriptor::getLabel()
412  *
413  * Returns the label of this field as an integer.
414  */
PHP_METHOD(FieldDescriptor,getLabel)415 PHP_METHOD(FieldDescriptor, getLabel) {
416   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
417   RETURN_LONG(upb_fielddef_label(intern->fielddef));
418 }
419 
420 /*
421  * FieldDescriptor::getType()
422  *
423  * Returns the type of this field as an integer.
424  */
PHP_METHOD(FieldDescriptor,getType)425 PHP_METHOD(FieldDescriptor, getType) {
426   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
427   RETURN_LONG(upb_fielddef_descriptortype(intern->fielddef));
428 }
429 
430 /*
431  * FieldDescriptor::isMap()
432  *
433  * Returns true if this field is a map.
434  */
PHP_METHOD(FieldDescriptor,isMap)435 PHP_METHOD(FieldDescriptor, isMap) {
436   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
437   RETURN_BOOL(upb_fielddef_ismap(intern->fielddef));
438 }
439 
440 /*
441  * FieldDescriptor::getEnumType()
442  *
443  * Returns the EnumDescriptor for this field, which must be an enum.
444  */
PHP_METHOD(FieldDescriptor,getEnumType)445 PHP_METHOD(FieldDescriptor, getEnumType) {
446   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
447   const upb_enumdef *e = upb_fielddef_enumsubdef(intern->fielddef);
448   zval ret;
449 
450   if (!e) {
451     zend_throw_exception_ex(NULL, 0,
452                             "Cannot get enum type for non-enum field '%s'",
453                             upb_fielddef_name(intern->fielddef));
454     return;
455   }
456 
457   EnumDescriptor_FromEnumDef(&ret, e);
458   RETURN_ZVAL(&ret, 1, 0);
459 }
460 
461 /*
462  * FieldDescriptor::getMessageType()
463  *
464  * Returns the Descriptor for this field, which must be a message.
465  */
PHP_METHOD(FieldDescriptor,getMessageType)466 PHP_METHOD(FieldDescriptor, getMessageType) {
467   FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis());
468   Descriptor* desc = Descriptor_GetFromFieldDef(intern->fielddef);
469   zval ret;
470 
471   if (!desc) {
472     zend_throw_exception_ex(
473         NULL, 0, "Cannot get message type for non-message field '%s'",
474         upb_fielddef_name(intern->fielddef));
475     return;
476   }
477 
478   ZVAL_OBJ(&ret, &desc->std);
479   RETURN_ZVAL(&ret, 1, 0);
480 }
481 
482 static zend_function_entry FieldDescriptor_methods[] = {
483   PHP_ME(FieldDescriptor, getName,   NULL, ZEND_ACC_PUBLIC)
484   PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
485   PHP_ME(FieldDescriptor, getLabel,  NULL, ZEND_ACC_PUBLIC)
486   PHP_ME(FieldDescriptor, getType,   NULL, ZEND_ACC_PUBLIC)
487   PHP_ME(FieldDescriptor, isMap,     NULL, ZEND_ACC_PUBLIC)
488   PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC)
489   PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC)
490   ZEND_FE_END
491 };
492 
493 // -----------------------------------------------------------------------------
494 // Descriptor
495 // -----------------------------------------------------------------------------
496 
497 zend_class_entry *Descriptor_class_entry;
498 static zend_object_handlers Descriptor_object_handlers;
499 
Descriptor_destructor(zend_object * obj)500 static void Descriptor_destructor(zend_object* obj) {
501   // We don't really need to do anything here, we don't allow this to be
502   // collected before the end of the request.
503 }
504 
505 // C Functions from def.h //////////////////////////////////////////////////////
506 
507 // These are documented in the header file.
508 
Descriptor_FromClassEntry(zval * val,zend_class_entry * ce)509 void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) {
510   if (ce == NULL) {
511     ZVAL_NULL(val);
512     return;
513   }
514 
515   if (!ObjCache_Get(ce, val)) {
516     const upb_msgdef *msgdef = NameMap_GetMessage(ce);
517     if (!msgdef) {
518       ZVAL_NULL(val);
519       return;
520     }
521     Descriptor* ret = emalloc(sizeof(Descriptor));
522     zend_object_std_init(&ret->std, Descriptor_class_entry);
523     ret->std.handlers = &Descriptor_object_handlers;
524     ret->class_entry = ce;
525     ret->msgdef = msgdef;
526     ObjCache_Add(ce, &ret->std);
527 
528     // Prevent this from ever being collected (within a request).
529     GC_ADDREF(&ret->std);
530 
531     ZVAL_OBJ(val, &ret->std);
532   }
533 }
534 
Descriptor_GetFromClassEntry(zend_class_entry * ce)535 Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) {
536   zval desc;
537   Descriptor_FromClassEntry(&desc, ce);
538   if (Z_TYPE_P(&desc) == IS_NULL) {
539     return NULL;
540   } else {
541     return (Descriptor*)Z_OBJ_P(&desc);
542   }
543 }
544 
Descriptor_GetFromMessageDef(const upb_msgdef * m)545 Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) {
546   if (m) {
547     if (upb_msgdef_mapentry(m)) {
548       // A bit of a hack, since map entries don't have classes.
549       Descriptor* ret = emalloc(sizeof(Descriptor));
550       zend_object_std_init(&ret->std, Descriptor_class_entry);
551       ret->std.handlers = &Descriptor_object_handlers;
552       ret->class_entry = NULL;
553       ret->msgdef = m;
554 
555       // Prevent this from ever being collected (within a request).
556       GC_ADDREF(&ret->std);
557 
558       return ret;
559     }
560 
561     char *classname =
562         GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m));
563     zend_string *str = zend_string_init(classname, strlen(classname), 0);
564     zend_class_entry *ce = zend_lookup_class(str);  // May autoload the class.
565 
566     zend_string_release (str);
567 
568     if (!ce) {
569       zend_error(E_ERROR, "Couldn't load generated class %s", classname);
570     }
571 
572     free(classname);
573     return Descriptor_GetFromClassEntry(ce);
574   } else {
575     return NULL;
576   }
577 }
578 
Descriptor_GetFromFieldDef(const upb_fielddef * f)579 Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) {
580   return Descriptor_GetFromMessageDef(upb_fielddef_msgsubdef(f));
581 }
582 
583 /*
584  * Descriptor::getPublicDescriptor()
585  *
586  * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not
587  * have two separate EnumDescriptor classes. We use a single class for both
588  * the public and private descriptor.
589  */
PHP_METHOD(Descriptor,getPublicDescriptor)590 PHP_METHOD(Descriptor, getPublicDescriptor) {
591   RETURN_ZVAL(getThis(), 1, 0);
592 }
593 
594 /*
595  * Descriptor::getFullName()
596  *
597  * Returns the full name for this message type.
598  */
PHP_METHOD(Descriptor,getFullName)599 PHP_METHOD(Descriptor, getFullName) {
600   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
601   RETURN_STRING(upb_msgdef_fullname(intern->msgdef));
602 }
603 
604 /*
605  * Descriptor::getField()
606  *
607  * Returns a FieldDescriptor for the given index, which must be in the range
608  * [0, getFieldCount()-1].
609  */
PHP_METHOD(Descriptor,getField)610 PHP_METHOD(Descriptor, getField) {
611   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
612   int count = upb_msgdef_numfields(intern->msgdef);
613   zval ret;
614   zend_long index;
615 
616   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
617     zend_error(E_USER_ERROR, "Expect integer for index.\n");
618     return;
619   }
620 
621   if (index < 0 || index >= count) {
622     zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
623     return;
624   }
625 
626   upb_msg_field_iter iter;
627   int i;
628   for(upb_msg_field_begin(&iter, intern->msgdef), i = 0;
629       !upb_msg_field_done(&iter) && i < index;
630       upb_msg_field_next(&iter), i++);
631   const upb_fielddef *field = upb_msg_iter_field(&iter);
632 
633   FieldDescriptor_FromFieldDef(&ret, field);
634   RETURN_ZVAL(&ret, 1, 0);
635 }
636 
637 /*
638  * Descriptor::getFieldCount()
639  *
640  * Returns the number of fields in this message.
641  */
PHP_METHOD(Descriptor,getFieldCount)642 PHP_METHOD(Descriptor, getFieldCount) {
643   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
644   RETURN_LONG(upb_msgdef_numfields(intern->msgdef));
645 }
646 
647 /*
648  * Descriptor::getOneofDecl()
649  *
650  * Returns a OneofDescriptor for the given index, which must be in the range
651  * [0, getOneofDeclCount()].
652  */
PHP_METHOD(Descriptor,getOneofDecl)653 PHP_METHOD(Descriptor, getOneofDecl) {
654   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
655   zend_long index;
656   zval ret;
657 
658   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
659     zend_error(E_USER_ERROR, "Expect integer for index.\n");
660     return;
661   }
662 
663   int field_num = upb_msgdef_numoneofs(intern->msgdef);
664   if (index < 0 || index >= field_num) {
665     zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
666     return;
667   }
668 
669   upb_msg_oneof_iter iter;
670   int i;
671   for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0;
672       !upb_msg_oneof_done(&iter) && i < index;
673       upb_msg_oneof_next(&iter), i++);
674   const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter);
675 
676   OneofDescriptor_FromOneofDef(&ret, oneof);
677   RETURN_ZVAL(&ret, 1, 0);
678 }
679 
680 /*
681  * Descriptor::getOneofDeclCount()
682  *
683  * Returns the number of oneofs in this message.
684  */
PHP_METHOD(Descriptor,getOneofDeclCount)685 PHP_METHOD(Descriptor, getOneofDeclCount) {
686   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
687   RETURN_LONG(upb_msgdef_numoneofs(intern->msgdef));
688 }
689 
690 /*
691  * Descriptor::getClass()
692  *
693  * Returns the name of the PHP class for this message.
694  */
PHP_METHOD(Descriptor,getClass)695 PHP_METHOD(Descriptor, getClass) {
696   Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis());
697   const char* classname = ZSTR_VAL(intern->class_entry->name);
698   RETURN_STRING(classname);
699 }
700 
701 
702 static zend_function_entry Descriptor_methods[] = {
703   PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC)
704   PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC)
705   PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC)
706   PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC)
707   PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC)
708   PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC)
709   PHP_ME(Descriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC)
710   ZEND_FE_END
711 };
712 
713 // -----------------------------------------------------------------------------
714 // DescriptorPool
715 // -----------------------------------------------------------------------------
716 
717 typedef struct DescriptorPool {
718   zend_object std;
719   upb_symtab *symtab;
720 } DescriptorPool;
721 
722 zend_class_entry *DescriptorPool_class_entry;
723 static zend_object_handlers DescriptorPool_object_handlers;
724 
GetPool(const zval * this_ptr)725 static DescriptorPool *GetPool(const zval* this_ptr) {
726   return (DescriptorPool*)Z_OBJ_P(this_ptr);
727 }
728 
729 /**
730  * Object handler to create an DescriptorPool.
731  */
DescriptorPool_create(zend_class_entry * class_type)732 static zend_object* DescriptorPool_create(zend_class_entry *class_type) {
733   DescriptorPool *intern = emalloc(sizeof(DescriptorPool));
734   zend_object_std_init(&intern->std, class_type);
735   intern->std.handlers = &DescriptorPool_object_handlers;
736   intern->symtab = upb_symtab_new();
737   // Skip object_properties_init(), we don't allow derived classes.
738   return &intern->std;
739 }
740 
741 /**
742  * Object handler to free an DescriptorPool.
743  */
DescriptorPool_destructor(zend_object * obj)744 static void DescriptorPool_destructor(zend_object* obj) {
745   DescriptorPool* intern = (DescriptorPool*)obj;
746   if (intern->symtab) {
747     upb_symtab_free(intern->symtab);
748   }
749   intern->symtab = NULL;
750   zend_object_std_dtor(&intern->std);
751 }
752 
DescriptorPool_CreateWithSymbolTable(zval * zv,upb_symtab * symtab)753 void DescriptorPool_CreateWithSymbolTable(zval *zv, upb_symtab *symtab) {
754   ZVAL_OBJ(zv, DescriptorPool_create(DescriptorPool_class_entry));
755 
756   if (symtab) {
757     DescriptorPool *intern = GetPool(zv);
758     upb_symtab_free(intern->symtab);
759     intern->symtab = symtab;
760   }
761 }
762 
DescriptorPool_Steal(zval * zv)763 upb_symtab *DescriptorPool_Steal(zval *zv) {
764   DescriptorPool *intern = GetPool(zv);
765   upb_symtab *ret = intern->symtab;
766   intern->symtab = NULL;
767   return ret;
768 }
769 
DescriptorPool_GetSymbolTable()770 upb_symtab *DescriptorPool_GetSymbolTable() {
771   DescriptorPool *intern = GetPool(get_generated_pool());
772   return intern->symtab;
773 }
774 
775 /*
776  * DescriptorPool::getGeneratedPool()
777  *
778  * Returns the generated DescriptorPool.
779  */
PHP_METHOD(DescriptorPool,getGeneratedPool)780 PHP_METHOD(DescriptorPool, getGeneratedPool) {
781   zval ret;
782   ZVAL_COPY(&ret, get_generated_pool());
783   RETURN_ZVAL(&ret, 0, 1);
784 }
785 
786 /*
787  * DescriptorPool::getDescriptorByClassName()
788  *
789  * Returns a Descriptor object for the given PHP class name.
790  */
PHP_METHOD(DescriptorPool,getDescriptorByClassName)791 PHP_METHOD(DescriptorPool, getDescriptorByClassName) {
792   char *classname = NULL;
793   zend_long classname_len;
794   zend_class_entry *ce;
795   zend_string *str;
796   zval ret;
797 
798   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &classname, &classname_len) ==
799       FAILURE) {
800     return;
801   }
802 
803   str = zend_string_init(classname, strlen(classname), 0);
804   ce = zend_lookup_class(str);  // May autoload the class.
805   zend_string_release (str);
806 
807   if (!ce) {
808     RETURN_NULL();
809   }
810 
811   Descriptor_FromClassEntry(&ret, ce);
812   RETURN_ZVAL(&ret, 1, 0);
813 }
814 
815 /*
816  * DescriptorPool::getEnumDescriptorByClassName()
817  *
818  * Returns a EnumDescriptor object for the given PHP class name.
819  */
PHP_METHOD(DescriptorPool,getEnumDescriptorByClassName)820 PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) {
821   char *classname = NULL;
822   zend_long classname_len;
823   zend_class_entry *ce;
824   zend_string *str;
825   zval ret;
826 
827   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &classname, &classname_len) ==
828       FAILURE) {
829     return;
830   }
831 
832   str = zend_string_init(classname, strlen(classname), 0);
833   ce = zend_lookup_class(str);  // May autoload the class.
834   zend_string_release (str);
835 
836   if (!ce) {
837     RETURN_NULL();
838   }
839 
840   EnumDescriptor_FromClassEntry(&ret, ce);
841   RETURN_ZVAL(&ret, 1, 0);
842 }
843 
844 /*
845  * DescriptorPool::getEnumDescriptorByProtoName()
846  *
847  * Returns a Descriptor object for the given protobuf message name.
848  */
PHP_METHOD(DescriptorPool,getDescriptorByProtoName)849 PHP_METHOD(DescriptorPool, getDescriptorByProtoName) {
850   DescriptorPool *intern = GetPool(getThis());
851   char *protoname = NULL;
852   zend_long protoname_len;
853   const upb_msgdef *m;
854 
855   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &protoname, &protoname_len) ==
856       FAILURE) {
857     return;
858   }
859 
860   if (*protoname == '.') protoname++;
861 
862   m = upb_symtab_lookupmsg(intern->symtab, protoname);
863 
864   if (m) {
865     zval ret;
866     ZVAL_OBJ(&ret, &Descriptor_GetFromMessageDef(m)->std);
867     RETURN_ZVAL(&ret, 1, 0);
868   } else {
869     RETURN_NULL();
870   }
871 }
872 
873 /*
874  * depends_on_descriptor()
875  *
876  * Returns true if this FileDescriptorProto depends on descriptor.proto.
877  */
depends_on_descriptor(const google_protobuf_FileDescriptorProto * file)878 bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) {
879   const upb_strview *deps;
880   upb_strview name = upb_strview_makez("google/protobuf/descriptor.proto");
881   size_t i, n;
882 
883   deps = google_protobuf_FileDescriptorProto_dependency(file, &n);
884   for (i = 0; i < n; i++) {
885     if (upb_strview_eql(deps[i], name)) {
886       return true;
887     }
888   }
889 
890   return false;
891 }
892 
893 /*
894  * add_name_mappings()
895  *
896  * Adds the messages and enums in this file to the NameMap.
897  */
add_name_mappings(const upb_filedef * file)898 static void add_name_mappings(const upb_filedef *file) {
899   size_t i;
900   for (i = 0; i < upb_filedef_msgcount(file); i++) {
901     NameMap_AddMessage(upb_filedef_msg(file, i));
902   }
903 
904   for (i = 0; i < upb_filedef_enumcount(file); i++) {
905     NameMap_AddEnum(upb_filedef_enum(file, i));
906   }
907 }
908 
909 /*
910  * add_name_mappings()
911  *
912  * Adds the given descriptor data to this DescriptorPool.
913  */
add_descriptor(DescriptorPool * pool,const char * data,int data_len,upb_arena * arena)914 static void add_descriptor(DescriptorPool *pool, const char *data,
915                            int data_len, upb_arena *arena) {
916   size_t i, n;
917   google_protobuf_FileDescriptorSet *set;
918   const google_protobuf_FileDescriptorProto* const* files;
919 
920   set = google_protobuf_FileDescriptorSet_parse(data, data_len, arena);
921 
922   if (!set) {
923     zend_error(E_ERROR, "Failed to parse binary descriptor\n");
924     return;
925   }
926 
927   files = google_protobuf_FileDescriptorSet_file(set, &n);
928 
929   for (i = 0; i < n; i++) {
930     const google_protobuf_FileDescriptorProto* file = files[i];
931     upb_strview name = google_protobuf_FileDescriptorProto_name(file);
932     upb_status status;
933     const upb_filedef *file_def;
934     upb_status_clear(&status);
935 
936     if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) {
937       // Already added.
938       continue;
939     }
940 
941     // The PHP code generator currently special-cases descriptor.proto.  It
942     // doesn't add it as a dependency even if the proto file actually does
943     // depend on it.
944     if (depends_on_descriptor(file)) {
945       google_protobuf_FileDescriptorProto_getmsgdef(pool->symtab);
946     }
947 
948     file_def = upb_symtab_addfile(pool->symtab, file, &status);
949     CheckUpbStatus(&status, "Unable to load descriptor");
950     add_name_mappings(file_def);
951   }
952 }
953 
954 /*
955  * DescriptorPool::internalAddGeneratedFile()
956  *
957  * Adds the given descriptor data to this DescriptorPool.
958  */
PHP_METHOD(DescriptorPool,internalAddGeneratedFile)959 PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
960   DescriptorPool *intern = GetPool(getThis());
961   char *data = NULL;
962   zend_long data_len;
963   zend_bool use_nested_submsg = false;
964   upb_arena *arena;
965 
966   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
967                             &use_nested_submsg) != SUCCESS) {
968     return;
969   }
970 
971   arena = upb_arena_new();
972   add_descriptor(intern, data, data_len, arena);
973   upb_arena_free(arena);
974 }
975 
976 static zend_function_entry DescriptorPool_methods[] = {
977   PHP_ME(DescriptorPool, getGeneratedPool, NULL,
978          ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
979   PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
980   PHP_ME(DescriptorPool, getDescriptorByProtoName, NULL, ZEND_ACC_PUBLIC)
981   PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
982   PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC)
983   ZEND_FE_END
984 };
985 
986 // -----------------------------------------------------------------------------
987 // GPBType
988 // -----------------------------------------------------------------------------
989 
990 zend_class_entry* gpb_type_type;
991 
992 static zend_function_entry gpb_type_methods[] = {
993   ZEND_FE_END
994 };
995 
996 // -----------------------------------------------------------------------------
997 // Module Init
998 // -----------------------------------------------------------------------------
999 
Def_ModuleInit()1000 void Def_ModuleInit() {
1001   zend_class_entry tmp_ce;
1002   zend_object_handlers *h;
1003 
1004   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\OneofDescriptor",
1005                    OneofDescriptor_methods);
1006   OneofDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
1007   OneofDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
1008   OneofDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
1009   h = &OneofDescriptor_object_handlers;
1010   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1011 
1012   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumValueDescriptor",
1013                    EnumValueDescriptor_methods);
1014   EnumValueDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
1015   EnumValueDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
1016   EnumValueDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
1017   h = &EnumValueDescriptor_object_handlers;
1018   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1019 
1020 
1021   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumDescriptor",
1022                    EnumDescriptor_methods);
1023   EnumDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
1024   EnumDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
1025   EnumDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
1026   h = &EnumDescriptor_object_handlers;
1027   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1028 
1029   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Descriptor",
1030                    Descriptor_methods);
1031 
1032   Descriptor_class_entry = zend_register_internal_class(&tmp_ce);
1033   Descriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
1034   Descriptor_class_entry->create_object = CreateHandler_ReturnNull;
1035   h = &Descriptor_object_handlers;
1036   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1037   h->dtor_obj = Descriptor_destructor;
1038 
1039   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\FieldDescriptor",
1040                    FieldDescriptor_methods);
1041   FieldDescriptor_class_entry = zend_register_internal_class(&tmp_ce);
1042   FieldDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL;
1043   FieldDescriptor_class_entry->create_object = CreateHandler_ReturnNull;
1044   h = &FieldDescriptor_object_handlers;
1045   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1046 
1047   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\DescriptorPool",
1048                    DescriptorPool_methods);
1049   DescriptorPool_class_entry = zend_register_internal_class(&tmp_ce);
1050   DescriptorPool_class_entry->ce_flags |= ZEND_ACC_FINAL;
1051   DescriptorPool_class_entry->create_object = DescriptorPool_create;
1052   h = &DescriptorPool_object_handlers;
1053   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
1054   h->dtor_obj = DescriptorPool_destructor;
1055 
1056   // GPBType.
1057 #define STR(str) (str), strlen(str)
1058   zend_class_entry class_type;
1059   INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType",
1060                    gpb_type_methods);
1061   gpb_type_type = zend_register_internal_class(&class_type);
1062   zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1);
1063   zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2);
1064   zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3);
1065   zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4);
1066   zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5);
1067   zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6);
1068   zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7);
1069   zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8);
1070   zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9);
1071   zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10);
1072   zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11);
1073   zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12);
1074   zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13);
1075   zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14);
1076   zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), 15);
1077   zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), 16);
1078   zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17);
1079   zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18);
1080 #undef STR
1081 }
1082