|  | <?php | 
|  |  | 
|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2008 Google Inc.  All rights reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://developers.google.com/open-source/licenses/bsd | 
|  |  | 
|  | /** | 
|  | * Defines Message, the parent class extended by all protocol message classes. | 
|  | */ | 
|  |  | 
|  | namespace Google\Protobuf\Internal; | 
|  |  | 
|  | use Google\Protobuf\Internal\CodedInputStream; | 
|  | use Google\Protobuf\Internal\CodedOutputStream; | 
|  | use Google\Protobuf\Internal\DescriptorPool; | 
|  | use Google\Protobuf\Internal\GPBLabel; | 
|  | use Google\Protobuf\Internal\GPBType; | 
|  | use Google\Protobuf\Internal\GPBWire; | 
|  | use Google\Protobuf\Internal\MapEntry; | 
|  | use Google\Protobuf\Internal\RepeatedField; | 
|  | use Google\Protobuf\ListValue; | 
|  | use Google\Protobuf\Value; | 
|  | use Google\Protobuf\Struct; | 
|  | use Google\Protobuf\NullValue; | 
|  |  | 
|  | /** | 
|  | * Parent class of all proto messages. Users should not instantiate this class | 
|  | * or extend this class or its child classes by their own.  See the comment of | 
|  | * specific functions for more details. | 
|  | */ | 
|  | #[\AllowDynamicProperties] | 
|  | class Message | 
|  | { | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private $desc; | 
|  | private $unknown = ""; | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function __construct($data = NULL) | 
|  | { | 
|  | // MapEntry message is shared by all types of map fields, whose | 
|  | // descriptors are different from each other. Thus, we cannot find a | 
|  | // specific descriptor from the descriptor pool. | 
|  | if ($this instanceof MapEntry) { | 
|  | $this->initWithDescriptor($data); | 
|  | } else { | 
|  | $this->initWithGeneratedPool(); | 
|  | if (is_array($data)) { | 
|  | $this->mergeFromArray($data); | 
|  | } else if (!empty($data)) { | 
|  | throw new \InvalidArgumentException( | 
|  | 'Message constructor must be an array or null.' | 
|  | ); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function initWithGeneratedPool() | 
|  | { | 
|  | $pool = DescriptorPool::getGeneratedPool(); | 
|  | $this->desc = $pool->getDescriptorByClassName(get_class($this)); | 
|  | if (is_null($this->desc)) { | 
|  | throw new \InvalidArgumentException( | 
|  | get_class($this) ." is not found in descriptor pool. " . | 
|  | 'Only generated classes may derive from Message.'); | 
|  | } | 
|  | foreach ($this->desc->getField() as $field) { | 
|  | $setter = $field->getSetter(); | 
|  | if ($field->isMap()) { | 
|  | $message_type = $field->getMessageType(); | 
|  | $key_field = $message_type->getFieldByNumber(1); | 
|  | $value_field = $message_type->getFieldByNumber(2); | 
|  | switch ($value_field->getType()) { | 
|  | case GPBType::MESSAGE: | 
|  | case GPBType::GROUP: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType(), | 
|  | $value_field->getMessageType()->getClass()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType(), | 
|  | $value_field->getEnumType()->getClass()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | default: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::REPEATED) { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::MESSAGE: | 
|  | case GPBType::GROUP: | 
|  | $repeated_field = new RepeatedField( | 
|  | $field->getType(), | 
|  | $field->getMessageType()->getClass()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | $repeated_field = new RepeatedField( | 
|  | $field->getType(), | 
|  | $field->getEnumType()->getClass()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | default: | 
|  | $repeated_field = new RepeatedField($field->getType()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | } | 
|  | } else if ($field->getOneofIndex() !== -1) { | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | $this->$oneof_name = new OneofField($oneof); | 
|  | } else if ($field->getLabel() === GPBLabel::OPTIONAL && | 
|  | PHP_INT_SIZE == 4) { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::INT64: | 
|  | case GPBType::UINT64: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::SINT64: | 
|  | $this->$setter("0"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function initWithDescriptor(Descriptor $desc) | 
|  | { | 
|  | $this->desc = $desc; | 
|  | foreach ($desc->getField() as $field) { | 
|  | $setter = $field->getSetter(); | 
|  | $defaultValue = $this->defaultValue($field); | 
|  | $this->$setter($defaultValue); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function readWrapperValue($member) | 
|  | { | 
|  | $field = $this->desc->getFieldByName($member); | 
|  | $oneof_index = $field->getOneofIndex(); | 
|  | if ($oneof_index === -1) { | 
|  | $wrapper = $this->$member; | 
|  | } else { | 
|  | $wrapper = $this->readOneof($field->getNumber()); | 
|  | } | 
|  |  | 
|  | if (is_null($wrapper)) { | 
|  | return NULL; | 
|  | } else { | 
|  | return $wrapper->getValue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function writeWrapperValue($member, $value) | 
|  | { | 
|  | $field = $this->desc->getFieldByName($member); | 
|  | $wrapped_value = $value; | 
|  | if (!is_null($value)) { | 
|  | $desc = $field->getMessageType(); | 
|  | $klass = $desc->getClass(); | 
|  | $wrapped_value = new $klass; | 
|  | $wrapped_value->setValue($value); | 
|  | } | 
|  |  | 
|  | $oneof_index = $field->getOneofIndex(); | 
|  | if ($oneof_index === -1) { | 
|  | $this->$member = $wrapped_value; | 
|  | } else { | 
|  | $this->writeOneof($field->getNumber(), $wrapped_value); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function readOneof($number) | 
|  | { | 
|  | $field = $this->desc->getFieldByNumber($number); | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | $oneof_field = $this->$oneof_name; | 
|  | if ($number === $oneof_field->getNumber()) { | 
|  | return $oneof_field->getValue(); | 
|  | } else { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function hasOneof($number) | 
|  | { | 
|  | $field = $this->desc->getFieldByNumber($number); | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | $oneof_field = $this->$oneof_name; | 
|  | return $number === $oneof_field->getNumber(); | 
|  | } | 
|  |  | 
|  | protected function writeOneof($number, $value) | 
|  | { | 
|  | $field = $this->desc->getFieldByNumber($number); | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | if ($value === null) { | 
|  | $this->$oneof_name = new OneofField($oneof); | 
|  | } else { | 
|  | $oneof_field = $this->$oneof_name; | 
|  | $oneof_field->setValue($value); | 
|  | $oneof_field->setFieldName($field->getName()); | 
|  | $oneof_field->setNumber($number); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function whichOneof($oneof_name) | 
|  | { | 
|  | $oneof_field = $this->$oneof_name; | 
|  | $number = $oneof_field->getNumber(); | 
|  | if ($number == 0) { | 
|  | return ""; | 
|  | } | 
|  | $field = $this->desc->getFieldByNumber($number); | 
|  | return $field->getName(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function defaultValue($field) | 
|  | { | 
|  | $value = null; | 
|  |  | 
|  | switch ($field->getType()) { | 
|  | case GPBType::DOUBLE: | 
|  | case GPBType::FLOAT: | 
|  | return 0.0; | 
|  | case GPBType::UINT32: | 
|  | case GPBType::INT32: | 
|  | case GPBType::FIXED32: | 
|  | case GPBType::SFIXED32: | 
|  | case GPBType::SINT32: | 
|  | case GPBType::ENUM: | 
|  | return 0; | 
|  | case GPBType::INT64: | 
|  | case GPBType::UINT64: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::SINT64: | 
|  | if (PHP_INT_SIZE === 4) { | 
|  | return '0'; | 
|  | } else { | 
|  | return 0; | 
|  | } | 
|  | case GPBType::BOOL: | 
|  | return false; | 
|  | case GPBType::STRING: | 
|  | case GPBType::BYTES: | 
|  | return ""; | 
|  | case GPBType::GROUP: | 
|  | case GPBType::MESSAGE: | 
|  | return null; | 
|  | default: | 
|  | user_error("Unsupported type."); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function skipField($input, $tag) | 
|  | { | 
|  | $number = GPBWire::getTagFieldNumber($tag); | 
|  | if ($number === 0) { | 
|  | throw new GPBDecodeException("Illegal field number zero."); | 
|  | } | 
|  |  | 
|  | $start = $input->current(); | 
|  | switch (GPBWire::getTagWireType($tag)) { | 
|  | case GPBWireType::VARINT: | 
|  | $uint64 = 0; | 
|  | if (!$input->readVarint64($uint64)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside varint."); | 
|  | } | 
|  | break; | 
|  | case GPBWireType::FIXED64: | 
|  | $uint64 = 0; | 
|  | if (!$input->readLittleEndian64($uint64)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside fixed64."); | 
|  | } | 
|  | break; | 
|  | case GPBWireType::FIXED32: | 
|  | $uint32 = 0; | 
|  | if (!$input->readLittleEndian32($uint32)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside fixed32."); | 
|  | } | 
|  | break; | 
|  | case GPBWireType::LENGTH_DELIMITED: | 
|  | $length = 0; | 
|  | if (!$input->readVarint32($length)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside length."); | 
|  | } | 
|  | $data = NULL; | 
|  | if (!$input->readRaw($length, $data)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside length delimited data."); | 
|  | } | 
|  | break; | 
|  | case GPBWireType::START_GROUP: | 
|  | case GPBWireType::END_GROUP: | 
|  | throw new GPBDecodeException("Unexpected wire type."); | 
|  | default: | 
|  | throw new GPBDecodeException("Unexpected wire type."); | 
|  | } | 
|  | $end = $input->current(); | 
|  |  | 
|  | $bytes = str_repeat(chr(0), CodedOutputStream::MAX_VARINT64_BYTES); | 
|  | $size = CodedOutputStream::writeVarintToArray($tag, $bytes, true); | 
|  | $this->unknown .= substr($bytes, 0, $size) . $input->substr($start, $end); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private static function parseFieldFromStreamNoTag($input, $field, &$value) | 
|  | { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::DOUBLE: | 
|  | if (!GPBWire::readDouble($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside double field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::FLOAT: | 
|  | if (!GPBWire::readFloat($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside float field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::INT64: | 
|  | if (!GPBWire::readInt64($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside int64 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::UINT64: | 
|  | if (!GPBWire::readUint64($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside uint64 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::INT32: | 
|  | if (!GPBWire::readInt32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside int32 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::FIXED64: | 
|  | if (!GPBWire::readFixed64($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside fixed64 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::FIXED32: | 
|  | if (!GPBWire::readFixed32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside fixed32 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::BOOL: | 
|  | if (!GPBWire::readBool($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside bool field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::STRING: | 
|  | // TODO: Add utf-8 check. | 
|  | if (!GPBWire::readString($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside string field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::GROUP: | 
|  | trigger_error("Not implemented.", E_USER_ERROR); | 
|  | break; | 
|  | case GPBType::MESSAGE: | 
|  | if ($field->isMap()) { | 
|  | $value = new MapEntry($field->getMessageType()); | 
|  | } else { | 
|  | $klass = $field->getMessageType()->getClass(); | 
|  | $value = new $klass; | 
|  | } | 
|  | if (!GPBWire::readMessage($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside message."); | 
|  | } | 
|  | break; | 
|  | case GPBType::BYTES: | 
|  | if (!GPBWire::readString($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside bytes field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::UINT32: | 
|  | if (!GPBWire::readUint32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside uint32 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | // TODO: Check unknown enum value. | 
|  | if (!GPBWire::readInt32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside enum field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::SFIXED32: | 
|  | if (!GPBWire::readSfixed32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside sfixed32 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::SFIXED64: | 
|  | if (!GPBWire::readSfixed64($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside sfixed64 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::SINT32: | 
|  | if (!GPBWire::readSint32($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside sint32 field."); | 
|  | } | 
|  | break; | 
|  | case GPBType::SINT64: | 
|  | if (!GPBWire::readSint64($input, $value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside sint64 field."); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | user_error("Unsupported type."); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function parseFieldFromStream($tag, $input, $field) | 
|  | { | 
|  | $value = null; | 
|  |  | 
|  | if (is_null($field)) { | 
|  | $value_format = GPBWire::UNKNOWN; | 
|  | } elseif (GPBWire::getTagWireType($tag) === | 
|  | GPBWire::getWireType($field->getType())) { | 
|  | $value_format = GPBWire::NORMAL_FORMAT; | 
|  | } elseif ($field->isPackable() && | 
|  | GPBWire::getTagWireType($tag) === | 
|  | GPBWire::WIRETYPE_LENGTH_DELIMITED) { | 
|  | $value_format = GPBWire::PACKED_FORMAT; | 
|  | } else { | 
|  | // the wire type doesn't match. Put it in our unknown field set. | 
|  | $value_format = GPBWire::UNKNOWN; | 
|  | } | 
|  |  | 
|  | if ($value_format === GPBWire::UNKNOWN) { | 
|  | $this->skipField($input, $tag); | 
|  | return; | 
|  | } elseif ($value_format === GPBWire::NORMAL_FORMAT) { | 
|  | self::parseFieldFromStreamNoTag($input, $field, $value); | 
|  | } elseif ($value_format === GPBWire::PACKED_FORMAT) { | 
|  | $length = 0; | 
|  | if (!GPBWire::readInt32($input, $length)) { | 
|  | throw new GPBDecodeException( | 
|  | "Unexpected EOF inside packed length."); | 
|  | } | 
|  | $limit = $input->pushLimit($length); | 
|  | $getter = $field->getGetter(); | 
|  | while ($input->bytesUntilLimit() > 0) { | 
|  | self::parseFieldFromStreamNoTag($input, $field, $value); | 
|  | $this->appendHelper($field, $value); | 
|  | } | 
|  | $input->popLimit($limit); | 
|  | return; | 
|  | } else { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if ($field->isMap()) { | 
|  | $this->kvUpdateHelper($field, $value->getKey(), $value->getValue()); | 
|  | } else if ($field->isRepeated()) { | 
|  | $this->appendHelper($field, $value); | 
|  | } else { | 
|  | $setter = $field->getSetter(); | 
|  | $this->$setter($value); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Clear all containing fields. | 
|  | * @return null | 
|  | */ | 
|  | public function clear() | 
|  | { | 
|  | $this->unknown = ""; | 
|  | foreach ($this->desc->getField() as $field) { | 
|  | $setter = $field->getSetter(); | 
|  | if ($field->isMap()) { | 
|  | $message_type = $field->getMessageType(); | 
|  | $key_field = $message_type->getFieldByNumber(1); | 
|  | $value_field = $message_type->getFieldByNumber(2); | 
|  | switch ($value_field->getType()) { | 
|  | case GPBType::MESSAGE: | 
|  | case GPBType::GROUP: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType(), | 
|  | $value_field->getMessageType()->getClass()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType(), | 
|  | $value_field->getEnumType()->getClass()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | default: | 
|  | $map_field = new MapField( | 
|  | $key_field->getType(), | 
|  | $value_field->getType()); | 
|  | $this->$setter($map_field); | 
|  | break; | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::REPEATED) { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::MESSAGE: | 
|  | case GPBType::GROUP: | 
|  | $repeated_field = new RepeatedField( | 
|  | $field->getType(), | 
|  | $field->getMessageType()->getClass()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | $repeated_field = new RepeatedField( | 
|  | $field->getType(), | 
|  | $field->getEnumType()->getClass()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | default: | 
|  | $repeated_field = new RepeatedField($field->getType()); | 
|  | $this->$setter($repeated_field); | 
|  | break; | 
|  | } | 
|  | } else if ($field->getOneofIndex() !== -1) { | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | $this->$oneof_name = new OneofField($oneof); | 
|  | } else if ($field->getLabel() === GPBLabel::OPTIONAL) { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::DOUBLE   : | 
|  | case GPBType::FLOAT    : | 
|  | $this->$setter(0.0); | 
|  | break; | 
|  | case GPBType::INT32    : | 
|  | case GPBType::FIXED32  : | 
|  | case GPBType::UINT32   : | 
|  | case GPBType::SFIXED32 : | 
|  | case GPBType::SINT32   : | 
|  | case GPBType::ENUM     : | 
|  | $this->$setter(0); | 
|  | break; | 
|  | case GPBType::BOOL     : | 
|  | $this->$setter(false); | 
|  | break; | 
|  | case GPBType::STRING   : | 
|  | case GPBType::BYTES    : | 
|  | $this->$setter(""); | 
|  | break; | 
|  | case GPBType::GROUP    : | 
|  | case GPBType::MESSAGE  : | 
|  | $null = null; | 
|  | $this->$setter($null); | 
|  | break; | 
|  | } | 
|  | if (PHP_INT_SIZE == 4) { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::INT64: | 
|  | case GPBType::UINT64: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::SINT64: | 
|  | $this->$setter("0"); | 
|  | } | 
|  | } else { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::INT64: | 
|  | case GPBType::UINT64: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::SINT64: | 
|  | $this->$setter(0); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Clear all unknown fields previously parsed. | 
|  | * @return null | 
|  | */ | 
|  | public function discardUnknownFields() | 
|  | { | 
|  | $this->unknown = ""; | 
|  | foreach ($this->desc->getField() as $field) { | 
|  | if ($field->getType() != GPBType::MESSAGE) { | 
|  | continue; | 
|  | } | 
|  | if ($field->isMap()) { | 
|  | $value_field = $field->getMessageType()->getFieldByNumber(2); | 
|  | if ($value_field->getType() != GPBType::MESSAGE) { | 
|  | continue; | 
|  | } | 
|  | $getter = $field->getGetter(); | 
|  | $map = $this->$getter(); | 
|  | foreach ($map as $key => $value) { | 
|  | $value->discardUnknownFields(); | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::REPEATED) { | 
|  | $getter = $field->getGetter(); | 
|  | $arr = $this->$getter(); | 
|  | foreach ($arr as $sub) { | 
|  | $sub->discardUnknownFields(); | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::OPTIONAL) { | 
|  | $getter = $field->getGetter(); | 
|  | $sub = $this->$getter(); | 
|  | if (!is_null($sub)) { | 
|  | $sub->discardUnknownFields(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Merges the contents of the specified message into current message. | 
|  | * | 
|  | * This method merges the contents of the specified message into the | 
|  | * current message. Singular fields that are set in the specified message | 
|  | * overwrite the corresponding fields in the current message.  Repeated | 
|  | * fields are appended. Map fields key-value pairs are overwritten. | 
|  | * Singular/Oneof sub-messages are recursively merged. All overwritten | 
|  | * sub-messages are deep-copied. | 
|  | * | 
|  | * @param object $msg Protobuf message to be merged from. | 
|  | * @return null | 
|  | */ | 
|  | public function mergeFrom($msg) | 
|  | { | 
|  | if (get_class($this) !== get_class($msg)) { | 
|  | user_error("Cannot merge messages with different class."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | foreach ($this->desc->getField() as $field) { | 
|  | $setter = $field->getSetter(); | 
|  | $getter = $field->getGetter(); | 
|  | if ($field->isMap()) { | 
|  | if (count($msg->$getter()) != 0) { | 
|  | $value_field = $field->getMessageType()->getFieldByNumber(2); | 
|  | foreach ($msg->$getter() as $key => $value) { | 
|  | if ($value_field->getType() == GPBType::MESSAGE) { | 
|  | $klass = $value_field->getMessageType()->getClass(); | 
|  | $copy = new $klass; | 
|  | $copy->mergeFrom($value); | 
|  |  | 
|  | $this->kvUpdateHelper($field, $key, $copy); | 
|  | } else { | 
|  | $this->kvUpdateHelper($field, $key, $value); | 
|  | } | 
|  | } | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::REPEATED) { | 
|  | if (count($msg->$getter()) != 0) { | 
|  | foreach ($msg->$getter() as $tmp) { | 
|  | if ($field->getType() == GPBType::MESSAGE) { | 
|  | $klass = $field->getMessageType()->getClass(); | 
|  | $copy = new $klass; | 
|  | $copy->mergeFrom($tmp); | 
|  | $this->appendHelper($field, $copy); | 
|  | } else { | 
|  | $this->appendHelper($field, $tmp); | 
|  | } | 
|  | } | 
|  | } | 
|  | } else if ($field->getLabel() === GPBLabel::OPTIONAL) { | 
|  | if($msg->$getter() !== $this->defaultValue($field)) { | 
|  | $tmp = $msg->$getter(); | 
|  | if ($field->getType() == GPBType::MESSAGE) { | 
|  | if (is_null($this->$getter())) { | 
|  | $klass = $field->getMessageType()->getClass(); | 
|  | $new_msg = new $klass; | 
|  | $this->$setter($new_msg); | 
|  | } | 
|  | $this->$getter()->mergeFrom($tmp); | 
|  | } else { | 
|  | $this->$setter($tmp); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parses a protocol buffer contained in a string. | 
|  | * | 
|  | * This function takes a string in the (non-human-readable) binary wire | 
|  | * format, matching the encoding output by serializeToString(). | 
|  | * See mergeFrom() for merging behavior, if the field is already set in the | 
|  | * specified message. | 
|  | * | 
|  | * @param string $data Binary protobuf data. | 
|  | * @return null | 
|  | * @throws \Exception Invalid data. | 
|  | */ | 
|  | public function mergeFromString($data) | 
|  | { | 
|  | $input = new CodedInputStream($data); | 
|  | $this->parseFromStream($input); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Parses a json string to protobuf message. | 
|  | * | 
|  | * This function takes a string in the json wire format, matching the | 
|  | * encoding output by serializeToJsonString(). | 
|  | * See mergeFrom() for merging behavior, if the field is already set in the | 
|  | * specified message. | 
|  | * | 
|  | * @param string $data Json protobuf data. | 
|  | * @param bool $ignore_unknown | 
|  | * @return null | 
|  | * @throws \Exception Invalid data. | 
|  | */ | 
|  | public function mergeFromJsonString($data, $ignore_unknown = false) | 
|  | { | 
|  | $input = new RawInputStream($data); | 
|  | $this->parseFromJsonStream($input, $ignore_unknown); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function parseFromStream($input) | 
|  | { | 
|  | while (true) { | 
|  | $tag = $input->readTag(); | 
|  | // End of input.  This is a valid place to end, so return true. | 
|  | if ($tag === 0) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | $number = GPBWire::getTagFieldNumber($tag); | 
|  | $field = $this->desc->getFieldByNumber($number); | 
|  |  | 
|  | $this->parseFieldFromStream($tag, $input, $field); | 
|  | } | 
|  | } | 
|  |  | 
|  | private function convertJsonValueToProtoValue( | 
|  | $value, | 
|  | $field, | 
|  | $ignore_unknown, | 
|  | $is_map_key = false) | 
|  | { | 
|  | switch ($field->getType()) { | 
|  | case GPBType::MESSAGE: | 
|  | $klass = $field->getMessageType()->getClass(); | 
|  | $submsg = new $klass; | 
|  |  | 
|  | if (is_a($submsg, "Google\Protobuf\Duration")) { | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } else if (!is_string($value)) { | 
|  | throw new GPBDecodeException("Expect string."); | 
|  | } | 
|  | return GPBUtil::parseDuration($value); | 
|  | } else if ($field->isTimestamp()) { | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } else if (!is_string($value)) { | 
|  | throw new GPBDecodeException("Expect string."); | 
|  | } | 
|  | try { | 
|  | $timestamp = GPBUtil::parseTimestamp($value); | 
|  | } catch (\Exception $e) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid RFC 3339 timestamp: ".$e->getMessage()); | 
|  | } | 
|  |  | 
|  | $submsg->setSeconds($timestamp->getSeconds()); | 
|  | $submsg->setNanos($timestamp->getNanos()); | 
|  | } else if (is_a($submsg, "Google\Protobuf\FieldMask")) { | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | try { | 
|  | return GPBUtil::parseFieldMask($value); | 
|  | } catch (\Exception $e) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid FieldMask: ".$e->getMessage()); | 
|  | } | 
|  | } else { | 
|  | if (is_null($value) && | 
|  | !is_a($submsg, "Google\Protobuf\Value")) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (GPBUtil::hasSpecialJsonMapping($submsg)) { | 
|  | } elseif (!is_object($value) && !is_array($value)) { | 
|  | throw new GPBDecodeException("Expect message."); | 
|  | } | 
|  | $submsg->mergeFromJsonArray($value, $ignore_unknown); | 
|  | } | 
|  | return $submsg; | 
|  | case GPBType::ENUM: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (is_integer($value)) { | 
|  | return $value; | 
|  | } | 
|  | $enum_value = $field->getEnumType()->getValueByName($value); | 
|  | if (!is_null($enum_value)) { | 
|  | return $enum_value->getNumber(); | 
|  | } else if ($ignore_unknown) { | 
|  | return $this->defaultValue($field); | 
|  | } else { | 
|  | throw new GPBDecodeException( | 
|  | "Enum field only accepts integer or enum value name"); | 
|  | } | 
|  | case GPBType::STRING: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (is_numeric($value)) { | 
|  | return strval($value); | 
|  | } | 
|  | if (!is_string($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "String field only accepts string value"); | 
|  | } | 
|  | return $value; | 
|  | case GPBType::BYTES: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (!is_string($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Byte field only accepts string value"); | 
|  | } | 
|  | $proto_value = base64_decode($value, true); | 
|  | if ($proto_value === false) { | 
|  | throw new GPBDecodeException("Invalid base64 characters"); | 
|  | } | 
|  | return $proto_value; | 
|  | case GPBType::BOOL: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if ($is_map_key) { | 
|  | if ($value === "true") { | 
|  | return true; | 
|  | } | 
|  | if ($value === "false") { | 
|  | return false; | 
|  | } | 
|  | throw new GPBDecodeException( | 
|  | "Bool field only accepts bool value"); | 
|  | } | 
|  | if (!is_bool($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Bool field only accepts bool value"); | 
|  | } | 
|  | return $value; | 
|  | case GPBType::FLOAT: | 
|  | case GPBType::DOUBLE: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if ($value === "Infinity") { | 
|  | return INF; | 
|  | } | 
|  | if ($value === "-Infinity") { | 
|  | return -INF; | 
|  | } | 
|  | if ($value === "NaN") { | 
|  | return NAN; | 
|  | } | 
|  | return $value; | 
|  | case GPBType::INT32: | 
|  | case GPBType::SINT32: | 
|  | case GPBType::SFIXED32: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (!is_numeric($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int32 field"); | 
|  | } | 
|  | if (is_string($value) && trim($value) !== $value) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int32 field"); | 
|  | } | 
|  | if (bccomp($value, "2147483647") > 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Int32 too large"); | 
|  | } | 
|  | if (bccomp($value, "-2147483648") < 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Int32 too small"); | 
|  | } | 
|  | return $value; | 
|  | case GPBType::UINT32: | 
|  | case GPBType::FIXED32: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (!is_numeric($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for uint32 field"); | 
|  | } | 
|  | if (is_string($value) && trim($value) !== $value) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int32 field"); | 
|  | } | 
|  | if (bccomp($value, 4294967295) > 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Uint32 too large"); | 
|  | } | 
|  | return $value; | 
|  | case GPBType::INT64: | 
|  | case GPBType::SINT64: | 
|  | case GPBType::SFIXED64: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (!is_numeric($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int64 field"); | 
|  | } | 
|  | if (is_string($value) && trim($value) !== $value) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int64 field"); | 
|  | } | 
|  | if (bccomp($value, "9223372036854775807") > 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Int64 too large"); | 
|  | } | 
|  | if (bccomp($value, "-9223372036854775808") < 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Int64 too small"); | 
|  | } | 
|  | return $value; | 
|  | case GPBType::UINT64: | 
|  | case GPBType::FIXED64: | 
|  | if (is_null($value)) { | 
|  | return $this->defaultValue($field); | 
|  | } | 
|  | if (!is_numeric($value)) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int64 field"); | 
|  | } | 
|  | if (is_string($value) && trim($value) !== $value) { | 
|  | throw new GPBDecodeException( | 
|  | "Invalid data type for int64 field"); | 
|  | } | 
|  | if (bccomp($value, "18446744073709551615") > 0) { | 
|  | throw new GPBDecodeException( | 
|  | "Uint64 too large"); | 
|  | } | 
|  | if (bccomp($value, "9223372036854775807") > 0) { | 
|  | $value = bcsub($value, "18446744073709551616"); | 
|  | } | 
|  | return $value; | 
|  | default: | 
|  | return $value; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Populates the message from a user-supplied PHP array. Array keys | 
|  | * correspond to Message properties and nested message properties. | 
|  | * | 
|  | * Example: | 
|  | * ``` | 
|  | * $message->mergeFromArray([ | 
|  | *     'name' => 'This is a message name', | 
|  | *     'interval' => [ | 
|  | *          'startTime' => time() - 60, | 
|  | *          'endTime' => time(), | 
|  | *     ] | 
|  | * ]); | 
|  | * ``` | 
|  | * | 
|  | * This method will trigger an error if it is passed data that cannot | 
|  | * be converted to the correct type. For example, a StringValue field | 
|  | * must receive data that is either a string or a StringValue object. | 
|  | * | 
|  | * @param array $array An array containing message properties and values. | 
|  | * @return null | 
|  | */ | 
|  | protected function mergeFromArray(array $array) | 
|  | { | 
|  | // Just call the setters for the field names | 
|  | foreach ($array as $key => $value) { | 
|  | $field = $this->desc->getFieldByName($key); | 
|  | if (is_null($field)) { | 
|  | throw new \UnexpectedValueException( | 
|  | 'Invalid message property: ' . $key); | 
|  | } | 
|  | $setter = $field->getSetter(); | 
|  | if ($field->isMap()) { | 
|  | $valueField = $field->getMessageType()->getFieldByName('value'); | 
|  | if (!is_null($valueField) && $valueField->isWrapperType()) { | 
|  | self::normalizeArrayElementsToMessageType($value, $valueField->getMessageType()->getClass()); | 
|  | } | 
|  | } elseif ($field->isWrapperType()) { | 
|  | $class = $field->getMessageType()->getClass(); | 
|  | if ($field->isRepeated()) { | 
|  | self::normalizeArrayElementsToMessageType($value, $class); | 
|  | } else { | 
|  | self::normalizeToMessageType($value, $class); | 
|  | } | 
|  | } | 
|  | $this->$setter($value); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Tries to normalize the elements in $value into a provided protobuf | 
|  | * wrapper type $class. If $value is any type other than array, we do | 
|  | * not do any conversion, and instead rely on the existing protobuf | 
|  | * type checking. If $value is an array, we process each element and | 
|  | * try to convert it to an instance of $class. | 
|  | * | 
|  | * @param mixed $value The array of values to normalize. | 
|  | * @param string $class The expected wrapper class name | 
|  | */ | 
|  | private static function normalizeArrayElementsToMessageType(&$value, $class) | 
|  | { | 
|  | if (!is_array($value)) { | 
|  | // In the case that $value is not an array, we do not want to | 
|  | // attempt any conversion. Note that this includes the cases | 
|  | // when $value is a RepeatedField of MapField. In those cases, | 
|  | // we do not need to convert the elements, as they should | 
|  | // already be the correct types. | 
|  | return; | 
|  | } else { | 
|  | // Normalize each element in the array. | 
|  | foreach ($value as $key => &$elementValue) { | 
|  | self::normalizeToMessageType($elementValue, $class); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Tries to normalize $value into a provided protobuf wrapper type $class. | 
|  | * If $value is any type other than an object, we attempt to construct an | 
|  | * instance of $class and assign $value to it using the setValue method | 
|  | * shared by all wrapper types. | 
|  | * | 
|  | * This method will raise an error if it receives a type that cannot be | 
|  | * assigned to the wrapper type via setValue. | 
|  | * | 
|  | * @param mixed $value The value to normalize. | 
|  | * @param string $class The expected wrapper class name | 
|  | */ | 
|  | private static function normalizeToMessageType(&$value, $class) | 
|  | { | 
|  | if (is_null($value) || is_object($value)) { | 
|  | // This handles the case that $value is an instance of $class. We | 
|  | // choose not to do any more strict checking here, relying on the | 
|  | // existing type checking done by GPBUtil. | 
|  | return; | 
|  | } else { | 
|  | // Try to instantiate $class and set the value | 
|  | try { | 
|  | $msg = new $class; | 
|  | $msg->setValue($value); | 
|  | $value = $msg; | 
|  | return; | 
|  | } catch (\Exception $exception) { | 
|  | trigger_error( | 
|  | "Error normalizing value to type '$class': " . $exception->getMessage(), | 
|  | E_USER_ERROR | 
|  | ); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | protected function mergeFromJsonArray($array, $ignore_unknown) | 
|  | { | 
|  | if (is_a($this, "Google\Protobuf\Any")) { | 
|  | $this->clear(); | 
|  | $this->setTypeUrl($array["@type"]); | 
|  | $msg = $this->unpack(); | 
|  | if (GPBUtil::hasSpecialJsonMapping($msg)) { | 
|  | $msg->mergeFromJsonArray($array["value"], $ignore_unknown); | 
|  | } else { | 
|  | unset($array["@type"]); | 
|  | $msg->mergeFromJsonArray($array, $ignore_unknown); | 
|  | } | 
|  | $this->setValue($msg->serializeToString()); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\DoubleValue") || | 
|  | is_a($this, "Google\Protobuf\FloatValue")  || | 
|  | is_a($this, "Google\Protobuf\Int64Value")  || | 
|  | is_a($this, "Google\Protobuf\UInt64Value") || | 
|  | is_a($this, "Google\Protobuf\Int32Value")  || | 
|  | is_a($this, "Google\Protobuf\UInt32Value") || | 
|  | is_a($this, "Google\Protobuf\BoolValue")   || | 
|  | is_a($this, "Google\Protobuf\StringValue")) { | 
|  | $this->setValue($array); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\BytesValue")) { | 
|  | $this->setValue(base64_decode($array)); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\Duration")) { | 
|  | $this->mergeFrom(GPBUtil::parseDuration($array)); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\FieldMask")) { | 
|  | $this->mergeFrom(GPBUtil::parseFieldMask($array)); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\Timestamp")) { | 
|  | $this->mergeFrom(GPBUtil::parseTimestamp($array)); | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\Struct")) { | 
|  | $fields = $this->getFields(); | 
|  | foreach($array as $key => $value) { | 
|  | $v = new Value(); | 
|  | $v->mergeFromJsonArray($value, $ignore_unknown); | 
|  | $fields[$key] = $v; | 
|  | } | 
|  | return; | 
|  | } | 
|  | if (is_a($this, "Google\Protobuf\Value")) { | 
|  | if (is_bool($array)) { | 
|  | $this->setBoolValue($array); | 
|  | } elseif (is_string($array)) { | 
|  | $this->setStringValue($array); | 
|  | } elseif (is_null($array)) { | 
|  | $this->setNullValue(0); | 
|  | } elseif (is_double($array) || is_integer($array)) { | 
|  | $this->setNumberValue($array); | 
|  | } elseif (is_array($array)) { | 
|  | if (array_values($array) !== $array) { | 
|  | // Associative array | 
|  | $struct_value = $this->getStructValue(); | 
|  | if (is_null($struct_value)) { | 
|  | $struct_value = new Struct(); | 
|  | $this->setStructValue($struct_value); | 
|  | } | 
|  | foreach ($array as $key => $v) { | 
|  | $value = new Value(); | 
|  | $value->mergeFromJsonArray($v, $ignore_unknown); | 
|  | $values = $struct_value->getFields(); | 
|  | $values[$key]= $value; | 
|  | } | 
|  | } else { | 
|  | // Array | 
|  | $list_value = $this->getListValue(); | 
|  | if (is_null($list_value)) { | 
|  | $list_value = new ListValue(); | 
|  | $this->setListValue($list_value); | 
|  | } | 
|  | foreach ($array as $v) { | 
|  | $value = new Value(); | 
|  | $value->mergeFromJsonArray($v, $ignore_unknown); | 
|  | $values = $list_value->getValues(); | 
|  | $values[]= $value; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | throw new GPBDecodeException("Invalid type for Value."); | 
|  | } | 
|  | return; | 
|  | } | 
|  | $this->mergeFromArrayJsonImpl($array, $ignore_unknown); | 
|  | } | 
|  |  | 
|  | private function mergeFromArrayJsonImpl($array, $ignore_unknown) | 
|  | { | 
|  | foreach ($array as $key => $value) { | 
|  | $field = $this->desc->getFieldByJsonName($key); | 
|  | if (is_null($field)) { | 
|  | $field = $this->desc->getFieldByName($key); | 
|  | if (is_null($field)) { | 
|  | if ($ignore_unknown) { | 
|  | continue; | 
|  | } else { | 
|  | throw new GPBDecodeException( | 
|  | $key . ' is unknown.' | 
|  | ); | 
|  | } | 
|  | } | 
|  | } | 
|  | if ($field->isMap()) { | 
|  | if (is_null($value)) { | 
|  | continue; | 
|  | } | 
|  | $key_field = $field->getMessageType()->getFieldByNumber(1); | 
|  | $value_field = $field->getMessageType()->getFieldByNumber(2); | 
|  | foreach ($value as $tmp_key => $tmp_value) { | 
|  | if (is_null($tmp_value)) { | 
|  | throw new \Exception( | 
|  | "Map value field element cannot be null."); | 
|  | } | 
|  | $proto_key = $this->convertJsonValueToProtoValue( | 
|  | $tmp_key, | 
|  | $key_field, | 
|  | $ignore_unknown, | 
|  | true); | 
|  | $proto_value = $this->convertJsonValueToProtoValue( | 
|  | $tmp_value, | 
|  | $value_field, | 
|  | $ignore_unknown); | 
|  | self::kvUpdateHelper($field, $proto_key, $proto_value); | 
|  | } | 
|  | } else if ($field->isRepeated()) { | 
|  | if (is_null($value)) { | 
|  | continue; | 
|  | } | 
|  | foreach ($value as $tmp) { | 
|  | if (is_null($tmp)) { | 
|  | throw new \Exception( | 
|  | "Repeated field elements cannot be null."); | 
|  | } | 
|  | $proto_value = $this->convertJsonValueToProtoValue( | 
|  | $tmp, | 
|  | $field, | 
|  | $ignore_unknown); | 
|  | self::appendHelper($field, $proto_value); | 
|  | } | 
|  | } else { | 
|  | $setter = $field->getSetter(); | 
|  | $proto_value = $this->convertJsonValueToProtoValue( | 
|  | $value, | 
|  | $field, | 
|  | $ignore_unknown); | 
|  | if ($field->getType() === GPBType::MESSAGE) { | 
|  | if (is_null($proto_value)) { | 
|  | continue; | 
|  | } | 
|  | $getter = $field->getGetter(); | 
|  | $submsg = $this->$getter(); | 
|  | if (!is_null($submsg)) { | 
|  | $submsg->mergeFrom($proto_value); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | $this->$setter($proto_value); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function parseFromJsonStream($input, $ignore_unknown) | 
|  | { | 
|  | $array = json_decode($input->getData(), true, 512, JSON_BIGINT_AS_STRING); | 
|  | if ($this instanceof \Google\Protobuf\ListValue) { | 
|  | $array = ["values"=>$array]; | 
|  | } | 
|  | if (is_null($array)) { | 
|  | if ($this instanceof \Google\Protobuf\Value) { | 
|  | $this->setNullValue(\Google\Protobuf\NullValue::NULL_VALUE); | 
|  | return; | 
|  | } else { | 
|  | throw new GPBDecodeException( | 
|  | "Cannot decode json string: " . $input->getData()); | 
|  | } | 
|  | } | 
|  | try { | 
|  | $this->mergeFromJsonArray($array, $ignore_unknown); | 
|  | } catch (\Exception $e) { | 
|  | throw new GPBDecodeException($e->getMessage()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function serializeSingularFieldToStream($field, &$output) | 
|  | { | 
|  | if (!$this->existField($field)) { | 
|  | return true; | 
|  | } | 
|  | $getter = $field->getGetter(); | 
|  | $value = $this->$getter(); | 
|  | if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function serializeRepeatedFieldToStream($field, &$output) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count === 0) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | $packed = $field->getPacked(); | 
|  | if ($packed) { | 
|  | if (!GPBWire::writeTag( | 
|  | $output, | 
|  | GPBWire::makeTag($field->getNumber(), GPBType::STRING))) { | 
|  | return false; | 
|  | } | 
|  | $size = 0; | 
|  | foreach ($values as $value) { | 
|  | $size += $this->fieldDataOnlyByteSize($field, $value); | 
|  | } | 
|  | if (!$output->writeVarint32($size, true)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | foreach ($values as $value) { | 
|  | if (!GPBWire::serializeFieldToStream( | 
|  | $value, | 
|  | $field, | 
|  | !$packed, | 
|  | $output)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function serializeMapFieldToStream($field, $output) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count === 0) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | foreach ($values as $key => $value) { | 
|  | $map_entry = new MapEntry($field->getMessageType()); | 
|  | $map_entry->setKey($key); | 
|  | $map_entry->setValue($value); | 
|  | if (!GPBWire::serializeFieldToStream( | 
|  | $map_entry, | 
|  | $field, | 
|  | true, | 
|  | $output)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function serializeFieldToStream(&$output, $field) | 
|  | { | 
|  | if ($field->isMap()) { | 
|  | return $this->serializeMapFieldToStream($field, $output); | 
|  | } elseif ($field->isRepeated()) { | 
|  | return $this->serializeRepeatedFieldToStream($field, $output); | 
|  | } else { | 
|  | return $this->serializeSingularFieldToStream($field, $output); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function serializeFieldToJsonStream(&$output, $field) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | return GPBJsonWire::serializeFieldToStream( | 
|  | $values, $field, $output, !GPBUtil::hasSpecialJsonMapping($this)); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function serializeToStream(&$output) | 
|  | { | 
|  | $fields = $this->desc->getField(); | 
|  | foreach ($fields as $field) { | 
|  | if (!$this->serializeFieldToStream($output, $field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | $output->writeRaw($this->unknown, strlen($this->unknown)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function serializeToJsonStream(&$output) | 
|  | { | 
|  | if (is_a($this, 'Google\Protobuf\Any')) { | 
|  | $output->writeRaw("{", 1); | 
|  | $type_field = $this->desc->getFieldByNumber(1); | 
|  | $value_msg = $this->unpack(); | 
|  |  | 
|  | // Serialize type url. | 
|  | $output->writeRaw("\"@type\":", 8); | 
|  | $output->writeRaw("\"", 1); | 
|  | $output->writeRaw($this->getTypeUrl(), strlen($this->getTypeUrl())); | 
|  | $output->writeRaw("\"", 1); | 
|  |  | 
|  | // Serialize value | 
|  | if (GPBUtil::hasSpecialJsonMapping($value_msg)) { | 
|  | $output->writeRaw(",\"value\":", 9); | 
|  | $value_msg->serializeToJsonStream($output); | 
|  | } else { | 
|  | $value_fields = $value_msg->desc->getField(); | 
|  | foreach ($value_fields as $field) { | 
|  | if ($value_msg->existField($field)) { | 
|  | $output->writeRaw(",", 1); | 
|  | if (!$value_msg->serializeFieldToJsonStream($output, $field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | $output->writeRaw("}", 1); | 
|  | } elseif (is_a($this, 'Google\Protobuf\FieldMask')) { | 
|  | $field_mask = GPBUtil::formatFieldMask($this); | 
|  | $output->writeRaw("\"", 1); | 
|  | $output->writeRaw($field_mask, strlen($field_mask)); | 
|  | $output->writeRaw("\"", 1); | 
|  | } elseif (is_a($this, 'Google\Protobuf\Duration')) { | 
|  | $duration = GPBUtil::formatDuration($this) . "s"; | 
|  | $output->writeRaw("\"", 1); | 
|  | $output->writeRaw($duration, strlen($duration)); | 
|  | $output->writeRaw("\"", 1); | 
|  | } elseif (get_class($this) === 'Google\Protobuf\Timestamp') { | 
|  | $timestamp = GPBUtil::formatTimestamp($this); | 
|  | $timestamp = json_encode($timestamp); | 
|  | $output->writeRaw($timestamp, strlen($timestamp)); | 
|  | } elseif (get_class($this) === 'Google\Protobuf\ListValue') { | 
|  | $field = $this->desc->getField()[1]; | 
|  | if (!$this->existField($field)) { | 
|  | $output->writeRaw("[]", 2); | 
|  | } else { | 
|  | if (!$this->serializeFieldToJsonStream($output, $field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } elseif (get_class($this) === 'Google\Protobuf\Struct') { | 
|  | $field = $this->desc->getField()[1]; | 
|  | if (!$this->existField($field)) { | 
|  | $output->writeRaw("{}", 2); | 
|  | } else { | 
|  | if (!$this->serializeFieldToJsonStream($output, $field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | $output->writeRaw("{", 1); | 
|  | } | 
|  | $fields = $this->desc->getField(); | 
|  | $first = true; | 
|  | foreach ($fields as $field) { | 
|  | if ($this->existField($field) || | 
|  | GPBUtil::hasJsonValue($this)) { | 
|  | if ($first) { | 
|  | $first = false; | 
|  | } else { | 
|  | $output->writeRaw(",", 1); | 
|  | } | 
|  | if (!$this->serializeFieldToJsonStream($output, $field)) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | $output->writeRaw("}", 1); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Serialize the message to string. | 
|  | * @return string Serialized binary protobuf data. | 
|  | */ | 
|  | public function serializeToString() | 
|  | { | 
|  | $output = new CodedOutputStream($this->byteSize()); | 
|  | $this->serializeToStream($output); | 
|  | return $output->getData(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Serialize the message to json string. | 
|  | * @return string Serialized json protobuf data. | 
|  | */ | 
|  | public function serializeToJsonString() | 
|  | { | 
|  | $output = new CodedOutputStream($this->jsonByteSize()); | 
|  | $this->serializeToJsonStream($output); | 
|  | return $output->getData(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function existField($field) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $hazzer = "has" . substr($getter, 3); | 
|  |  | 
|  | if (method_exists($this, $hazzer)) { | 
|  | return $this->$hazzer(); | 
|  | } else if ($field->getOneofIndex() !== -1) { | 
|  | // For old generated code, which does not have hazzers for oneof | 
|  | // fields. | 
|  | $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; | 
|  | $oneof_name = $oneof->getName(); | 
|  | return $this->$oneof_name->getNumber() === $field->getNumber(); | 
|  | } | 
|  |  | 
|  | $values = $this->$getter(); | 
|  | if ($field->isMap()) { | 
|  | return count($values) !== 0; | 
|  | } elseif ($field->isRepeated()) { | 
|  | return count($values) !== 0; | 
|  | } else { | 
|  | return $values !== $this->defaultValue($field); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function repeatedFieldDataOnlyByteSize($field) | 
|  | { | 
|  | $size = 0; | 
|  |  | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count !== 0) { | 
|  | $size += $count * GPBWire::tagSize($field); | 
|  | foreach ($values as $value) { | 
|  | $size += $this->singularFieldDataOnlyByteSize($field); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function fieldDataOnlyByteSize($field, $value) | 
|  | { | 
|  | $size = 0; | 
|  |  | 
|  | switch ($field->getType()) { | 
|  | case GPBType::BOOL: | 
|  | $size += 1; | 
|  | break; | 
|  | case GPBType::FLOAT: | 
|  | case GPBType::FIXED32: | 
|  | case GPBType::SFIXED32: | 
|  | $size += 4; | 
|  | break; | 
|  | case GPBType::DOUBLE: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::SFIXED64: | 
|  | $size += 8; | 
|  | break; | 
|  | case GPBType::INT32: | 
|  | case GPBType::ENUM: | 
|  | $size += GPBWire::varint32Size($value, true); | 
|  | break; | 
|  | case GPBType::UINT32: | 
|  | $size += GPBWire::varint32Size($value); | 
|  | break; | 
|  | case GPBType::UINT64: | 
|  | case GPBType::INT64: | 
|  | $size += GPBWire::varint64Size($value); | 
|  | break; | 
|  | case GPBType::SINT32: | 
|  | $size += GPBWire::sint32Size($value); | 
|  | break; | 
|  | case GPBType::SINT64: | 
|  | $size += GPBWire::sint64Size($value); | 
|  | break; | 
|  | case GPBType::STRING: | 
|  | case GPBType::BYTES: | 
|  | $size += strlen($value); | 
|  | $size += GPBWire::varint32Size($size); | 
|  | break; | 
|  | case GPBType::MESSAGE: | 
|  | $size += $value->byteSize(); | 
|  | $size += GPBWire::varint32Size($size); | 
|  | break; | 
|  | case GPBType::GROUP: | 
|  | // TODO: Add support. | 
|  | user_error("Unsupported type."); | 
|  | break; | 
|  | default: | 
|  | user_error("Unsupported type."); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function fieldDataOnlyJsonByteSize($field, $value) | 
|  | { | 
|  | $size = 0; | 
|  |  | 
|  | switch ($field->getType()) { | 
|  | case GPBType::SFIXED32: | 
|  | case GPBType::SINT32: | 
|  | case GPBType::INT32: | 
|  | $size += strlen(strval($value)); | 
|  | break; | 
|  | case GPBType::FIXED32: | 
|  | case GPBType::UINT32: | 
|  | if ($value < 0) { | 
|  | $value = bcadd($value, "4294967296"); | 
|  | } | 
|  | $size += strlen(strval($value)); | 
|  | break; | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::UINT64: | 
|  | if ($value < 0) { | 
|  | $value = bcadd($value, "18446744073709551616"); | 
|  | } | 
|  | // Intentional fall through. | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::INT64: | 
|  | case GPBType::SINT64: | 
|  | $size += 2;  // size for "" | 
|  | $size += strlen(strval($value)); | 
|  | break; | 
|  | case GPBType::FLOAT: | 
|  | if (is_nan($value)) { | 
|  | $size += strlen("NaN") + 2; | 
|  | } elseif ($value === INF) { | 
|  | $size += strlen("Infinity") + 2; | 
|  | } elseif ($value === -INF) { | 
|  | $size += strlen("-Infinity") + 2; | 
|  | } else { | 
|  | $size += strlen(sprintf("%.8g", $value)); | 
|  | } | 
|  | break; | 
|  | case GPBType::DOUBLE: | 
|  | if (is_nan($value)) { | 
|  | $size += strlen("NaN") + 2; | 
|  | } elseif ($value === INF) { | 
|  | $size += strlen("Infinity") + 2; | 
|  | } elseif ($value === -INF) { | 
|  | $size += strlen("-Infinity") + 2; | 
|  | } else { | 
|  | $size += strlen(sprintf("%.17g", $value)); | 
|  | } | 
|  | break; | 
|  | case GPBType::ENUM: | 
|  | $enum_desc = $field->getEnumType(); | 
|  | if ($enum_desc->getClass() === "Google\Protobuf\NullValue") { | 
|  | $size += 4; | 
|  | break; | 
|  | } | 
|  | $enum_value_desc = $enum_desc->getValueByNumber($value); | 
|  | if (!is_null($enum_value_desc)) { | 
|  | $size += 2;  // size for "" | 
|  | $size += strlen($enum_value_desc->getName()); | 
|  | } else { | 
|  | $str_value = strval($value); | 
|  | $size += strlen($str_value); | 
|  | } | 
|  | break; | 
|  | case GPBType::BOOL: | 
|  | if ($value) { | 
|  | $size += 4; | 
|  | } else { | 
|  | $size += 5; | 
|  | } | 
|  | break; | 
|  | case GPBType::STRING: | 
|  | $value = json_encode($value, JSON_UNESCAPED_UNICODE); | 
|  | $size += strlen($value); | 
|  | break; | 
|  | case GPBType::BYTES: | 
|  | # if (is_a($this, "Google\Protobuf\BytesValue")) { | 
|  | #     $size += strlen(json_encode($value)); | 
|  | # } else { | 
|  | #     $size += strlen(base64_encode($value)); | 
|  | #     $size += 2;  // size for \"\" | 
|  | # } | 
|  | $size += strlen(base64_encode($value)); | 
|  | $size += 2;  // size for \"\" | 
|  | break; | 
|  | case GPBType::MESSAGE: | 
|  | $size += $value->jsonByteSize(); | 
|  | break; | 
|  | #             case GPBType::GROUP: | 
|  | #                 // TODO: Add support. | 
|  | #                 user_error("Unsupported type."); | 
|  | #                 break; | 
|  | default: | 
|  | user_error("Unsupported type " . $field->getType()); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function fieldByteSize($field) | 
|  | { | 
|  | $size = 0; | 
|  | if ($field->isMap()) { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count !== 0) { | 
|  | $size += $count * GPBWire::tagSize($field); | 
|  | $message_type = $field->getMessageType(); | 
|  | $key_field = $message_type->getFieldByNumber(1); | 
|  | $value_field = $message_type->getFieldByNumber(2); | 
|  | foreach ($values as $key => $value) { | 
|  | $data_size = 0; | 
|  | if ($key != $this->defaultValue($key_field)) { | 
|  | $data_size += $this->fieldDataOnlyByteSize( | 
|  | $key_field, | 
|  | $key); | 
|  | $data_size += GPBWire::tagSize($key_field); | 
|  | } | 
|  | if ($value != $this->defaultValue($value_field)) { | 
|  | $data_size += $this->fieldDataOnlyByteSize( | 
|  | $value_field, | 
|  | $value); | 
|  | $data_size += GPBWire::tagSize($value_field); | 
|  | } | 
|  | $size += GPBWire::varint32Size($data_size) + $data_size; | 
|  | } | 
|  | } | 
|  | } elseif ($field->isRepeated()) { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count !== 0) { | 
|  | if ($field->getPacked()) { | 
|  | $data_size = 0; | 
|  | foreach ($values as $value) { | 
|  | $data_size += $this->fieldDataOnlyByteSize($field, $value); | 
|  | } | 
|  | $size += GPBWire::tagSize($field); | 
|  | $size += GPBWire::varint32Size($data_size); | 
|  | $size += $data_size; | 
|  | } else { | 
|  | $size += $count * GPBWire::tagSize($field); | 
|  | foreach ($values as $value) { | 
|  | $size += $this->fieldDataOnlyByteSize($field, $value); | 
|  | } | 
|  | } | 
|  | } | 
|  | } elseif ($this->existField($field)) { | 
|  | $size += GPBWire::tagSize($field); | 
|  | $getter = $field->getGetter(); | 
|  | $value = $this->$getter(); | 
|  | $size += $this->fieldDataOnlyByteSize($field, $value); | 
|  | } | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | private function fieldJsonByteSize($field) | 
|  | { | 
|  | $size = 0; | 
|  |  | 
|  | if ($field->isMap()) { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count !== 0) { | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | $size += 3;                              // size for "\"\":". | 
|  | $size += strlen($field->getJsonName());  // size for field name | 
|  | } | 
|  | $size += 2;  // size for "{}". | 
|  | $size += $count - 1;                     // size for commas | 
|  | $getter = $field->getGetter(); | 
|  | $map_entry = $field->getMessageType(); | 
|  | $key_field = $map_entry->getFieldByNumber(1); | 
|  | $value_field = $map_entry->getFieldByNumber(2); | 
|  | switch ($key_field->getType()) { | 
|  | case GPBType::STRING: | 
|  | case GPBType::SFIXED64: | 
|  | case GPBType::INT64: | 
|  | case GPBType::SINT64: | 
|  | case GPBType::FIXED64: | 
|  | case GPBType::UINT64: | 
|  | $additional_quote = false; | 
|  | break; | 
|  | default: | 
|  | $additional_quote = true; | 
|  | } | 
|  | foreach ($values as $key => $value) { | 
|  | if ($additional_quote) { | 
|  | $size += 2;  // size for "" | 
|  | } | 
|  | $size += $this->fieldDataOnlyJsonByteSize($key_field, $key); | 
|  | $size += $this->fieldDataOnlyJsonByteSize($value_field, $value); | 
|  | $size += 1;  // size for : | 
|  | } | 
|  | } | 
|  | } elseif ($field->isRepeated()) { | 
|  | $getter = $field->getGetter(); | 
|  | $values = $this->$getter(); | 
|  | $count = count($values); | 
|  | if ($count !== 0) { | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | $size += 3;                              // size for "\"\":". | 
|  | $size += strlen($field->getJsonName());  // size for field name | 
|  | } | 
|  | $size += 2;  // size for "[]". | 
|  | $size += $count - 1;                     // size for commas | 
|  | $getter = $field->getGetter(); | 
|  | foreach ($values as $value) { | 
|  | $size += $this->fieldDataOnlyJsonByteSize($field, $value); | 
|  | } | 
|  | } | 
|  | } elseif ($this->existField($field) || GPBUtil::hasJsonValue($this)) { | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | $size += 3;                              // size for "\"\":". | 
|  | $size += strlen($field->getJsonName());  // size for field name | 
|  | } | 
|  | $getter = $field->getGetter(); | 
|  | $value = $this->$getter(); | 
|  | $size += $this->fieldDataOnlyJsonByteSize($field, $value); | 
|  | } | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function byteSize() | 
|  | { | 
|  | $size = 0; | 
|  |  | 
|  | $fields = $this->desc->getField(); | 
|  | foreach ($fields as $field) { | 
|  | $size += $this->fieldByteSize($field); | 
|  | } | 
|  | $size += strlen($this->unknown); | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | private function appendHelper($field, $append_value) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $setter = $field->getSetter(); | 
|  |  | 
|  | $field_arr_value = $this->$getter(); | 
|  | $field_arr_value[] = $append_value; | 
|  |  | 
|  | if (!is_object($field_arr_value)) { | 
|  | $this->$setter($field_arr_value); | 
|  | } | 
|  | } | 
|  |  | 
|  | private function kvUpdateHelper($field, $update_key, $update_value) | 
|  | { | 
|  | $getter = $field->getGetter(); | 
|  | $setter = $field->getSetter(); | 
|  |  | 
|  | $field_arr_value = $this->$getter(); | 
|  | $field_arr_value[$update_key] = $update_value; | 
|  |  | 
|  | if (!is_object($field_arr_value)) { | 
|  | $this->$setter($field_arr_value); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @ignore | 
|  | */ | 
|  | public function jsonByteSize() | 
|  | { | 
|  | $size = 0; | 
|  | if (is_a($this, 'Google\Protobuf\Any')) { | 
|  | // Size for "{}". | 
|  | $size += 2; | 
|  |  | 
|  | // Size for "\"@type\":". | 
|  | $size += 8; | 
|  |  | 
|  | // Size for url. +2 for "" /. | 
|  | $size += strlen($this->getTypeUrl()) + 2; | 
|  |  | 
|  | $value_msg = $this->unpack(); | 
|  | if (GPBUtil::hasSpecialJsonMapping($value_msg)) { | 
|  | // Size for "\",value\":". | 
|  | $size += 9; | 
|  | $size += $value_msg->jsonByteSize(); | 
|  | } else { | 
|  | $value_size = $value_msg->jsonByteSize(); | 
|  | // size === 2 it's empty message {} which is not serialized inside any | 
|  | if ($value_size !== 2) { | 
|  | // Size for value. +1 for comma, -2 for "{}". | 
|  | $size += $value_size -1; | 
|  | } | 
|  | } | 
|  | } elseif (get_class($this) === 'Google\Protobuf\FieldMask') { | 
|  | $field_mask = GPBUtil::formatFieldMask($this); | 
|  | $size += strlen($field_mask) + 2;  // 2 for "" | 
|  | } elseif (get_class($this) === 'Google\Protobuf\Duration') { | 
|  | $duration = GPBUtil::formatDuration($this) . "s"; | 
|  | $size += strlen($duration) + 2;  // 2 for "" | 
|  | } elseif (get_class($this) === 'Google\Protobuf\Timestamp') { | 
|  | $timestamp = GPBUtil::formatTimestamp($this); | 
|  | $timestamp = json_encode($timestamp); | 
|  | $size += strlen($timestamp); | 
|  | } elseif (get_class($this) === 'Google\Protobuf\ListValue') { | 
|  | $field = $this->desc->getField()[1]; | 
|  | if ($this->existField($field)) { | 
|  | $field_size = $this->fieldJsonByteSize($field); | 
|  | $size += $field_size; | 
|  | } else { | 
|  | // Size for "[]". | 
|  | $size += 2; | 
|  | } | 
|  | } elseif (get_class($this) === 'Google\Protobuf\Struct') { | 
|  | $field = $this->desc->getField()[1]; | 
|  | if ($this->existField($field)) { | 
|  | $field_size = $this->fieldJsonByteSize($field); | 
|  | $size += $field_size; | 
|  | } else { | 
|  | // Size for "{}". | 
|  | $size += 2; | 
|  | } | 
|  | } else { | 
|  | if (!GPBUtil::hasSpecialJsonMapping($this)) { | 
|  | // Size for "{}". | 
|  | $size += 2; | 
|  | } | 
|  |  | 
|  | $fields = $this->desc->getField(); | 
|  | $count = 0; | 
|  | foreach ($fields as $field) { | 
|  | $field_size = $this->fieldJsonByteSize($field); | 
|  | $size += $field_size; | 
|  | if ($field_size != 0) { | 
|  | $count++; | 
|  | } | 
|  | } | 
|  | // size for comma | 
|  | $size += $count > 0 ? ($count - 1) : 0; | 
|  | } | 
|  | return $size; | 
|  | } | 
|  |  | 
|  | public function __debugInfo() | 
|  | { | 
|  | if (is_a($this, 'Google\Protobuf\FieldMask')) { | 
|  | return ['paths' => $this->getPaths()->__debugInfo()]; | 
|  | } | 
|  |  | 
|  | if (is_a($this, 'Google\Protobuf\Value')) { | 
|  | switch ($this->getKind()) { | 
|  | case 'null_value': | 
|  | return ['nullValue' => $this->getNullValue()]; | 
|  | case 'number_value': | 
|  | return ['numberValue' => $this->getNumberValue()]; | 
|  | case 'string_value': | 
|  | return ['stringValue' => $this->getStringValue()]; | 
|  | case 'bool_value': | 
|  | return ['boolValue' => $this->getBoolValue()]; | 
|  | case 'struct_value': | 
|  | return ['structValue' => $this->getStructValue()->__debugInfo()]; | 
|  | case 'list_value': | 
|  | return ['listValue' => $this->getListValue()->__debugInfo()]; | 
|  | } | 
|  | return []; | 
|  | } | 
|  |  | 
|  | if (is_a($this, 'Google\Protobuf\BoolValue') | 
|  | || is_a($this, 'Google\Protobuf\BytesValue') | 
|  | || is_a($this, 'Google\Protobuf\DoubleValue') | 
|  | || is_a($this, 'Google\Protobuf\FloatValue') | 
|  | || is_a($this, 'Google\Protobuf\StringValue') | 
|  | || is_a($this, 'Google\Protobuf\Int32Value') | 
|  | || is_a($this, 'Google\Protobuf\Int64Value') | 
|  | || is_a($this, 'Google\Protobuf\UInt32Value') | 
|  | || is_a($this, 'Google\Protobuf\UInt64Value') | 
|  | ) { | 
|  | return [ | 
|  | 'value' => json_decode($this->serializeToJsonString(), true), | 
|  | ]; | 
|  | } | 
|  |  | 
|  | if ( | 
|  | is_a($this, 'Google\Protobuf\Duration') | 
|  | || is_a($this, 'Google\Protobuf\Timestamp') | 
|  | ) { | 
|  | return [ | 
|  | 'seconds' => $this->getSeconds(), | 
|  | 'nanos' => $this->getNanos(), | 
|  | ]; | 
|  | } | 
|  |  | 
|  | return json_decode($this->serializeToJsonString(), true); | 
|  | } | 
|  | } |