| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 | 
							- // Protocol Buffers - Google's data interchange format
 
- // Copyright 2014 Google Inc.  All rights reserved.
 
- // https://developers.google.com/protocol-buffers/
 
- //
 
- // Redistribution and use in source and binary forms, with or without
 
- // modification, are permitted provided that the following conditions are
 
- // met:
 
- //
 
- //     * Redistributions of source code must retain the above copyright
 
- // notice, this list of conditions and the following disclaimer.
 
- //     * Redistributions in binary form must reproduce the above
 
- // copyright notice, this list of conditions and the following disclaimer
 
- // in the documentation and/or other materials provided with the
 
- // distribution.
 
- //     * Neither the name of Google Inc. nor the names of its
 
- // contributors may be used to endorse or promote products derived from
 
- // this software without specific prior written permission.
 
- //
 
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
- #include "message.h"
 
- #include <inttypes.h>
 
- #include <php.h>
 
- #include <stdlib.h>
 
- // This is not self-contained: it must be after other Zend includes.
 
- #include <Zend/zend_exceptions.h>
 
- #include "arena.h"
 
- #include "array.h"
 
- #include "convert.h"
 
- #include "def.h"
 
- #include "map.h"
 
- #include "php-upb.h"
 
- #include "protobuf.h"
 
- // -----------------------------------------------------------------------------
 
- // Message
 
- // -----------------------------------------------------------------------------
 
- typedef struct {
 
-   zend_object std;
 
-   zval arena;
 
-   const Descriptor* desc;
 
-   upb_msg *msg;
 
- } Message;
 
- zend_class_entry *message_ce;
 
- static zend_object_handlers message_object_handlers;
 
- // PHP Object Handlers /////////////////////////////////////////////////////////
 
- /**
 
-  * Message_create()
 
-  *
 
-  * PHP class entry function to allocate and initialize a new Message object.
 
-  */
 
- static zend_object* Message_create(zend_class_entry *class_type) {
 
-   Message *intern = emalloc(sizeof(Message));
 
-   // XXX(haberman): verify whether we actually want to take this route.
 
-   class_type->default_properties_count = 0;
 
-   zend_object_std_init(&intern->std, class_type);
 
-   intern->std.handlers = &message_object_handlers;
 
-   Arena_Init(&intern->arena);
 
-   return &intern->std;
 
- }
 
- /**
 
-  * Message_dtor()
 
-  *
 
-  * Object handler to destroy a Message. This releases all resources associated
 
-  * with the message. Note that it is possible to access a destroyed object from
 
-  * PHP in rare cases.
 
-  */
 
- static void Message_dtor(zend_object* obj) {
 
-   Message* intern = (Message*)obj;
 
-   ObjCache_Delete(intern->msg);
 
-   zval_dtor(&intern->arena);
 
-   zend_object_std_dtor(&intern->std);
 
- }
 
- /**
 
-  * get_field()
 
-  *
 
-  * Helper function to look up a field given a member name (as a string).
 
-  */
 
- static const upb_fielddef *get_field(Message *msg, zval *member) {
 
-   const upb_msgdef *m = msg->desc->msgdef;
 
-   const upb_fielddef *f =
 
-       upb_msgdef_ntof(m, Z_STRVAL_P(member), Z_STRLEN_P(member));
 
-   if (!f) {
 
-     zend_throw_exception_ex(NULL, 0, "No such property %s.",
 
-                             ZSTR_VAL(msg->desc->class_entry->name));
 
-   }
 
-   return f;
 
- }
 
- /**
 
-  * Message_read_property()
 
-  *
 
-  * Object handler for reading a property in PHP. Called when PHP code does:
 
-  *
 
-  *   $x = $message->foobar;
 
-  *
 
-  * Note that all properties of generated messages are private, so this should
 
-  * only be possible to invoke from generated code, which has accessors like:
 
-  *
 
-  *   public function getOptionalInt32()
 
-  *   {
 
-  *       return $this->optional_int32;
 
-  *   }
 
-  *
 
-  * We lookup the field and return the scalar, RepeatedField, or MapField for
 
-  * this field.
 
-  */
 
