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