- static zval *Message_read_property(zval *obj, zval *member, int type,
 
-                                    void **cache_slot, zval *rv) {
 
-   Message* intern = (Message*)Z_OBJ_P(obj);
 
-   const upb_fielddef *f = get_field(intern, member);
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   if (!f) return NULL;
 
-   if (upb_fielddef_ismap(f)) {
 
-     upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
 
-     MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena);
 
-   } else if (upb_fielddef_isseq(f)) {
 
-     upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena);
 
-     RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena);
 
-   } else {
 
-     upb_msgval msgval = upb_msg_get(intern->msg, f);
 
-     const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
 
-     Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena);
 
-   }
 
-   return rv;
 
- }
 
- /**
 
-  * Message_write_property()
 
-  *
 
-  * Object handler for writing a property in PHP. Called when PHP code does:
 
-  *
 
-  *   $message->foobar = $x;
 
-  *
 
-  * Note that all properties of generated messages are private, so this should
 
-  * only be possible to invoke from generated code, which has accessors like:
 
-  *
 
-  *   public function setOptionalInt32($var)
 
-  *   {
 
-  *       GPBUtil::checkInt32($var);
 
-  *       $this->optional_int32 = $var;
 
-  *
 
-  *       return $this;
 
-  *   }
 
-  *
 
-  * The C extension version of checkInt32() doesn't actually check anything, so
 
-  * we perform all checking and conversion in this function.
 
-  */
 
- static void Message_write_property(zval *obj, zval *member, zval *val,
 
-                                    void **cache_slot) {
 
-   Message* intern = (Message*)Z_OBJ_P(obj);
 
-   const upb_fielddef *f = get_field(intern, member);
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   upb_msgval msgval;
 
-   if (!f) return;
 
-   if (upb_fielddef_ismap(f)) {
 
-     msgval.map_val = MapField_GetUpbMap(val, f, arena);
 
-     if (!msgval.map_val) return;
 
-   } else if (upb_fielddef_isseq(f)) {
 
-     msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
 
-     if (!msgval.array_val) return;
 
-   } else {
 
-     upb_fieldtype_t type = upb_fielddef_type(f);
 
-     const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
 
-     bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena);
 
-     if (!ok) return;
 
-   }
 
-   upb_msg_set(intern->msg, f, msgval, arena);
 
- }
 
- /**
 
-  * Message_get_property_ptr_ptr()
 
-  *
 
-  * Object handler for the get_property_ptr_ptr event in PHP. This returns a
 
-  * reference to our internal properties. We don't support this, so we return
 
-  * NULL.
 
-  */
 
- static zval *Message_get_property_ptr_ptr(zval *object, zval *member, int type,
 
-                                           void **cache_slot) {
 
-   return NULL;  // We do not have a properties table.
 
- }
 
- /**
 
-  * Message_get_properties()
 
-  *
 
-  * Object handler for the get_properties event in PHP. This returns a HashTable
 
-  * of our internal properties. We don't support this, so we return NULL.
 
-  */
 
- static HashTable* Message_get_properties(zval* object TSRMLS_DC) {
 
-   return NULL;  // We don't offer direct references to our properties.
 
- }
 
- // C Functions from message.h. /////////////////////////////////////////////////
 
- // These are documented in the header file.
 
- void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg,
 
-                            zval *arena) {
 
-   if (!msg) {
 
-     ZVAL_NULL(val);
 
-     return;
 
-   }
 
-   if (!ObjCache_Get(msg, val)) {
 
-     Message *intern = emalloc(sizeof(Message));
 
-     // XXX(haberman): verify whether we actually want to take this route.
 
-     desc->class_entry->default_properties_count = 0;
 
-     zend_object_std_init(&intern->std, desc->class_entry);
 
-     intern->std.handlers = &message_object_handlers;
 
-     ZVAL_COPY(&intern->arena, arena);
 
-     intern->desc = desc;
 
-     intern->msg = msg;
 
-     ZVAL_OBJ(val, &intern->std);
 
-     ObjCache_Add(intern->msg, &intern->std);
 
-   }
 
- }
 
- bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena,
 
-                            upb_msg **msg) {
 
-   PBPHP_ASSERT(desc);
 
-   if (Z_ISREF_P(val)) {
 
-     ZVAL_DEREF(val);
 
-   }
 
-   if (Z_TYPE_P(val) == IS_NULL) {
 
-     *msg = NULL;
 
-     return true;
 
-   }
 
-   if (Z_TYPE_P(val) == IS_OBJECT &&
 
-       instanceof_function(Z_OBJCE_P(val), desc->class_entry)) {
 
-     Message *intern = (Message*)Z_OBJ_P(val);
 
-     upb_arena_fuse(arena, Arena_Get(&intern->arena));
 
-     *msg = intern->msg;
 
-     return true;
 
-   } else {
 
-     zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.",
 
-                             ZSTR_VAL(desc->class_entry->name));
 
-     return false;
 
-   }
 
- }
 
- // Message PHP methods /////////////////////////////////////////////////////////
 
- /**
 
-  * Message_InitFromPhp()
 
-  *
 
-  * Helper method to handle the initialization of a message from a PHP value, eg.
 
-  *
 
-  *   $m = new TestMessage([
 
-  *       'optional_int32' => -42,
 
-  *       'optional_bool' => true,
 
-  *       'optional_string' => 'a',
 
-  *       'optional_enum' => TestEnum::ONE,
 
-  *       'optional_message' => new Sub([
 
-  *           'a' => 33
 
-  *       ]),
 
-  *       'repeated_int32' => [-42, -52],
 
-  *       'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE],
 
-  *       'repeated_message' => [new Sub(['a' => 34]),
 
-  *                              new Sub(['a' => 35])],
 
-  *       'map_int32_int32' => [-62 => -62],
 
-  *       'map_int32_enum' => [1 => TestEnum::ONE],
 
-  *       'map_int32_message' => [1 => new Sub(['a' => 36])],
 
-  *   ]);
 
-  *
 
-  * The initializer must be an array.
 
-  */
 
- bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init,
 
-                          upb_arena *arena) {
 
-   HashTable* table = HASH_OF(init);
 
-   HashPosition pos;
 
-   if (Z_ISREF_P(init)) {
 
-     ZVAL_DEREF(init);
 
-   }
 
-   if (Z_TYPE_P(init) != IS_ARRAY) {
 
-     zend_throw_exception_ex(NULL, 0,
 
-                             "Initializer for a message %s must be an array.",
 
-                             upb_msgdef_fullname(m));
 
-     return false;
 
-   }
 
-   zend_hash_internal_pointer_reset_ex(table, &pos);
 
-   while (true) {  // Iterate over key/value pairs.
 
-     zval key;
 
-     zval *val;
 
-     const upb_fielddef *f;
 
-     upb_msgval msgval;
 
-     zend_hash_get_current_key_zval_ex(table, &key, &pos);
 
-     val = zend_hash_get_current_data_ex(table, &pos);
 
-     if (!val) return true;  // Finished iteration.
 
-     if (Z_ISREF_P(val)) {
 
-       ZVAL_DEREF(val);
 
-     }
 
-     f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key));
 
-     if (!f) {
 
-       zend_throw_exception_ex(NULL, 0,
 
-                               "No such field %s", Z_STRVAL_P(&key));
 
-       return false;
 
-     }
 
-     if (upb_fielddef_ismap(f)) {
 
-       msgval.map_val = MapField_GetUpbMap(val, f, arena);
 
-       if (!msgval.map_val) return false;
 
-     } else if (upb_fielddef_isseq(f)) {
 
-       msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
 
-       if (!msgval.array_val) return false;
 
-     } else {
 
-       const Descriptor *desc = Descriptor_GetFromFieldDef(f);
 
-       upb_fieldtype_t type = upb_fielddef_type(f);
 
-       if (!Convert_PhpToUpbAutoWrap(val, &msgval, type, desc, arena)) {
 
-         return false;
 
-       }
 
-     }
 
-     upb_msg_set(msg, f, msgval, arena);
 
-     zend_hash_move_forward_ex(table, &pos);
 
-     zval_dtor(&key);
 
-   }
 
- }
 
- /**
 
-  * Message::__construct()
 
-  *
 
-  * Constructor for Message.
 
-  * @param array Map of initial values ['k' = val]
 
-  */
 
- PHP_METHOD(Message, __construct) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   const Descriptor* desc = Descriptor_GetFromClassEntry(Z_OBJCE_P(getThis()));
 
-   const upb_msgdef *msgdef = desc->msgdef;
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   zval *init_arr = NULL;
 
-   intern->desc = desc;
 
-   intern->msg = upb_msg_new(msgdef, arena);
 
-   ObjCache_Add(intern->msg, &intern->std);
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) {
 
-     return;
 
-   }
 
-   if (init_arr) {
 
-     Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena);
 
-   }
 
- }
 
- /**
 
-  * Message::discardUnknownFields()
 
-  *
 
-  * Discards any unknown fields for this message or any submessages.
 
-  */
 
- PHP_METHOD(Message, discardUnknownFields) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64);
 
- }
 
- /**
 
-  * Message::clear()
 
-  *
 
-  * Clears all fields of this message.
 
-  */
 
- PHP_METHOD(Message, clear) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   upb_msg_clear(intern->msg, intern->desc->msgdef);
 
- }
 
- /**
 
-  * Message::mergeFrom()
 
-  *
 
-  * Merges from the given message, which must be of the same class as us.
 
-  * @param object Message to merge from.
 
-  */
 
- PHP_METHOD(Message, mergeFrom) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   Message* from;
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
 
-   zval* value;
 
-   char *pb;
 
-   size_t size;
 
-   bool ok;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value,
 
-                             intern->desc->class_entry) == FAILURE) {
 
-     return;
 
-   }
 
-   from = (Message*)Z_OBJ_P(value);
 
-   // Should be guaranteed since we passed the class type to
 
-   // zend_parse_parameters().
 
-   PBPHP_ASSERT(from->desc == intern->desc);
 
-   // TODO(haberman): use a temp arena for this once we can make upb_decode()
 
-   // copy strings.
 
-   pb = upb_encode(from->msg, l, arena, &size);
 
-   if (!pb) {
 
-     zend_throw_exception_ex(NULL, 0, "Max nesting exceeded");
 
-     return;
 
-   }
 
-   ok = upb_decode(pb, size, intern->msg, l, arena);
 
-   PBPHP_ASSERT(ok);
 
- }
 
- /**
 
-  * Message::mergeFromString()
 
-  *
 
-  * Merges from the given string.
 
-  * @param string Binary protobuf data to merge.
 
-  */
 
- PHP_METHOD(Message, mergeFromString) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   char *data = NULL;
 
-   char *data_copy = NULL;
 
-   zend_long data_len;
 
-   const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) ==
 
-       FAILURE) {
 
-     return;
 
-   }
 
-   // TODO(haberman): avoid this copy when we can make the decoder copy.
 
-   data_copy = upb_arena_malloc(arena, data_len);
 
-   memcpy(data_copy, data, data_len);
 
-   if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) {
 
-     zend_throw_exception_ex(NULL, 0, "Error occurred during parsing");
 
-     return;
 
-   }
 
- }
 
- /**
 
-  * Message::serializeToString()
 
-  *
 
-  * Serializes this message instance to protobuf data.
 
-  * @return string Serialized protobuf data.
 
-  */
 
- PHP_METHOD(Message, serializeToString) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef);
 
-   upb_arena *tmp_arena = upb_arena_new();
 
-   char *data;
 
-   size_t size;
 
-   data = upb_encode(intern->msg, l, tmp_arena, &size);
 
-   if (!data) {
 
-     zend_throw_exception_ex(NULL, 0, "Error occurred during serialization");
 
-     upb_arena_free(tmp_arena);
 
-     return;
 
-   }
 
-   RETVAL_STRINGL(data, size);
 
-   upb_arena_free(tmp_arena);
 
- }
 
- /**
 
-  * Message::mergeFromJsonString()
 
-  *
 
-  * Merges the JSON data parsed from the given string.
 
-  * @param string Serialized JSON data.
 
-  */
 
- PHP_METHOD(Message, mergeFromJsonString) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   char *data = NULL;
 
-   char *data_copy = NULL;
 
-   zend_long data_len;
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   upb_status status;
 
-   zend_bool ignore_json_unknown = false;
 
-   int options = 0;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len,
 
-                             &ignore_json_unknown) == FAILURE) {
 
-     return;
 
-   }
 
-   // TODO(haberman): avoid this copy when we can make the decoder copy.
 
-   data_copy = upb_arena_malloc(arena, data_len + 1);
 
-   memcpy(data_copy, data, data_len);
 
-   data_copy[data_len] = '\0';
 
-   if (ignore_json_unknown) {
 
-     options |= UPB_JSONDEC_IGNOREUNKNOWN;
 
-   }
 
-   upb_status_clear(&status);
 
-   if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef,
 
-                        DescriptorPool_GetSymbolTable(), options, arena,
 
-                        &status)) {
 
-     zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s",
 
-                             upb_status_errmsg(&status));
 
-     return;
 
-   }
 
- }
 
- /**
 
-  * Message::serializeToJsonString()
 
-  *
 
-  * Serializes this object to JSON.
 
-  * @return string Serialized JSON data.
 
-  */
 
- PHP_METHOD(Message, serializeToJsonString) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   size_t size;
 
-   int options = 0;
 
-   char buf[1024];
 
-   zend_bool preserve_proto_fieldnames = false;
 
-   upb_status status;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b",
 
-                             &preserve_proto_fieldnames) == FAILURE) {
 
-     return;
 
-   }
 
-   if (preserve_proto_fieldnames) {
 
-     options |= UPB_JSONENC_PROTONAMES;
 
-   }
 
-   upb_status_clear(&status);
 
-   size = upb_json_encode(intern->msg, intern->desc->msgdef,
 
-                          DescriptorPool_GetSymbolTable(), options, buf,
 
-                          sizeof(buf), &status);
 
-   if (!upb_ok(&status)) {
 
-     zend_throw_exception_ex(NULL, 0,
 
-                             "Error occurred during JSON serialization: %s",
 
-                             upb_status_errmsg(&status));
 
-     return;
 
-   }
 
-   if (size >= sizeof(buf)) {
 
-     char *buf2 = malloc(size + 1);
 
-     upb_json_encode(intern->msg, intern->desc->msgdef,
 
-                     DescriptorPool_GetSymbolTable(), options, buf2, size + 1,
 
-                     &status);
 
-     RETVAL_STRINGL(buf2, size);
 
-     free(buf2);
 
-   } else {
 
-     RETVAL_STRINGL(buf, size);
 
-   }
 
- }
 
- /**
 
-  * Message::readWrapperValue()
 
-  *
 
-  * Returns an unboxed value for the given field. This is called from generated
 
-  * methods for wrapper fields, eg.
 
-  *
 
-  *   public function getDoubleValueUnwrapped()
 
-  *   {
 
-  *       return $this->readWrapperValue("double_value");
 
-  *   }
 
-  *
 
-  * @return Unwrapped field value or null.
 
-  */
 
- PHP_METHOD(Message, readWrapperValue) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   char* member;
 
-   const upb_fielddef *f;
 
-   zend_long size;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) {
 
-     return;
 
-   }
 
-   f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
 
-   if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
 
-     zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
 
-                             upb_msgdef_fullname(intern->desc->msgdef), member);
 
-     return;
 
-   }
 
-   if (upb_msg_has(intern->msg, f)) {
 
-     const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val;
 
-     const upb_msgdef *m = upb_fielddef_msgsubdef(f);
 
-     const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
 
-     const upb_fieldtype_t val_type = upb_fielddef_type(val_f);
 
-     upb_msgval msgval = upb_msg_get(wrapper, val_f);
 
-     zval ret;
 
-     Convert_UpbToPhp(msgval, &ret, val_type, NULL, &intern->arena);
 
-     RETURN_ZVAL(&ret, 1, 0);
 
-   } else {
 
-     RETURN_NULL();
 
-   }
 
- }
 
- /**
 
-  * Message::writeWrapperValue()
 
-  *
 
-  * Sets the given wrapper field to the given unboxed value. This is called from
 
-  * generated methods for wrapper fields, eg.
 
-  *
 
-  *
 
-  *   public function setDoubleValueUnwrapped($var)
 
-  *   {
 
-  *       $this->writeWrapperValue("double_value", $var);
 
-  *       return $this;
 
-  *   }
 
-  *
 
-  * @param Unwrapped field value or null.
 
-  */
 
- PHP_METHOD(Message, writeWrapperValue) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   char* member;
 
-   const upb_fielddef *f;
 
-   upb_msgval msgval;
 
-   zend_long size;
 
-   zval* val;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) ==
 
-       FAILURE) {
 
-     return;
 
-   }
 
-   f = upb_msgdef_ntof(intern->desc->msgdef, member, size);
 
-   if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) {
 
-     zend_throw_exception_ex(NULL, 0, "Message %s has no field %s",
 
-                             upb_msgdef_fullname(intern->desc->msgdef), member);
 
-     return;
 
-   }
 
-   if (Z_ISREF_P(val)) {
 
-     ZVAL_DEREF(val);
 
-   }
 
-   if (Z_TYPE_P(val) == IS_NULL) {
 
-     upb_msg_clearfield(intern->msg, f);
 
-   } else {
 
-     const upb_msgdef *m = upb_fielddef_msgsubdef(f);
 
-     const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
 
-     upb_fieldtype_t val_type = upb_fielddef_type(val_f);
 
-     upb_msg *wrapper;
 
-     if (!Convert_PhpToUpb(val, &msgval, val_type, NULL, arena)) {
 
-       return;  // Error is already set.
 
-     }
 
-     wrapper = upb_msg_mutable(intern->msg, f, arena).msg;
 
-     upb_msg_set(wrapper, val_f, msgval, arena);
 
-   }
 
- }
 
- /**
 
-  * Message::whichOneof()
 
-  *
 
-  * Given a oneof name, returns the name of the field that is set for this oneof,
 
-  * or otherwise the empty string.
 
-  *
 
-  * @return string The field name in this oneof that is currently set.
 
-  */
 
- PHP_METHOD(Message, whichOneof) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   const upb_oneofdef* oneof;
 
-   const upb_fielddef* field;
 
-   char* name;
 
-   zend_long len;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) {
 
-     return;
 
-   }
 
-   oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len);
 
-   if (!oneof) {
 
-     zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s",
 
-                             upb_msgdef_fullname(intern->desc->msgdef), name);
 
-     return;
 
-   }
 
-   field = upb_msg_whichoneof(intern->msg, oneof);
 
-   RETURN_STRING(field ? upb_fielddef_name(field) : "");
 
- }
 
- /**
 
-  * Message::readOneof()
 
-  *
 
-  * Returns the contents of the given oneof field, given a field number. Called
 
-  * from generated code methods such as:
 
-  *
 
-  *    public function getDoubleValueOneof()
 
-  *    {
 
-  *        return $this->readOneof(10);
 
-  *    }
 
-  *
 
-  * @return object The oneof's field value.
 
-  */
 
- PHP_METHOD(Message, readOneof) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   zend_long field_num;
 
-   const upb_fielddef* f;
 
-   zval ret;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) {
 
-     return;
 
-   }
 
-   f = upb_msgdef_itof(intern->desc->msgdef, field_num);
 
-   if (!f || !upb_fielddef_realcontainingoneof(f)) {
 
-     php_error_docref(NULL, E_USER_ERROR,
 
-                      "Internal error, no such oneof field %d\n",
 
-                      (int)field_num);
 
-   }
 
-   {
 
-     upb_msgval msgval = upb_msg_get(intern->msg, f);
 
-     const Descriptor *subdesc = Descriptor_GetFromFieldDef(f);
 
-     Convert_UpbToPhp(msgval, &ret, upb_fielddef_type(f), subdesc,
 
-                      &intern->arena);
 
-   }
 
-   RETURN_ZVAL(&ret, 1, 0);
 
- }
 
- /**
 
-  * Message::writeOneof()
 
-  *
 
-  * Sets the contents of the given oneof field, given a field number. Called
 
-  * from generated code methods such as:
 
-  *
 
-  *    public function setDoubleValueOneof($var)
 
-  *   {
 
-  *       GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class);
 
-  *       $this->writeOneof(10, $var);
 
-  *
 
-  *       return $this;
 
-  *   }
 
-  *
 
-  * The C extension version of GPBUtil::check*() does nothing, so we perform
 
-  * all type checking and conversion here.
 
-  *
 
-  * @param integer The field number we are setting.
 
-  * @param object The field value we want to set.
 
-  */
 
- PHP_METHOD(Message, writeOneof) {
 
-   Message* intern = (Message*)Z_OBJ_P(getThis());
 
-   zend_long field_num;
 
-   const upb_fielddef* f;
 
-   upb_arena *arena = Arena_Get(&intern->arena);
 
-   upb_msgval msgval;
 
-   zval* val;
 
-   if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) ==
 
-       FAILURE) {
 
-     return;
 
-   }
 
-   f = upb_msgdef_itof(intern->desc->msgdef, field_num);
 
-   if (!Convert_PhpToUpb(val, &msgval, upb_fielddef_type(f),
 
-                         Descriptor_GetFromFieldDef(f), arena)) {
 
-     return;
 
-   }
 
-   upb_msg_set(intern->msg, f, msgval, arena);
 
- }
 
- static zend_function_entry Message_methods[] = {
 
-   PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC)
 
-   PHP_ME(Message, readWrapperValue, NULL, ZEND_ACC_PROTECTED)
 
-   PHP_ME(Message, writeWrapperValue, NULL, ZEND_ACC_PROTECTED)
 
-   PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED)
 
-   PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED)
 
-   PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED)
 
-   PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED)
 
-   ZEND_FE_END
 
- };
 
- /**
 
-  * Message_ModuleInit()
 
-  *
 
-  * Called when the C extension is loaded to register all types.
 
-  */
 
- void Message_ModuleInit() {
 
-   zend_class_entry tmp_ce;
 
-   zend_object_handlers *h = &message_object_handlers;
 
-   INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message",
 
-                    Message_methods);
 
-   message_ce = zend_register_internal_class(&tmp_ce);
 
-   message_ce->create_object = Message_create;
 
-   memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
 
-   h->dtor_obj = Message_dtor;
 
-   h->read_property = Message_read_property;
 
-   h->write_property = Message_write_property;
 
-   h->get_properties = Message_get_properties;
 
-   h->get_property_ptr_ptr = Message_get_property_ptr_ptr;
 
- }
 
 
  |