1ffe3c632Sopenharmony_ci<?php
2ffe3c632Sopenharmony_ci
3ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
4ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc.  All rights reserved.
5ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/
6ffe3c632Sopenharmony_ci//
7ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
8ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are
9ffe3c632Sopenharmony_ci// met:
10ffe3c632Sopenharmony_ci//
11ffe3c632Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
12ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer.
13ffe3c632Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
14ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer
15ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the
16ffe3c632Sopenharmony_ci// distribution.
17ffe3c632Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
18ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from
19ffe3c632Sopenharmony_ci// this software without specific prior written permission.
20ffe3c632Sopenharmony_ci//
21ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32ffe3c632Sopenharmony_ci
33ffe3c632Sopenharmony_ci/**
34ffe3c632Sopenharmony_ci * Defines Message, the parent class extended by all protocol message classes.
35ffe3c632Sopenharmony_ci */
36ffe3c632Sopenharmony_ci
37ffe3c632Sopenharmony_cinamespace Google\Protobuf\Internal;
38ffe3c632Sopenharmony_ci
39ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\CodedInputStream;
40ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\CodedOutputStream;
41ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\DescriptorPool;
42ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\GPBLabel;
43ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\GPBType;
44ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\GPBWire;
45ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\MapEntry;
46ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\RepeatedField;
47ffe3c632Sopenharmony_ciuse Google\Protobuf\ListValue;
48ffe3c632Sopenharmony_ciuse Google\Protobuf\Value;
49ffe3c632Sopenharmony_ciuse Google\Protobuf\Struct;
50ffe3c632Sopenharmony_ciuse Google\Protobuf\NullValue;
51ffe3c632Sopenharmony_ci
52ffe3c632Sopenharmony_ci/**
53ffe3c632Sopenharmony_ci * Parent class of all proto messages. Users should not instantiate this class
54ffe3c632Sopenharmony_ci * or extend this class or its child classes by their own.  See the comment of
55ffe3c632Sopenharmony_ci * specific functions for more details.
56ffe3c632Sopenharmony_ci */
57ffe3c632Sopenharmony_ciclass Message
58ffe3c632Sopenharmony_ci{
59ffe3c632Sopenharmony_ci
60ffe3c632Sopenharmony_ci    /**
61ffe3c632Sopenharmony_ci     * @ignore
62ffe3c632Sopenharmony_ci     */
63ffe3c632Sopenharmony_ci    private $desc;
64ffe3c632Sopenharmony_ci    private $unknown = "";
65ffe3c632Sopenharmony_ci
66ffe3c632Sopenharmony_ci    /**
67ffe3c632Sopenharmony_ci     * @ignore
68ffe3c632Sopenharmony_ci     */
69ffe3c632Sopenharmony_ci    public function __construct($data = NULL)
70ffe3c632Sopenharmony_ci    {
71ffe3c632Sopenharmony_ci        // MapEntry message is shared by all types of map fields, whose
72ffe3c632Sopenharmony_ci        // descriptors are different from each other. Thus, we cannot find a
73ffe3c632Sopenharmony_ci        // specific descriptor from the descriptor pool.
74ffe3c632Sopenharmony_ci        if ($this instanceof MapEntry) {
75ffe3c632Sopenharmony_ci            $this->initWithDescriptor($data);
76ffe3c632Sopenharmony_ci        } else {
77ffe3c632Sopenharmony_ci            $this->initWithGeneratedPool();
78ffe3c632Sopenharmony_ci            if (is_array($data)) {
79ffe3c632Sopenharmony_ci                $this->mergeFromArray($data);
80ffe3c632Sopenharmony_ci            } else if (!empty($data)) {
81ffe3c632Sopenharmony_ci                throw new \InvalidArgumentException(
82ffe3c632Sopenharmony_ci                    'Message constructor must be an array or null.'
83ffe3c632Sopenharmony_ci                );
84ffe3c632Sopenharmony_ci            }
85ffe3c632Sopenharmony_ci        }
86ffe3c632Sopenharmony_ci    }
87ffe3c632Sopenharmony_ci
88ffe3c632Sopenharmony_ci    /**
89ffe3c632Sopenharmony_ci     * @ignore
90ffe3c632Sopenharmony_ci     */
91ffe3c632Sopenharmony_ci    private function initWithGeneratedPool()
92ffe3c632Sopenharmony_ci    {
93ffe3c632Sopenharmony_ci        $pool = DescriptorPool::getGeneratedPool();
94ffe3c632Sopenharmony_ci        $this->desc = $pool->getDescriptorByClassName(get_class($this));
95ffe3c632Sopenharmony_ci        if (is_null($this->desc)) {
96ffe3c632Sopenharmony_ci            user_error(get_class($this) . " is not found in descriptor pool.");
97ffe3c632Sopenharmony_ci            return;
98ffe3c632Sopenharmony_ci        }
99ffe3c632Sopenharmony_ci        foreach ($this->desc->getField() as $field) {
100ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
101ffe3c632Sopenharmony_ci            if ($field->isMap()) {
102ffe3c632Sopenharmony_ci                $message_type = $field->getMessageType();
103ffe3c632Sopenharmony_ci                $key_field = $message_type->getFieldByNumber(1);
104ffe3c632Sopenharmony_ci                $value_field = $message_type->getFieldByNumber(2);
105ffe3c632Sopenharmony_ci                switch ($value_field->getType()) {
106ffe3c632Sopenharmony_ci                    case GPBType::MESSAGE:
107ffe3c632Sopenharmony_ci                    case GPBType::GROUP:
108ffe3c632Sopenharmony_ci                        $map_field = new MapField(
109ffe3c632Sopenharmony_ci                            $key_field->getType(),
110ffe3c632Sopenharmony_ci                            $value_field->getType(),
111ffe3c632Sopenharmony_ci                            $value_field->getMessageType()->getClass());
112ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
113ffe3c632Sopenharmony_ci                        break;
114ffe3c632Sopenharmony_ci                    case GPBType::ENUM:
115ffe3c632Sopenharmony_ci                        $map_field = new MapField(
116ffe3c632Sopenharmony_ci                            $key_field->getType(),
117ffe3c632Sopenharmony_ci                            $value_field->getType(),
118ffe3c632Sopenharmony_ci                            $value_field->getEnumType()->getClass());
119ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
120ffe3c632Sopenharmony_ci                        break;
121ffe3c632Sopenharmony_ci                    default:
122ffe3c632Sopenharmony_ci                        $map_field = new MapField(
123ffe3c632Sopenharmony_ci                            $key_field->getType(),
124ffe3c632Sopenharmony_ci                            $value_field->getType());
125ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
126ffe3c632Sopenharmony_ci                        break;
127ffe3c632Sopenharmony_ci                }
128ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::REPEATED) {
129ffe3c632Sopenharmony_ci                switch ($field->getType()) {
130ffe3c632Sopenharmony_ci                    case GPBType::MESSAGE:
131ffe3c632Sopenharmony_ci                    case GPBType::GROUP:
132ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField(
133ffe3c632Sopenharmony_ci                            $field->getType(),
134ffe3c632Sopenharmony_ci                            $field->getMessageType()->getClass());
135ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
136ffe3c632Sopenharmony_ci                        break;
137ffe3c632Sopenharmony_ci                    case GPBType::ENUM:
138ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField(
139ffe3c632Sopenharmony_ci                            $field->getType(),
140ffe3c632Sopenharmony_ci                            $field->getEnumType()->getClass());
141ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
142ffe3c632Sopenharmony_ci                        break;
143ffe3c632Sopenharmony_ci                    default:
144ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField($field->getType());
145ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
146ffe3c632Sopenharmony_ci                        break;
147ffe3c632Sopenharmony_ci                }
148ffe3c632Sopenharmony_ci            } else if ($field->getOneofIndex() !== -1) {
149ffe3c632Sopenharmony_ci                $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
150ffe3c632Sopenharmony_ci                $oneof_name = $oneof->getName();
151ffe3c632Sopenharmony_ci                $this->$oneof_name = new OneofField($oneof);
152ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::OPTIONAL &&
153ffe3c632Sopenharmony_ci                       PHP_INT_SIZE == 4) {
154ffe3c632Sopenharmony_ci                switch ($field->getType()) {
155ffe3c632Sopenharmony_ci                    case GPBType::INT64:
156ffe3c632Sopenharmony_ci                    case GPBType::UINT64:
157ffe3c632Sopenharmony_ci                    case GPBType::FIXED64:
158ffe3c632Sopenharmony_ci                    case GPBType::SFIXED64:
159ffe3c632Sopenharmony_ci                    case GPBType::SINT64:
160ffe3c632Sopenharmony_ci                        $this->$setter("0");
161ffe3c632Sopenharmony_ci                }
162ffe3c632Sopenharmony_ci            }
163ffe3c632Sopenharmony_ci        }
164ffe3c632Sopenharmony_ci    }
165ffe3c632Sopenharmony_ci
166ffe3c632Sopenharmony_ci    /**
167ffe3c632Sopenharmony_ci     * @ignore
168ffe3c632Sopenharmony_ci     */
169ffe3c632Sopenharmony_ci    private function initWithDescriptor(Descriptor $desc)
170ffe3c632Sopenharmony_ci    {
171ffe3c632Sopenharmony_ci        $this->desc = $desc;
172ffe3c632Sopenharmony_ci        foreach ($desc->getField() as $field) {
173ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
174ffe3c632Sopenharmony_ci            $defaultValue = $this->defaultValue($field);
175ffe3c632Sopenharmony_ci            $this->$setter($defaultValue);
176ffe3c632Sopenharmony_ci        }
177ffe3c632Sopenharmony_ci    }
178ffe3c632Sopenharmony_ci
179ffe3c632Sopenharmony_ci    protected function readWrapperValue($member)
180ffe3c632Sopenharmony_ci    {
181ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByName($member);
182ffe3c632Sopenharmony_ci        $oneof_index = $field->getOneofIndex();
183ffe3c632Sopenharmony_ci        if ($oneof_index === -1) {
184ffe3c632Sopenharmony_ci            $wrapper = $this->$member;
185ffe3c632Sopenharmony_ci        } else {
186ffe3c632Sopenharmony_ci            $wrapper = $this->readOneof($field->getNumber());
187ffe3c632Sopenharmony_ci        }
188ffe3c632Sopenharmony_ci
189ffe3c632Sopenharmony_ci        if (is_null($wrapper)) {
190ffe3c632Sopenharmony_ci            return NULL;
191ffe3c632Sopenharmony_ci        } else {
192ffe3c632Sopenharmony_ci            return $wrapper->getValue();
193ffe3c632Sopenharmony_ci        }
194ffe3c632Sopenharmony_ci    }
195ffe3c632Sopenharmony_ci
196ffe3c632Sopenharmony_ci    protected function writeWrapperValue($member, $value)
197ffe3c632Sopenharmony_ci    {
198ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByName($member);
199ffe3c632Sopenharmony_ci        $wrapped_value = $value;
200ffe3c632Sopenharmony_ci        if (!is_null($value)) {
201ffe3c632Sopenharmony_ci            $desc = $field->getMessageType();
202ffe3c632Sopenharmony_ci            $klass = $desc->getClass();
203ffe3c632Sopenharmony_ci            $wrapped_value = new $klass;
204ffe3c632Sopenharmony_ci            $wrapped_value->setValue($value);
205ffe3c632Sopenharmony_ci        }
206ffe3c632Sopenharmony_ci
207ffe3c632Sopenharmony_ci        $oneof_index = $field->getOneofIndex();
208ffe3c632Sopenharmony_ci        if ($oneof_index === -1) {
209ffe3c632Sopenharmony_ci            $this->$member = $wrapped_value;
210ffe3c632Sopenharmony_ci        } else {
211ffe3c632Sopenharmony_ci            $this->writeOneof($field->getNumber(), $wrapped_value);
212ffe3c632Sopenharmony_ci        }
213ffe3c632Sopenharmony_ci    }
214ffe3c632Sopenharmony_ci
215ffe3c632Sopenharmony_ci    protected function readOneof($number)
216ffe3c632Sopenharmony_ci    {
217ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByNumber($number);
218ffe3c632Sopenharmony_ci        $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
219ffe3c632Sopenharmony_ci        $oneof_name = $oneof->getName();
220ffe3c632Sopenharmony_ci        $oneof_field = $this->$oneof_name;
221ffe3c632Sopenharmony_ci        if ($number === $oneof_field->getNumber()) {
222ffe3c632Sopenharmony_ci            return $oneof_field->getValue();
223ffe3c632Sopenharmony_ci        } else {
224ffe3c632Sopenharmony_ci            return $this->defaultValue($field);
225ffe3c632Sopenharmony_ci        }
226ffe3c632Sopenharmony_ci    }
227ffe3c632Sopenharmony_ci
228ffe3c632Sopenharmony_ci    protected function hasOneof($number)
229ffe3c632Sopenharmony_ci    {
230ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByNumber($number);
231ffe3c632Sopenharmony_ci        $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
232ffe3c632Sopenharmony_ci        $oneof_name = $oneof->getName();
233ffe3c632Sopenharmony_ci        $oneof_field = $this->$oneof_name;
234ffe3c632Sopenharmony_ci        return $number === $oneof_field->getNumber();
235ffe3c632Sopenharmony_ci    }
236ffe3c632Sopenharmony_ci
237ffe3c632Sopenharmony_ci    protected function writeOneof($number, $value)
238ffe3c632Sopenharmony_ci    {
239ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByNumber($number);
240ffe3c632Sopenharmony_ci        $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
241ffe3c632Sopenharmony_ci        $oneof_name = $oneof->getName();
242ffe3c632Sopenharmony_ci        $oneof_field = $this->$oneof_name;
243ffe3c632Sopenharmony_ci        $oneof_field->setValue($value);
244ffe3c632Sopenharmony_ci        $oneof_field->setFieldName($field->getName());
245ffe3c632Sopenharmony_ci        $oneof_field->setNumber($number);
246ffe3c632Sopenharmony_ci    }
247ffe3c632Sopenharmony_ci
248ffe3c632Sopenharmony_ci    protected function whichOneof($oneof_name)
249ffe3c632Sopenharmony_ci    {
250ffe3c632Sopenharmony_ci        $oneof_field = $this->$oneof_name;
251ffe3c632Sopenharmony_ci        $number = $oneof_field->getNumber();
252ffe3c632Sopenharmony_ci        if ($number == 0) {
253ffe3c632Sopenharmony_ci          return "";
254ffe3c632Sopenharmony_ci        }
255ffe3c632Sopenharmony_ci        $field = $this->desc->getFieldByNumber($number);
256ffe3c632Sopenharmony_ci        return $field->getName();
257ffe3c632Sopenharmony_ci    }
258ffe3c632Sopenharmony_ci
259ffe3c632Sopenharmony_ci    /**
260ffe3c632Sopenharmony_ci     * @ignore
261ffe3c632Sopenharmony_ci     */
262ffe3c632Sopenharmony_ci    private function defaultValue($field)
263ffe3c632Sopenharmony_ci    {
264ffe3c632Sopenharmony_ci        $value = null;
265ffe3c632Sopenharmony_ci
266ffe3c632Sopenharmony_ci        switch ($field->getType()) {
267ffe3c632Sopenharmony_ci            case GPBType::DOUBLE:
268ffe3c632Sopenharmony_ci            case GPBType::FLOAT:
269ffe3c632Sopenharmony_ci                return 0.0;
270ffe3c632Sopenharmony_ci            case GPBType::UINT32:
271ffe3c632Sopenharmony_ci            case GPBType::INT32:
272ffe3c632Sopenharmony_ci            case GPBType::FIXED32:
273ffe3c632Sopenharmony_ci            case GPBType::SFIXED32:
274ffe3c632Sopenharmony_ci            case GPBType::SINT32:
275ffe3c632Sopenharmony_ci            case GPBType::ENUM:
276ffe3c632Sopenharmony_ci                return 0;
277ffe3c632Sopenharmony_ci            case GPBType::INT64:
278ffe3c632Sopenharmony_ci            case GPBType::UINT64:
279ffe3c632Sopenharmony_ci            case GPBType::FIXED64:
280ffe3c632Sopenharmony_ci            case GPBType::SFIXED64:
281ffe3c632Sopenharmony_ci            case GPBType::SINT64:
282ffe3c632Sopenharmony_ci                if (PHP_INT_SIZE === 4) {
283ffe3c632Sopenharmony_ci                    return '0';
284ffe3c632Sopenharmony_ci                } else {
285ffe3c632Sopenharmony_ci                    return 0;
286ffe3c632Sopenharmony_ci                }
287ffe3c632Sopenharmony_ci            case GPBType::BOOL:
288ffe3c632Sopenharmony_ci                return false;
289ffe3c632Sopenharmony_ci            case GPBType::STRING:
290ffe3c632Sopenharmony_ci            case GPBType::BYTES:
291ffe3c632Sopenharmony_ci                return "";
292ffe3c632Sopenharmony_ci            case GPBType::GROUP:
293ffe3c632Sopenharmony_ci            case GPBType::MESSAGE:
294ffe3c632Sopenharmony_ci                return null;
295ffe3c632Sopenharmony_ci            default:
296ffe3c632Sopenharmony_ci                user_error("Unsupported type.");
297ffe3c632Sopenharmony_ci                return false;
298ffe3c632Sopenharmony_ci        }
299ffe3c632Sopenharmony_ci    }
300ffe3c632Sopenharmony_ci
301ffe3c632Sopenharmony_ci    /**
302ffe3c632Sopenharmony_ci     * @ignore
303ffe3c632Sopenharmony_ci     */
304ffe3c632Sopenharmony_ci    private function skipField($input, $tag)
305ffe3c632Sopenharmony_ci    {
306ffe3c632Sopenharmony_ci        $number = GPBWire::getTagFieldNumber($tag);
307ffe3c632Sopenharmony_ci        if ($number === 0) {
308ffe3c632Sopenharmony_ci            throw new GPBDecodeException("Illegal field number zero.");
309ffe3c632Sopenharmony_ci        }
310ffe3c632Sopenharmony_ci
311ffe3c632Sopenharmony_ci        $start = $input->current();
312ffe3c632Sopenharmony_ci        switch (GPBWire::getTagWireType($tag)) {
313ffe3c632Sopenharmony_ci            case GPBWireType::VARINT:
314ffe3c632Sopenharmony_ci                $uint64 = 0;
315ffe3c632Sopenharmony_ci                if (!$input->readVarint64($uint64)) {
316ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
317ffe3c632Sopenharmony_ci                        "Unexpected EOF inside varint.");
318ffe3c632Sopenharmony_ci                }
319ffe3c632Sopenharmony_ci                break;
320ffe3c632Sopenharmony_ci            case GPBWireType::FIXED64:
321ffe3c632Sopenharmony_ci                $uint64 = 0;
322ffe3c632Sopenharmony_ci                if (!$input->readLittleEndian64($uint64)) {
323ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
324ffe3c632Sopenharmony_ci                        "Unexpected EOF inside fixed64.");
325ffe3c632Sopenharmony_ci                }
326ffe3c632Sopenharmony_ci                break;
327ffe3c632Sopenharmony_ci            case GPBWireType::FIXED32:
328ffe3c632Sopenharmony_ci                $uint32 = 0;
329ffe3c632Sopenharmony_ci                if (!$input->readLittleEndian32($uint32)) {
330ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
331ffe3c632Sopenharmony_ci                        "Unexpected EOF inside fixed32.");
332ffe3c632Sopenharmony_ci                }
333ffe3c632Sopenharmony_ci                break;
334ffe3c632Sopenharmony_ci            case GPBWireType::LENGTH_DELIMITED:
335ffe3c632Sopenharmony_ci                $length = 0;
336ffe3c632Sopenharmony_ci                if (!$input->readVarint32($length)) {
337ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
338ffe3c632Sopenharmony_ci                        "Unexpected EOF inside length.");
339ffe3c632Sopenharmony_ci                }
340ffe3c632Sopenharmony_ci                $data = NULL;
341ffe3c632Sopenharmony_ci                if (!$input->readRaw($length, $data)) {
342ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
343ffe3c632Sopenharmony_ci                        "Unexpected EOF inside length delimited data.");
344ffe3c632Sopenharmony_ci                }
345ffe3c632Sopenharmony_ci                break;
346ffe3c632Sopenharmony_ci            case GPBWireType::START_GROUP:
347ffe3c632Sopenharmony_ci            case GPBWireType::END_GROUP:
348ffe3c632Sopenharmony_ci                throw new GPBDecodeException("Unexpected wire type.");
349ffe3c632Sopenharmony_ci            default:
350ffe3c632Sopenharmony_ci                throw new GPBDecodeException("Unexpected wire type.");
351ffe3c632Sopenharmony_ci        }
352ffe3c632Sopenharmony_ci        $end = $input->current();
353ffe3c632Sopenharmony_ci
354ffe3c632Sopenharmony_ci        $bytes = str_repeat(chr(0), CodedOutputStream::MAX_VARINT64_BYTES);
355ffe3c632Sopenharmony_ci        $size = CodedOutputStream::writeVarintToArray($tag, $bytes, true);
356ffe3c632Sopenharmony_ci        $this->unknown .= substr($bytes, 0, $size) . $input->substr($start, $end);
357ffe3c632Sopenharmony_ci    }
358ffe3c632Sopenharmony_ci
359ffe3c632Sopenharmony_ci    /**
360ffe3c632Sopenharmony_ci     * @ignore
361ffe3c632Sopenharmony_ci     */
362ffe3c632Sopenharmony_ci    private static function parseFieldFromStreamNoTag($input, $field, &$value)
363ffe3c632Sopenharmony_ci    {
364ffe3c632Sopenharmony_ci        switch ($field->getType()) {
365ffe3c632Sopenharmony_ci            case GPBType::DOUBLE:
366ffe3c632Sopenharmony_ci                if (!GPBWire::readDouble($input, $value)) {
367ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
368ffe3c632Sopenharmony_ci                        "Unexpected EOF inside double field.");
369ffe3c632Sopenharmony_ci                }
370ffe3c632Sopenharmony_ci                break;
371ffe3c632Sopenharmony_ci            case GPBType::FLOAT:
372ffe3c632Sopenharmony_ci                if (!GPBWire::readFloat($input, $value)) {
373ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
374ffe3c632Sopenharmony_ci                        "Unexpected EOF inside float field.");
375ffe3c632Sopenharmony_ci                }
376ffe3c632Sopenharmony_ci                break;
377ffe3c632Sopenharmony_ci            case GPBType::INT64:
378ffe3c632Sopenharmony_ci                if (!GPBWire::readInt64($input, $value)) {
379ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
380ffe3c632Sopenharmony_ci                        "Unexpected EOF inside int64 field.");
381ffe3c632Sopenharmony_ci                }
382ffe3c632Sopenharmony_ci                break;
383ffe3c632Sopenharmony_ci            case GPBType::UINT64:
384ffe3c632Sopenharmony_ci                if (!GPBWire::readUint64($input, $value)) {
385ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
386ffe3c632Sopenharmony_ci                        "Unexpected EOF inside uint64 field.");
387ffe3c632Sopenharmony_ci                }
388ffe3c632Sopenharmony_ci                break;
389ffe3c632Sopenharmony_ci            case GPBType::INT32:
390ffe3c632Sopenharmony_ci                if (!GPBWire::readInt32($input, $value)) {
391ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
392ffe3c632Sopenharmony_ci                        "Unexpected EOF inside int32 field.");
393ffe3c632Sopenharmony_ci                }
394ffe3c632Sopenharmony_ci                break;
395ffe3c632Sopenharmony_ci            case GPBType::FIXED64:
396ffe3c632Sopenharmony_ci                if (!GPBWire::readFixed64($input, $value)) {
397ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
398ffe3c632Sopenharmony_ci                        "Unexpected EOF inside fixed64 field.");
399ffe3c632Sopenharmony_ci                }
400ffe3c632Sopenharmony_ci                break;
401ffe3c632Sopenharmony_ci            case GPBType::FIXED32:
402ffe3c632Sopenharmony_ci                if (!GPBWire::readFixed32($input, $value)) {
403ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
404ffe3c632Sopenharmony_ci                        "Unexpected EOF inside fixed32 field.");
405ffe3c632Sopenharmony_ci                }
406ffe3c632Sopenharmony_ci                break;
407ffe3c632Sopenharmony_ci            case GPBType::BOOL:
408ffe3c632Sopenharmony_ci                if (!GPBWire::readBool($input, $value)) {
409ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
410ffe3c632Sopenharmony_ci                        "Unexpected EOF inside bool field.");
411ffe3c632Sopenharmony_ci                }
412ffe3c632Sopenharmony_ci                break;
413ffe3c632Sopenharmony_ci            case GPBType::STRING:
414ffe3c632Sopenharmony_ci                // TODO(teboring): Add utf-8 check.
415ffe3c632Sopenharmony_ci                if (!GPBWire::readString($input, $value)) {
416ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
417ffe3c632Sopenharmony_ci                        "Unexpected EOF inside string field.");
418ffe3c632Sopenharmony_ci                }
419ffe3c632Sopenharmony_ci                break;
420ffe3c632Sopenharmony_ci            case GPBType::GROUP:
421ffe3c632Sopenharmony_ci                trigger_error("Not implemented.", E_ERROR);
422ffe3c632Sopenharmony_ci                break;
423ffe3c632Sopenharmony_ci            case GPBType::MESSAGE:
424ffe3c632Sopenharmony_ci                if ($field->isMap()) {
425ffe3c632Sopenharmony_ci                    $value = new MapEntry($field->getMessageType());
426ffe3c632Sopenharmony_ci                } else {
427ffe3c632Sopenharmony_ci                    $klass = $field->getMessageType()->getClass();
428ffe3c632Sopenharmony_ci                    $value = new $klass;
429ffe3c632Sopenharmony_ci                }
430ffe3c632Sopenharmony_ci                if (!GPBWire::readMessage($input, $value)) {
431ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
432ffe3c632Sopenharmony_ci                        "Unexpected EOF inside message.");
433ffe3c632Sopenharmony_ci                }
434ffe3c632Sopenharmony_ci                break;
435ffe3c632Sopenharmony_ci            case GPBType::BYTES:
436ffe3c632Sopenharmony_ci                if (!GPBWire::readString($input, $value)) {
437ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
438ffe3c632Sopenharmony_ci                        "Unexpected EOF inside bytes field.");
439ffe3c632Sopenharmony_ci                }
440ffe3c632Sopenharmony_ci                break;
441ffe3c632Sopenharmony_ci            case GPBType::UINT32:
442ffe3c632Sopenharmony_ci                if (!GPBWire::readUint32($input, $value)) {
443ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
444ffe3c632Sopenharmony_ci                        "Unexpected EOF inside uint32 field.");
445ffe3c632Sopenharmony_ci                }
446ffe3c632Sopenharmony_ci                break;
447ffe3c632Sopenharmony_ci            case GPBType::ENUM:
448ffe3c632Sopenharmony_ci                // TODO(teboring): Check unknown enum value.
449ffe3c632Sopenharmony_ci                if (!GPBWire::readInt32($input, $value)) {
450ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
451ffe3c632Sopenharmony_ci                        "Unexpected EOF inside enum field.");
452ffe3c632Sopenharmony_ci                }
453ffe3c632Sopenharmony_ci                break;
454ffe3c632Sopenharmony_ci            case GPBType::SFIXED32:
455ffe3c632Sopenharmony_ci                if (!GPBWire::readSfixed32($input, $value)) {
456ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
457ffe3c632Sopenharmony_ci                        "Unexpected EOF inside sfixed32 field.");
458ffe3c632Sopenharmony_ci                }
459ffe3c632Sopenharmony_ci                break;
460ffe3c632Sopenharmony_ci            case GPBType::SFIXED64:
461ffe3c632Sopenharmony_ci                if (!GPBWire::readSfixed64($input, $value)) {
462ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
463ffe3c632Sopenharmony_ci                        "Unexpected EOF inside sfixed64 field.");
464ffe3c632Sopenharmony_ci                }
465ffe3c632Sopenharmony_ci                break;
466ffe3c632Sopenharmony_ci            case GPBType::SINT32:
467ffe3c632Sopenharmony_ci                if (!GPBWire::readSint32($input, $value)) {
468ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
469ffe3c632Sopenharmony_ci                        "Unexpected EOF inside sint32 field.");
470ffe3c632Sopenharmony_ci                }
471ffe3c632Sopenharmony_ci                break;
472ffe3c632Sopenharmony_ci            case GPBType::SINT64:
473ffe3c632Sopenharmony_ci                if (!GPBWire::readSint64($input, $value)) {
474ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
475ffe3c632Sopenharmony_ci                        "Unexpected EOF inside sint64 field.");
476ffe3c632Sopenharmony_ci                }
477ffe3c632Sopenharmony_ci                break;
478ffe3c632Sopenharmony_ci            default:
479ffe3c632Sopenharmony_ci                user_error("Unsupported type.");
480ffe3c632Sopenharmony_ci                return false;
481ffe3c632Sopenharmony_ci        }
482ffe3c632Sopenharmony_ci        return true;
483ffe3c632Sopenharmony_ci    }
484ffe3c632Sopenharmony_ci
485ffe3c632Sopenharmony_ci    /**
486ffe3c632Sopenharmony_ci     * @ignore
487ffe3c632Sopenharmony_ci     */
488ffe3c632Sopenharmony_ci    private function parseFieldFromStream($tag, $input, $field)
489ffe3c632Sopenharmony_ci    {
490ffe3c632Sopenharmony_ci        $value = null;
491ffe3c632Sopenharmony_ci
492ffe3c632Sopenharmony_ci        if (is_null($field)) {
493ffe3c632Sopenharmony_ci            $value_format = GPBWire::UNKNOWN;
494ffe3c632Sopenharmony_ci        } elseif (GPBWire::getTagWireType($tag) ===
495ffe3c632Sopenharmony_ci            GPBWire::getWireType($field->getType())) {
496ffe3c632Sopenharmony_ci            $value_format = GPBWire::NORMAL_FORMAT;
497ffe3c632Sopenharmony_ci        } elseif ($field->isPackable() &&
498ffe3c632Sopenharmony_ci            GPBWire::getTagWireType($tag) ===
499ffe3c632Sopenharmony_ci            GPBWire::WIRETYPE_LENGTH_DELIMITED) {
500ffe3c632Sopenharmony_ci            $value_format = GPBWire::PACKED_FORMAT;
501ffe3c632Sopenharmony_ci        } else {
502ffe3c632Sopenharmony_ci            // the wire type doesn't match. Put it in our unknown field set.
503ffe3c632Sopenharmony_ci            $value_format = GPBWire::UNKNOWN;
504ffe3c632Sopenharmony_ci        }
505ffe3c632Sopenharmony_ci
506ffe3c632Sopenharmony_ci        if ($value_format === GPBWire::UNKNOWN) {
507ffe3c632Sopenharmony_ci            $this->skipField($input, $tag);
508ffe3c632Sopenharmony_ci            return;
509ffe3c632Sopenharmony_ci        } elseif ($value_format === GPBWire::NORMAL_FORMAT) {
510ffe3c632Sopenharmony_ci            self::parseFieldFromStreamNoTag($input, $field, $value);
511ffe3c632Sopenharmony_ci        } elseif ($value_format === GPBWire::PACKED_FORMAT) {
512ffe3c632Sopenharmony_ci            $length = 0;
513ffe3c632Sopenharmony_ci            if (!GPBWire::readInt32($input, $length)) {
514ffe3c632Sopenharmony_ci                throw new GPBDecodeException(
515ffe3c632Sopenharmony_ci                    "Unexpected EOF inside packed length.");
516ffe3c632Sopenharmony_ci            }
517ffe3c632Sopenharmony_ci            $limit = $input->pushLimit($length);
518ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
519ffe3c632Sopenharmony_ci            while ($input->bytesUntilLimit() > 0) {
520ffe3c632Sopenharmony_ci                self::parseFieldFromStreamNoTag($input, $field, $value);
521ffe3c632Sopenharmony_ci                $this->appendHelper($field, $value);
522ffe3c632Sopenharmony_ci            }
523ffe3c632Sopenharmony_ci            $input->popLimit($limit);
524ffe3c632Sopenharmony_ci            return;
525ffe3c632Sopenharmony_ci        } else {
526ffe3c632Sopenharmony_ci            return;
527ffe3c632Sopenharmony_ci        }
528ffe3c632Sopenharmony_ci
529ffe3c632Sopenharmony_ci        if ($field->isMap()) {
530ffe3c632Sopenharmony_ci            $this->kvUpdateHelper($field, $value->getKey(), $value->getValue());
531ffe3c632Sopenharmony_ci        } else if ($field->isRepeated()) {
532ffe3c632Sopenharmony_ci            $this->appendHelper($field, $value);
533ffe3c632Sopenharmony_ci        } else {
534ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
535ffe3c632Sopenharmony_ci            $this->$setter($value);
536ffe3c632Sopenharmony_ci        }
537ffe3c632Sopenharmony_ci    }
538ffe3c632Sopenharmony_ci
539ffe3c632Sopenharmony_ci    /**
540ffe3c632Sopenharmony_ci     * Clear all containing fields.
541ffe3c632Sopenharmony_ci     * @return null.
542ffe3c632Sopenharmony_ci     */
543ffe3c632Sopenharmony_ci    public function clear()
544ffe3c632Sopenharmony_ci    {
545ffe3c632Sopenharmony_ci        $this->unknown = "";
546ffe3c632Sopenharmony_ci        foreach ($this->desc->getField() as $field) {
547ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
548ffe3c632Sopenharmony_ci            if ($field->isMap()) {
549ffe3c632Sopenharmony_ci                $message_type = $field->getMessageType();
550ffe3c632Sopenharmony_ci                $key_field = $message_type->getFieldByNumber(1);
551ffe3c632Sopenharmony_ci                $value_field = $message_type->getFieldByNumber(2);
552ffe3c632Sopenharmony_ci                switch ($value_field->getType()) {
553ffe3c632Sopenharmony_ci                    case GPBType::MESSAGE:
554ffe3c632Sopenharmony_ci                    case GPBType::GROUP:
555ffe3c632Sopenharmony_ci                        $map_field = new MapField(
556ffe3c632Sopenharmony_ci                            $key_field->getType(),
557ffe3c632Sopenharmony_ci                            $value_field->getType(),
558ffe3c632Sopenharmony_ci                            $value_field->getMessageType()->getClass());
559ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
560ffe3c632Sopenharmony_ci                        break;
561ffe3c632Sopenharmony_ci                    case GPBType::ENUM:
562ffe3c632Sopenharmony_ci                        $map_field = new MapField(
563ffe3c632Sopenharmony_ci                            $key_field->getType(),
564ffe3c632Sopenharmony_ci                            $value_field->getType(),
565ffe3c632Sopenharmony_ci                            $value_field->getEnumType()->getClass());
566ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
567ffe3c632Sopenharmony_ci                        break;
568ffe3c632Sopenharmony_ci                    default:
569ffe3c632Sopenharmony_ci                        $map_field = new MapField(
570ffe3c632Sopenharmony_ci                            $key_field->getType(),
571ffe3c632Sopenharmony_ci                            $value_field->getType());
572ffe3c632Sopenharmony_ci                        $this->$setter($map_field);
573ffe3c632Sopenharmony_ci                        break;
574ffe3c632Sopenharmony_ci                }
575ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::REPEATED) {
576ffe3c632Sopenharmony_ci                switch ($field->getType()) {
577ffe3c632Sopenharmony_ci                    case GPBType::MESSAGE:
578ffe3c632Sopenharmony_ci                    case GPBType::GROUP:
579ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField(
580ffe3c632Sopenharmony_ci                            $field->getType(),
581ffe3c632Sopenharmony_ci                            $field->getMessageType()->getClass());
582ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
583ffe3c632Sopenharmony_ci                        break;
584ffe3c632Sopenharmony_ci                    case GPBType::ENUM:
585ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField(
586ffe3c632Sopenharmony_ci                            $field->getType(),
587ffe3c632Sopenharmony_ci                            $field->getEnumType()->getClass());
588ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
589ffe3c632Sopenharmony_ci                        break;
590ffe3c632Sopenharmony_ci                    default:
591ffe3c632Sopenharmony_ci                        $repeated_field = new RepeatedField($field->getType());
592ffe3c632Sopenharmony_ci                        $this->$setter($repeated_field);
593ffe3c632Sopenharmony_ci                        break;
594ffe3c632Sopenharmony_ci                }
595ffe3c632Sopenharmony_ci            } else if ($field->getOneofIndex() !== -1) {
596ffe3c632Sopenharmony_ci                $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
597ffe3c632Sopenharmony_ci                $oneof_name = $oneof->getName();
598ffe3c632Sopenharmony_ci                $this->$oneof_name = new OneofField($oneof);
599ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::OPTIONAL) {
600ffe3c632Sopenharmony_ci                switch ($field->getType()) {
601ffe3c632Sopenharmony_ci                    case GPBType::DOUBLE   :
602ffe3c632Sopenharmony_ci                    case GPBType::FLOAT    :
603ffe3c632Sopenharmony_ci                        $this->$setter(0.0);
604ffe3c632Sopenharmony_ci                        break;
605ffe3c632Sopenharmony_ci                    case GPBType::INT32    :
606ffe3c632Sopenharmony_ci                    case GPBType::FIXED32  :
607ffe3c632Sopenharmony_ci                    case GPBType::UINT32   :
608ffe3c632Sopenharmony_ci                    case GPBType::SFIXED32 :
609ffe3c632Sopenharmony_ci                    case GPBType::SINT32   :
610ffe3c632Sopenharmony_ci                    case GPBType::ENUM     :
611ffe3c632Sopenharmony_ci                        $this->$setter(0);
612ffe3c632Sopenharmony_ci                        break;
613ffe3c632Sopenharmony_ci                    case GPBType::BOOL     :
614ffe3c632Sopenharmony_ci                        $this->$setter(false);
615ffe3c632Sopenharmony_ci                        break;
616ffe3c632Sopenharmony_ci                    case GPBType::STRING   :
617ffe3c632Sopenharmony_ci                    case GPBType::BYTES    :
618ffe3c632Sopenharmony_ci                        $this->$setter("");
619ffe3c632Sopenharmony_ci                        break;
620ffe3c632Sopenharmony_ci                    case GPBType::GROUP    :
621ffe3c632Sopenharmony_ci                    case GPBType::MESSAGE  :
622ffe3c632Sopenharmony_ci                        $null = null;
623ffe3c632Sopenharmony_ci                        $this->$setter($null);
624ffe3c632Sopenharmony_ci                        break;
625ffe3c632Sopenharmony_ci                }
626ffe3c632Sopenharmony_ci                if (PHP_INT_SIZE == 4) {
627ffe3c632Sopenharmony_ci                    switch ($field->getType()) {
628ffe3c632Sopenharmony_ci                        case GPBType::INT64:
629ffe3c632Sopenharmony_ci                        case GPBType::UINT64:
630ffe3c632Sopenharmony_ci                        case GPBType::FIXED64:
631ffe3c632Sopenharmony_ci                        case GPBType::SFIXED64:
632ffe3c632Sopenharmony_ci                        case GPBType::SINT64:
633ffe3c632Sopenharmony_ci                            $this->$setter("0");
634ffe3c632Sopenharmony_ci                    }
635ffe3c632Sopenharmony_ci                } else {
636ffe3c632Sopenharmony_ci                    switch ($field->getType()) {
637ffe3c632Sopenharmony_ci                        case GPBType::INT64:
638ffe3c632Sopenharmony_ci                        case GPBType::UINT64:
639ffe3c632Sopenharmony_ci                        case GPBType::FIXED64:
640ffe3c632Sopenharmony_ci                        case GPBType::SFIXED64:
641ffe3c632Sopenharmony_ci                        case GPBType::SINT64:
642ffe3c632Sopenharmony_ci                            $this->$setter(0);
643ffe3c632Sopenharmony_ci                    }
644ffe3c632Sopenharmony_ci                }
645ffe3c632Sopenharmony_ci            }
646ffe3c632Sopenharmony_ci        }
647ffe3c632Sopenharmony_ci    }
648ffe3c632Sopenharmony_ci
649ffe3c632Sopenharmony_ci    /**
650ffe3c632Sopenharmony_ci     * Clear all unknown fields previously parsed.
651ffe3c632Sopenharmony_ci     * @return null.
652ffe3c632Sopenharmony_ci     */
653ffe3c632Sopenharmony_ci    public function discardUnknownFields()
654ffe3c632Sopenharmony_ci    {
655ffe3c632Sopenharmony_ci        $this->unknown = "";
656ffe3c632Sopenharmony_ci        foreach ($this->desc->getField() as $field) {
657ffe3c632Sopenharmony_ci            if ($field->getType() != GPBType::MESSAGE) {
658ffe3c632Sopenharmony_ci                continue;
659ffe3c632Sopenharmony_ci            }
660ffe3c632Sopenharmony_ci            if ($field->isMap()) {
661ffe3c632Sopenharmony_ci                $value_field = $field->getMessageType()->getFieldByNumber(2);
662ffe3c632Sopenharmony_ci                if ($value_field->getType() != GPBType::MESSAGE) {
663ffe3c632Sopenharmony_ci                    continue;
664ffe3c632Sopenharmony_ci                }
665ffe3c632Sopenharmony_ci                $getter = $field->getGetter();
666ffe3c632Sopenharmony_ci                $map = $this->$getter();
667ffe3c632Sopenharmony_ci                foreach ($map as $key => $value) {
668ffe3c632Sopenharmony_ci                    $value->discardUnknownFields();
669ffe3c632Sopenharmony_ci                }
670ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::REPEATED) {
671ffe3c632Sopenharmony_ci                $getter = $field->getGetter();
672ffe3c632Sopenharmony_ci                $arr = $this->$getter();
673ffe3c632Sopenharmony_ci                foreach ($arr as $sub) {
674ffe3c632Sopenharmony_ci                    $sub->discardUnknownFields();
675ffe3c632Sopenharmony_ci                }
676ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::OPTIONAL) {
677ffe3c632Sopenharmony_ci                $getter = $field->getGetter();
678ffe3c632Sopenharmony_ci                $sub = $this->$getter();
679ffe3c632Sopenharmony_ci                if (!is_null($sub)) {
680ffe3c632Sopenharmony_ci                    $sub->discardUnknownFields();
681ffe3c632Sopenharmony_ci                }
682ffe3c632Sopenharmony_ci            }
683ffe3c632Sopenharmony_ci        }
684ffe3c632Sopenharmony_ci    }
685ffe3c632Sopenharmony_ci
686ffe3c632Sopenharmony_ci    /**
687ffe3c632Sopenharmony_ci     * Merges the contents of the specified message into current message.
688ffe3c632Sopenharmony_ci     *
689ffe3c632Sopenharmony_ci     * This method merges the contents of the specified message into the
690ffe3c632Sopenharmony_ci     * current message. Singular fields that are set in the specified message
691ffe3c632Sopenharmony_ci     * overwrite the corresponding fields in the current message.  Repeated
692ffe3c632Sopenharmony_ci     * fields are appended. Map fields key-value pairs are overwritten.
693ffe3c632Sopenharmony_ci     * Singular/Oneof sub-messages are recursively merged. All overwritten
694ffe3c632Sopenharmony_ci     * sub-messages are deep-copied.
695ffe3c632Sopenharmony_ci     *
696ffe3c632Sopenharmony_ci     * @param object $msg Protobuf message to be merged from.
697ffe3c632Sopenharmony_ci     * @return null.
698ffe3c632Sopenharmony_ci     */
699ffe3c632Sopenharmony_ci    public function mergeFrom($msg)
700ffe3c632Sopenharmony_ci    {
701ffe3c632Sopenharmony_ci        if (get_class($this) !== get_class($msg)) {
702ffe3c632Sopenharmony_ci            user_error("Cannot merge messages with different class.");
703ffe3c632Sopenharmony_ci            return;
704ffe3c632Sopenharmony_ci        }
705ffe3c632Sopenharmony_ci
706ffe3c632Sopenharmony_ci        foreach ($this->desc->getField() as $field) {
707ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
708ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
709ffe3c632Sopenharmony_ci            if ($field->isMap()) {
710ffe3c632Sopenharmony_ci                if (count($msg->$getter()) != 0) {
711ffe3c632Sopenharmony_ci                    $value_field = $field->getMessageType()->getFieldByNumber(2);
712ffe3c632Sopenharmony_ci                    foreach ($msg->$getter() as $key => $value) {
713ffe3c632Sopenharmony_ci                        if ($value_field->getType() == GPBType::MESSAGE) {
714ffe3c632Sopenharmony_ci                            $klass = $value_field->getMessageType()->getClass();
715ffe3c632Sopenharmony_ci                            $copy = new $klass;
716ffe3c632Sopenharmony_ci                            $copy->mergeFrom($value);
717ffe3c632Sopenharmony_ci
718ffe3c632Sopenharmony_ci                            $this->kvUpdateHelper($field, $key, $copy);
719ffe3c632Sopenharmony_ci                        } else {
720ffe3c632Sopenharmony_ci                            $this->kvUpdateHelper($field, $key, $value);
721ffe3c632Sopenharmony_ci                        }
722ffe3c632Sopenharmony_ci                    }
723ffe3c632Sopenharmony_ci                }
724ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::REPEATED) {
725ffe3c632Sopenharmony_ci                if (count($msg->$getter()) != 0) {
726ffe3c632Sopenharmony_ci                    foreach ($msg->$getter() as $tmp) {
727ffe3c632Sopenharmony_ci                        if ($field->getType() == GPBType::MESSAGE) {
728ffe3c632Sopenharmony_ci                            $klass = $field->getMessageType()->getClass();
729ffe3c632Sopenharmony_ci                            $copy = new $klass;
730ffe3c632Sopenharmony_ci                            $copy->mergeFrom($tmp);
731ffe3c632Sopenharmony_ci                            $this->appendHelper($field, $copy);
732ffe3c632Sopenharmony_ci                        } else {
733ffe3c632Sopenharmony_ci                            $this->appendHelper($field, $tmp);
734ffe3c632Sopenharmony_ci                        }
735ffe3c632Sopenharmony_ci                    }
736ffe3c632Sopenharmony_ci                }
737ffe3c632Sopenharmony_ci            } else if ($field->getLabel() === GPBLabel::OPTIONAL) {
738ffe3c632Sopenharmony_ci                if($msg->$getter() !== $this->defaultValue($field)) {
739ffe3c632Sopenharmony_ci                    $tmp = $msg->$getter();
740ffe3c632Sopenharmony_ci                    if ($field->getType() == GPBType::MESSAGE) {
741ffe3c632Sopenharmony_ci                        if (is_null($this->$getter())) {
742ffe3c632Sopenharmony_ci                            $klass = $field->getMessageType()->getClass();
743ffe3c632Sopenharmony_ci                            $new_msg = new $klass;
744ffe3c632Sopenharmony_ci                            $this->$setter($new_msg);
745ffe3c632Sopenharmony_ci                        }
746ffe3c632Sopenharmony_ci                        $this->$getter()->mergeFrom($tmp);
747ffe3c632Sopenharmony_ci                    } else {
748ffe3c632Sopenharmony_ci                        $this->$setter($tmp);
749ffe3c632Sopenharmony_ci                    }
750ffe3c632Sopenharmony_ci                }
751ffe3c632Sopenharmony_ci            }
752ffe3c632Sopenharmony_ci        }
753ffe3c632Sopenharmony_ci    }
754ffe3c632Sopenharmony_ci
755ffe3c632Sopenharmony_ci    /**
756ffe3c632Sopenharmony_ci     * Parses a protocol buffer contained in a string.
757ffe3c632Sopenharmony_ci     *
758ffe3c632Sopenharmony_ci     * This function takes a string in the (non-human-readable) binary wire
759ffe3c632Sopenharmony_ci     * format, matching the encoding output by serializeToString().
760ffe3c632Sopenharmony_ci     * See mergeFrom() for merging behavior, if the field is already set in the
761ffe3c632Sopenharmony_ci     * specified message.
762ffe3c632Sopenharmony_ci     *
763ffe3c632Sopenharmony_ci     * @param string $data Binary protobuf data.
764ffe3c632Sopenharmony_ci     * @return null.
765ffe3c632Sopenharmony_ci     * @throws \Exception Invalid data.
766ffe3c632Sopenharmony_ci     */
767ffe3c632Sopenharmony_ci    public function mergeFromString($data)
768ffe3c632Sopenharmony_ci    {
769ffe3c632Sopenharmony_ci        $input = new CodedInputStream($data);
770ffe3c632Sopenharmony_ci        $this->parseFromStream($input);
771ffe3c632Sopenharmony_ci    }
772ffe3c632Sopenharmony_ci
773ffe3c632Sopenharmony_ci    /**
774ffe3c632Sopenharmony_ci     * Parses a json string to protobuf message.
775ffe3c632Sopenharmony_ci     *
776ffe3c632Sopenharmony_ci     * This function takes a string in the json wire format, matching the
777ffe3c632Sopenharmony_ci     * encoding output by serializeToJsonString().
778ffe3c632Sopenharmony_ci     * See mergeFrom() for merging behavior, if the field is already set in the
779ffe3c632Sopenharmony_ci     * specified message.
780ffe3c632Sopenharmony_ci     *
781ffe3c632Sopenharmony_ci     * @param string $data Json protobuf data.
782ffe3c632Sopenharmony_ci     * @return null.
783ffe3c632Sopenharmony_ci     * @throws \Exception Invalid data.
784ffe3c632Sopenharmony_ci     */
785ffe3c632Sopenharmony_ci    public function mergeFromJsonString($data, $ignore_unknown = false)
786ffe3c632Sopenharmony_ci    {
787ffe3c632Sopenharmony_ci        $input = new RawInputStream($data);
788ffe3c632Sopenharmony_ci        $this->parseFromJsonStream($input, $ignore_unknown);
789ffe3c632Sopenharmony_ci    }
790ffe3c632Sopenharmony_ci
791ffe3c632Sopenharmony_ci    /**
792ffe3c632Sopenharmony_ci     * @ignore
793ffe3c632Sopenharmony_ci     */
794ffe3c632Sopenharmony_ci    public function parseFromStream($input)
795ffe3c632Sopenharmony_ci    {
796ffe3c632Sopenharmony_ci        while (true) {
797ffe3c632Sopenharmony_ci            $tag = $input->readTag();
798ffe3c632Sopenharmony_ci            // End of input.  This is a valid place to end, so return true.
799ffe3c632Sopenharmony_ci            if ($tag === 0) {
800ffe3c632Sopenharmony_ci                return true;
801ffe3c632Sopenharmony_ci            }
802ffe3c632Sopenharmony_ci
803ffe3c632Sopenharmony_ci            $number = GPBWire::getTagFieldNumber($tag);
804ffe3c632Sopenharmony_ci            $field = $this->desc->getFieldByNumber($number);
805ffe3c632Sopenharmony_ci
806ffe3c632Sopenharmony_ci            $this->parseFieldFromStream($tag, $input, $field);
807ffe3c632Sopenharmony_ci        }
808ffe3c632Sopenharmony_ci    }
809ffe3c632Sopenharmony_ci
810ffe3c632Sopenharmony_ci    private function convertJsonValueToProtoValue(
811ffe3c632Sopenharmony_ci        $value,
812ffe3c632Sopenharmony_ci        $field,
813ffe3c632Sopenharmony_ci        $ignore_unknown,
814ffe3c632Sopenharmony_ci        $is_map_key = false)
815ffe3c632Sopenharmony_ci    {
816ffe3c632Sopenharmony_ci        switch ($field->getType()) {
817ffe3c632Sopenharmony_ci            case GPBType::MESSAGE:
818ffe3c632Sopenharmony_ci                $klass = $field->getMessageType()->getClass();
819ffe3c632Sopenharmony_ci                $submsg = new $klass;
820ffe3c632Sopenharmony_ci
821ffe3c632Sopenharmony_ci                if (is_a($submsg, "Google\Protobuf\Duration")) {
822ffe3c632Sopenharmony_ci                    if (is_null($value)) {
823ffe3c632Sopenharmony_ci                        return $this->defaultValue($field);
824ffe3c632Sopenharmony_ci                    } else if (!is_string($value)) {
825ffe3c632Sopenharmony_ci                        throw new GPBDecodeException("Expect string.");
826ffe3c632Sopenharmony_ci                    }
827ffe3c632Sopenharmony_ci                    return GPBUtil::parseDuration($value);
828ffe3c632Sopenharmony_ci                } else if ($field->isTimestamp()) {
829ffe3c632Sopenharmony_ci                    if (is_null($value)) {
830ffe3c632Sopenharmony_ci                        return $this->defaultValue($field);
831ffe3c632Sopenharmony_ci                    } else if (!is_string($value)) {
832ffe3c632Sopenharmony_ci                        throw new GPBDecodeException("Expect string.");
833ffe3c632Sopenharmony_ci                    }
834ffe3c632Sopenharmony_ci                    try {
835ffe3c632Sopenharmony_ci                        $timestamp = GPBUtil::parseTimestamp($value);
836ffe3c632Sopenharmony_ci                    } catch (\Exception $e) {
837ffe3c632Sopenharmony_ci                        throw new GPBDecodeException(
838ffe3c632Sopenharmony_ci                            "Invalid RFC 3339 timestamp: ".$e->getMessage());
839ffe3c632Sopenharmony_ci                    }
840ffe3c632Sopenharmony_ci
841ffe3c632Sopenharmony_ci                    $submsg->setSeconds($timestamp->getSeconds());
842ffe3c632Sopenharmony_ci                    $submsg->setNanos($timestamp->getNanos());
843ffe3c632Sopenharmony_ci                } else if (is_a($submsg, "Google\Protobuf\FieldMask")) {
844ffe3c632Sopenharmony_ci                    if (is_null($value)) {
845ffe3c632Sopenharmony_ci                        return $this->defaultValue($field);
846ffe3c632Sopenharmony_ci                    }
847ffe3c632Sopenharmony_ci                    try {
848ffe3c632Sopenharmony_ci                        return GPBUtil::parseFieldMask($value);
849ffe3c632Sopenharmony_ci                    } catch (\Exception $e) {
850ffe3c632Sopenharmony_ci                        throw new GPBDecodeException(
851ffe3c632Sopenharmony_ci                            "Invalid FieldMask: ".$e->getMessage());
852ffe3c632Sopenharmony_ci                    }
853ffe3c632Sopenharmony_ci                } else {
854ffe3c632Sopenharmony_ci                    if (is_null($value) &&
855ffe3c632Sopenharmony_ci                        !is_a($submsg, "Google\Protobuf\Value")) {
856ffe3c632Sopenharmony_ci                        return $this->defaultValue($field);
857ffe3c632Sopenharmony_ci                    }
858ffe3c632Sopenharmony_ci                    if (GPBUtil::hasSpecialJsonMapping($submsg)) {
859ffe3c632Sopenharmony_ci                    } elseif (!is_object($value) && !is_array($value)) {
860ffe3c632Sopenharmony_ci                        throw new GPBDecodeException("Expect message.");
861ffe3c632Sopenharmony_ci                    }
862ffe3c632Sopenharmony_ci                    $submsg->mergeFromJsonArray($value, $ignore_unknown);
863ffe3c632Sopenharmony_ci                }
864ffe3c632Sopenharmony_ci                return $submsg;
865ffe3c632Sopenharmony_ci            case GPBType::ENUM:
866ffe3c632Sopenharmony_ci                if (is_null($value)) {
867ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
868ffe3c632Sopenharmony_ci                }
869ffe3c632Sopenharmony_ci                if (is_integer($value)) {
870ffe3c632Sopenharmony_ci                    return $value;
871ffe3c632Sopenharmony_ci                }
872ffe3c632Sopenharmony_ci                $enum_value = $field->getEnumType()->getValueByName($value);
873ffe3c632Sopenharmony_ci                if (!is_null($enum_value)) {
874ffe3c632Sopenharmony_ci                    return $enum_value->getNumber();
875ffe3c632Sopenharmony_ci                } else if ($ignore_unknown) {
876ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
877ffe3c632Sopenharmony_ci                } else {
878ffe3c632Sopenharmony_ci                  throw new GPBDecodeException(
879ffe3c632Sopenharmony_ci                          "Enum field only accepts integer or enum value name");
880ffe3c632Sopenharmony_ci                }
881ffe3c632Sopenharmony_ci            case GPBType::STRING:
882ffe3c632Sopenharmony_ci                if (is_null($value)) {
883ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
884ffe3c632Sopenharmony_ci                }
885ffe3c632Sopenharmony_ci                if (is_numeric($value)) {
886ffe3c632Sopenharmony_ci                    return strval($value);
887ffe3c632Sopenharmony_ci                }
888ffe3c632Sopenharmony_ci                if (!is_string($value)) {
889ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
890ffe3c632Sopenharmony_ci                        "String field only accepts string value");
891ffe3c632Sopenharmony_ci                }
892ffe3c632Sopenharmony_ci                return $value;
893ffe3c632Sopenharmony_ci            case GPBType::BYTES:
894ffe3c632Sopenharmony_ci                if (is_null($value)) {
895ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
896ffe3c632Sopenharmony_ci                }
897ffe3c632Sopenharmony_ci                if (!is_string($value)) {
898ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
899ffe3c632Sopenharmony_ci                        "Byte field only accepts string value");
900ffe3c632Sopenharmony_ci                }
901ffe3c632Sopenharmony_ci                $proto_value = base64_decode($value, true);
902ffe3c632Sopenharmony_ci                if ($proto_value === false) {
903ffe3c632Sopenharmony_ci                    throw new GPBDecodeException("Invalid base64 characters");
904ffe3c632Sopenharmony_ci                }
905ffe3c632Sopenharmony_ci                return $proto_value;
906ffe3c632Sopenharmony_ci            case GPBType::BOOL:
907ffe3c632Sopenharmony_ci                if (is_null($value)) {
908ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
909ffe3c632Sopenharmony_ci                }
910ffe3c632Sopenharmony_ci                if ($is_map_key) {
911ffe3c632Sopenharmony_ci                    if ($value === "true") {
912ffe3c632Sopenharmony_ci                        return true;
913ffe3c632Sopenharmony_ci                    }
914ffe3c632Sopenharmony_ci                    if ($value === "false") {
915ffe3c632Sopenharmony_ci                        return false;
916ffe3c632Sopenharmony_ci                    }
917ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
918ffe3c632Sopenharmony_ci                        "Bool field only accepts bool value");
919ffe3c632Sopenharmony_ci                }
920ffe3c632Sopenharmony_ci                if (!is_bool($value)) {
921ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
922ffe3c632Sopenharmony_ci                        "Bool field only accepts bool value");
923ffe3c632Sopenharmony_ci                }
924ffe3c632Sopenharmony_ci                return $value;
925ffe3c632Sopenharmony_ci            case GPBType::FLOAT:
926ffe3c632Sopenharmony_ci            case GPBType::DOUBLE:
927ffe3c632Sopenharmony_ci                if (is_null($value)) {
928ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
929ffe3c632Sopenharmony_ci                }
930ffe3c632Sopenharmony_ci                if ($value === "Infinity") {
931ffe3c632Sopenharmony_ci                    return INF;
932ffe3c632Sopenharmony_ci                }
933ffe3c632Sopenharmony_ci                if ($value === "-Infinity") {
934ffe3c632Sopenharmony_ci                    return -INF;
935ffe3c632Sopenharmony_ci                }
936ffe3c632Sopenharmony_ci                if ($value === "NaN") {
937ffe3c632Sopenharmony_ci                    return NAN;
938ffe3c632Sopenharmony_ci                }
939ffe3c632Sopenharmony_ci                return $value;
940ffe3c632Sopenharmony_ci            case GPBType::INT32:
941ffe3c632Sopenharmony_ci            case GPBType::SINT32:
942ffe3c632Sopenharmony_ci            case GPBType::SFIXED32:
943ffe3c632Sopenharmony_ci                if (is_null($value)) {
944ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
945ffe3c632Sopenharmony_ci                }
946ffe3c632Sopenharmony_ci                if (!is_numeric($value)) {
947ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
948ffe3c632Sopenharmony_ci                       "Invalid data type for int32 field");
949ffe3c632Sopenharmony_ci                }
950ffe3c632Sopenharmony_ci                if (is_string($value) && trim($value) !== $value) {
951ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
952ffe3c632Sopenharmony_ci                       "Invalid data type for int32 field");
953ffe3c632Sopenharmony_ci                }
954ffe3c632Sopenharmony_ci                if (bccomp($value, "2147483647") > 0) {
955ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
956ffe3c632Sopenharmony_ci                       "Int32 too large");
957ffe3c632Sopenharmony_ci                }
958ffe3c632Sopenharmony_ci                if (bccomp($value, "-2147483648") < 0) {
959ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
960ffe3c632Sopenharmony_ci                       "Int32 too small");
961ffe3c632Sopenharmony_ci                }
962ffe3c632Sopenharmony_ci                return $value;
963ffe3c632Sopenharmony_ci            case GPBType::UINT32:
964ffe3c632Sopenharmony_ci            case GPBType::FIXED32:
965ffe3c632Sopenharmony_ci                if (is_null($value)) {
966ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
967ffe3c632Sopenharmony_ci                }
968ffe3c632Sopenharmony_ci                if (!is_numeric($value)) {
969ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
970ffe3c632Sopenharmony_ci                       "Invalid data type for uint32 field");
971ffe3c632Sopenharmony_ci                }
972ffe3c632Sopenharmony_ci                if (is_string($value) && trim($value) !== $value) {
973ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
974ffe3c632Sopenharmony_ci                       "Invalid data type for int32 field");
975ffe3c632Sopenharmony_ci                }
976ffe3c632Sopenharmony_ci                if (bccomp($value, 4294967295) > 0) {
977ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
978ffe3c632Sopenharmony_ci                        "Uint32 too large");
979ffe3c632Sopenharmony_ci                }
980ffe3c632Sopenharmony_ci                return $value;
981ffe3c632Sopenharmony_ci            case GPBType::INT64:
982ffe3c632Sopenharmony_ci            case GPBType::SINT64:
983ffe3c632Sopenharmony_ci            case GPBType::SFIXED64:
984ffe3c632Sopenharmony_ci                if (is_null($value)) {
985ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
986ffe3c632Sopenharmony_ci                }
987ffe3c632Sopenharmony_ci                if (!is_numeric($value)) {
988ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
989ffe3c632Sopenharmony_ci                       "Invalid data type for int64 field");
990ffe3c632Sopenharmony_ci                }
991ffe3c632Sopenharmony_ci                if (is_string($value) && trim($value) !== $value) {
992ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
993ffe3c632Sopenharmony_ci                       "Invalid data type for int64 field");
994ffe3c632Sopenharmony_ci                }
995ffe3c632Sopenharmony_ci                if (bccomp($value, "9223372036854775807") > 0) {
996ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
997ffe3c632Sopenharmony_ci                        "Int64 too large");
998ffe3c632Sopenharmony_ci                }
999ffe3c632Sopenharmony_ci                if (bccomp($value, "-9223372036854775808") < 0) {
1000ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
1001ffe3c632Sopenharmony_ci                        "Int64 too small");
1002ffe3c632Sopenharmony_ci                }
1003ffe3c632Sopenharmony_ci                return $value;
1004ffe3c632Sopenharmony_ci            case GPBType::UINT64:
1005ffe3c632Sopenharmony_ci            case GPBType::FIXED64:
1006ffe3c632Sopenharmony_ci                if (is_null($value)) {
1007ffe3c632Sopenharmony_ci                    return $this->defaultValue($field);
1008ffe3c632Sopenharmony_ci                }
1009ffe3c632Sopenharmony_ci                if (!is_numeric($value)) {
1010ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
1011ffe3c632Sopenharmony_ci                       "Invalid data type for int64 field");
1012ffe3c632Sopenharmony_ci                }
1013ffe3c632Sopenharmony_ci                if (is_string($value) && trim($value) !== $value) {
1014ffe3c632Sopenharmony_ci                   throw new GPBDecodeException(
1015ffe3c632Sopenharmony_ci                       "Invalid data type for int64 field");
1016ffe3c632Sopenharmony_ci                }
1017ffe3c632Sopenharmony_ci                if (bccomp($value, "18446744073709551615") > 0) {
1018ffe3c632Sopenharmony_ci                    throw new GPBDecodeException(
1019ffe3c632Sopenharmony_ci                        "Uint64 too large");
1020ffe3c632Sopenharmony_ci                }
1021ffe3c632Sopenharmony_ci                if (bccomp($value, "9223372036854775807") > 0) {
1022ffe3c632Sopenharmony_ci                    $value = bcsub($value, "18446744073709551616");
1023ffe3c632Sopenharmony_ci                }
1024ffe3c632Sopenharmony_ci                return $value;
1025ffe3c632Sopenharmony_ci            default:
1026ffe3c632Sopenharmony_ci                return $value;
1027ffe3c632Sopenharmony_ci        }
1028ffe3c632Sopenharmony_ci    }
1029ffe3c632Sopenharmony_ci
1030ffe3c632Sopenharmony_ci    /**
1031ffe3c632Sopenharmony_ci     * Populates the message from a user-supplied PHP array. Array keys
1032ffe3c632Sopenharmony_ci     * correspond to Message properties and nested message properties.
1033ffe3c632Sopenharmony_ci     *
1034ffe3c632Sopenharmony_ci     * Example:
1035ffe3c632Sopenharmony_ci     * ```
1036ffe3c632Sopenharmony_ci     * $message->mergeFromArray([
1037ffe3c632Sopenharmony_ci     *     'name' => 'This is a message name',
1038ffe3c632Sopenharmony_ci     *     'interval' => [
1039ffe3c632Sopenharmony_ci     *          'startTime' => time() - 60,
1040ffe3c632Sopenharmony_ci     *          'endTime' => time(),
1041ffe3c632Sopenharmony_ci     *     ]
1042ffe3c632Sopenharmony_ci     * ]);
1043ffe3c632Sopenharmony_ci     * ```
1044ffe3c632Sopenharmony_ci     *
1045ffe3c632Sopenharmony_ci     * This method will trigger an error if it is passed data that cannot
1046ffe3c632Sopenharmony_ci     * be converted to the correct type. For example, a StringValue field
1047ffe3c632Sopenharmony_ci     * must receive data that is either a string or a StringValue object.
1048ffe3c632Sopenharmony_ci     *
1049ffe3c632Sopenharmony_ci     * @param array $array An array containing message properties and values.
1050ffe3c632Sopenharmony_ci     * @return null.
1051ffe3c632Sopenharmony_ci     */
1052ffe3c632Sopenharmony_ci    protected function mergeFromArray(array $array)
1053ffe3c632Sopenharmony_ci    {
1054ffe3c632Sopenharmony_ci        // Just call the setters for the field names
1055ffe3c632Sopenharmony_ci        foreach ($array as $key => $value) {
1056ffe3c632Sopenharmony_ci            $field = $this->desc->getFieldByName($key);
1057ffe3c632Sopenharmony_ci            if (is_null($field)) {
1058ffe3c632Sopenharmony_ci                throw new \UnexpectedValueException(
1059ffe3c632Sopenharmony_ci                    'Invalid message property: ' . $key);
1060ffe3c632Sopenharmony_ci            }
1061ffe3c632Sopenharmony_ci            $setter = $field->getSetter();
1062ffe3c632Sopenharmony_ci            if ($field->isMap()) {
1063ffe3c632Sopenharmony_ci                $valueField = $field->getMessageType()->getFieldByName('value');
1064ffe3c632Sopenharmony_ci                if (!is_null($valueField) && $valueField->isWrapperType()) {
1065ffe3c632Sopenharmony_ci                    self::normalizeArrayElementsToMessageType($value, $valueField->getMessageType()->getClass());
1066ffe3c632Sopenharmony_ci                }
1067ffe3c632Sopenharmony_ci            } elseif ($field->isWrapperType()) {
1068ffe3c632Sopenharmony_ci                $class = $field->getMessageType()->getClass();
1069ffe3c632Sopenharmony_ci                if ($field->isRepeated()) {
1070ffe3c632Sopenharmony_ci                    self::normalizeArrayElementsToMessageType($value, $class);
1071ffe3c632Sopenharmony_ci                } else {
1072ffe3c632Sopenharmony_ci                    self::normalizeToMessageType($value, $class);
1073ffe3c632Sopenharmony_ci                }
1074ffe3c632Sopenharmony_ci            }
1075ffe3c632Sopenharmony_ci            $this->$setter($value);
1076ffe3c632Sopenharmony_ci        }
1077ffe3c632Sopenharmony_ci    }
1078ffe3c632Sopenharmony_ci
1079ffe3c632Sopenharmony_ci    /**
1080ffe3c632Sopenharmony_ci     * Tries to normalize the elements in $value into a provided protobuf
1081ffe3c632Sopenharmony_ci     * wrapper type $class. If $value is any type other than array, we do
1082ffe3c632Sopenharmony_ci     * not do any conversion, and instead rely on the existing protobuf
1083ffe3c632Sopenharmony_ci     * type checking. If $value is an array, we process each element and
1084ffe3c632Sopenharmony_ci     * try to convert it to an instance of $class.
1085ffe3c632Sopenharmony_ci     *
1086ffe3c632Sopenharmony_ci     * @param mixed $value The array of values to normalize.
1087ffe3c632Sopenharmony_ci     * @param string $class The expected wrapper class name
1088ffe3c632Sopenharmony_ci     */
1089ffe3c632Sopenharmony_ci    private static function normalizeArrayElementsToMessageType(&$value, $class)
1090ffe3c632Sopenharmony_ci    {
1091ffe3c632Sopenharmony_ci        if (!is_array($value)) {
1092ffe3c632Sopenharmony_ci            // In the case that $value is not an array, we do not want to
1093ffe3c632Sopenharmony_ci            // attempt any conversion. Note that this includes the cases
1094ffe3c632Sopenharmony_ci            // when $value is a RepeatedField of MapField. In those cases,
1095ffe3c632Sopenharmony_ci            // we do not need to convert the elements, as they should
1096ffe3c632Sopenharmony_ci            // already be the correct types.
1097ffe3c632Sopenharmony_ci            return;
1098ffe3c632Sopenharmony_ci        } else {
1099ffe3c632Sopenharmony_ci            // Normalize each element in the array.
1100ffe3c632Sopenharmony_ci            foreach ($value as $key => &$elementValue) {
1101ffe3c632Sopenharmony_ci              self::normalizeToMessageType($elementValue, $class);
1102ffe3c632Sopenharmony_ci            }
1103ffe3c632Sopenharmony_ci        }
1104ffe3c632Sopenharmony_ci    }
1105ffe3c632Sopenharmony_ci
1106ffe3c632Sopenharmony_ci    /**
1107ffe3c632Sopenharmony_ci     * Tries to normalize $value into a provided protobuf wrapper type $class.
1108ffe3c632Sopenharmony_ci     * If $value is any type other than an object, we attempt to construct an
1109ffe3c632Sopenharmony_ci     * instance of $class and assign $value to it using the setValue method
1110ffe3c632Sopenharmony_ci     * shared by all wrapper types.
1111ffe3c632Sopenharmony_ci     *
1112ffe3c632Sopenharmony_ci     * This method will raise an error if it receives a type that cannot be
1113ffe3c632Sopenharmony_ci     * assigned to the wrapper type via setValue.
1114ffe3c632Sopenharmony_ci     *
1115ffe3c632Sopenharmony_ci     * @param mixed $value The value to normalize.
1116ffe3c632Sopenharmony_ci     * @param string $class The expected wrapper class name
1117ffe3c632Sopenharmony_ci     */
1118ffe3c632Sopenharmony_ci    private static function normalizeToMessageType(&$value, $class)
1119ffe3c632Sopenharmony_ci    {
1120ffe3c632Sopenharmony_ci        if (is_null($value) || is_object($value)) {
1121ffe3c632Sopenharmony_ci            // This handles the case that $value is an instance of $class. We
1122ffe3c632Sopenharmony_ci            // choose not to do any more strict checking here, relying on the
1123ffe3c632Sopenharmony_ci            // existing type checking done by GPBUtil.
1124ffe3c632Sopenharmony_ci            return;
1125ffe3c632Sopenharmony_ci        } else {
1126ffe3c632Sopenharmony_ci            // Try to instantiate $class and set the value
1127ffe3c632Sopenharmony_ci            try {
1128ffe3c632Sopenharmony_ci                $msg = new $class;
1129ffe3c632Sopenharmony_ci                $msg->setValue($value);
1130ffe3c632Sopenharmony_ci                $value = $msg;
1131ffe3c632Sopenharmony_ci                return;
1132ffe3c632Sopenharmony_ci            } catch (\Exception $exception) {
1133ffe3c632Sopenharmony_ci                trigger_error(
1134ffe3c632Sopenharmony_ci                    "Error normalizing value to type '$class': " . $exception->getMessage(),
1135ffe3c632Sopenharmony_ci                    E_USER_ERROR
1136ffe3c632Sopenharmony_ci                );
1137ffe3c632Sopenharmony_ci            }
1138ffe3c632Sopenharmony_ci        }
1139ffe3c632Sopenharmony_ci    }
1140ffe3c632Sopenharmony_ci
1141ffe3c632Sopenharmony_ci    protected function mergeFromJsonArray($array, $ignore_unknown)
1142ffe3c632Sopenharmony_ci    {
1143ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\Any")) {
1144ffe3c632Sopenharmony_ci            $this->clear();
1145ffe3c632Sopenharmony_ci            $this->setTypeUrl($array["@type"]);
1146ffe3c632Sopenharmony_ci            $msg = $this->unpack();
1147ffe3c632Sopenharmony_ci            if (GPBUtil::hasSpecialJsonMapping($msg)) {
1148ffe3c632Sopenharmony_ci                $msg->mergeFromJsonArray($array["value"], $ignore_unknown);
1149ffe3c632Sopenharmony_ci            } else {
1150ffe3c632Sopenharmony_ci                unset($array["@type"]);
1151ffe3c632Sopenharmony_ci                $msg->mergeFromJsonArray($array, $ignore_unknown);
1152ffe3c632Sopenharmony_ci            }
1153ffe3c632Sopenharmony_ci            $this->setValue($msg->serializeToString());
1154ffe3c632Sopenharmony_ci            return;
1155ffe3c632Sopenharmony_ci        }
1156ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\DoubleValue") ||
1157ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\FloatValue")  ||
1158ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\Int64Value")  ||
1159ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\UInt64Value") ||
1160ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\Int32Value")  ||
1161ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\UInt32Value") ||
1162ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\BoolValue")   ||
1163ffe3c632Sopenharmony_ci            is_a($this, "Google\Protobuf\StringValue")) {
1164ffe3c632Sopenharmony_ci            $this->setValue($array);
1165ffe3c632Sopenharmony_ci            return;
1166ffe3c632Sopenharmony_ci        }
1167ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\BytesValue")) {
1168ffe3c632Sopenharmony_ci            $this->setValue(base64_decode($array));
1169ffe3c632Sopenharmony_ci            return;
1170ffe3c632Sopenharmony_ci        }
1171ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\Duration")) {
1172ffe3c632Sopenharmony_ci            $this->mergeFrom(GPBUtil::parseDuration($array));
1173ffe3c632Sopenharmony_ci            return;
1174ffe3c632Sopenharmony_ci        }
1175ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\FieldMask")) {
1176ffe3c632Sopenharmony_ci            $this->mergeFrom(GPBUtil::parseFieldMask($array));
1177ffe3c632Sopenharmony_ci            return;
1178ffe3c632Sopenharmony_ci        }
1179ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\Timestamp")) {
1180ffe3c632Sopenharmony_ci            $this->mergeFrom(GPBUtil::parseTimestamp($array));
1181ffe3c632Sopenharmony_ci            return;
1182ffe3c632Sopenharmony_ci        }
1183ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\Struct")) {
1184ffe3c632Sopenharmony_ci            $fields = $this->getFields();
1185ffe3c632Sopenharmony_ci            foreach($array as $key => $value) {
1186ffe3c632Sopenharmony_ci                $v = new Value();
1187ffe3c632Sopenharmony_ci                $v->mergeFromJsonArray($value, $ignore_unknown);
1188ffe3c632Sopenharmony_ci                $fields[$key] = $v;
1189ffe3c632Sopenharmony_ci            }
1190ffe3c632Sopenharmony_ci        }
1191ffe3c632Sopenharmony_ci        if (is_a($this, "Google\Protobuf\Value")) {
1192ffe3c632Sopenharmony_ci            if (is_bool($array)) {
1193ffe3c632Sopenharmony_ci                $this->setBoolValue($array);
1194ffe3c632Sopenharmony_ci            } elseif (is_string($array)) {
1195ffe3c632Sopenharmony_ci                $this->setStringValue($array);
1196ffe3c632Sopenharmony_ci            } elseif (is_null($array)) {
1197ffe3c632Sopenharmony_ci                $this->setNullValue(0);
1198ffe3c632Sopenharmony_ci            } elseif (is_double($array) || is_integer($array)) {
1199ffe3c632Sopenharmony_ci                $this->setNumberValue($array);
1200ffe3c632Sopenharmony_ci            } elseif (is_array($array)) {
1201ffe3c632Sopenharmony_ci                if (array_values($array) !== $array) {
1202ffe3c632Sopenharmony_ci                    // Associative array
1203ffe3c632Sopenharmony_ci                    $struct_value = $this->getStructValue();
1204ffe3c632Sopenharmony_ci                    if (is_null($struct_value)) {
1205ffe3c632Sopenharmony_ci                        $struct_value = new Struct();
1206ffe3c632Sopenharmony_ci                        $this->setStructValue($struct_value);
1207ffe3c632Sopenharmony_ci                    }
1208ffe3c632Sopenharmony_ci                    foreach ($array as $key => $v) {
1209ffe3c632Sopenharmony_ci                        $value = new Value();
1210ffe3c632Sopenharmony_ci                        $value->mergeFromJsonArray($v, $ignore_unknown);
1211ffe3c632Sopenharmony_ci                        $values = $struct_value->getFields();
1212ffe3c632Sopenharmony_ci                        $values[$key]= $value;
1213ffe3c632Sopenharmony_ci                    }
1214ffe3c632Sopenharmony_ci                } else {
1215ffe3c632Sopenharmony_ci                    // Array
1216ffe3c632Sopenharmony_ci                    $list_value = $this->getListValue();
1217ffe3c632Sopenharmony_ci                    if (is_null($list_value)) {
1218ffe3c632Sopenharmony_ci                        $list_value = new ListValue();
1219ffe3c632Sopenharmony_ci                        $this->setListValue($list_value);
1220ffe3c632Sopenharmony_ci                    }
1221ffe3c632Sopenharmony_ci                    foreach ($array as $v) {
1222ffe3c632Sopenharmony_ci                        $value = new Value();
1223ffe3c632Sopenharmony_ci                        $value->mergeFromJsonArray($v, $ignore_unknown);
1224ffe3c632Sopenharmony_ci                        $values = $list_value->getValues();
1225ffe3c632Sopenharmony_ci                        $values[]= $value;
1226ffe3c632Sopenharmony_ci                    }
1227ffe3c632Sopenharmony_ci                }
1228ffe3c632Sopenharmony_ci            } else {
1229ffe3c632Sopenharmony_ci                throw new GPBDecodeException("Invalid type for Value.");
1230ffe3c632Sopenharmony_ci            }
1231ffe3c632Sopenharmony_ci            return;
1232ffe3c632Sopenharmony_ci        }
1233ffe3c632Sopenharmony_ci        $this->mergeFromArrayJsonImpl($array, $ignore_unknown);
1234ffe3c632Sopenharmony_ci    }
1235ffe3c632Sopenharmony_ci
1236ffe3c632Sopenharmony_ci    private function mergeFromArrayJsonImpl($array, $ignore_unknown)
1237ffe3c632Sopenharmony_ci    {
1238ffe3c632Sopenharmony_ci        foreach ($array as $key => $value) {
1239ffe3c632Sopenharmony_ci            $field = $this->desc->getFieldByJsonName($key);
1240ffe3c632Sopenharmony_ci            if (is_null($field)) {
1241ffe3c632Sopenharmony_ci                $field = $this->desc->getFieldByName($key);
1242ffe3c632Sopenharmony_ci                if (is_null($field)) {
1243ffe3c632Sopenharmony_ci                    continue;
1244ffe3c632Sopenharmony_ci                }
1245ffe3c632Sopenharmony_ci            }
1246ffe3c632Sopenharmony_ci            if ($field->isMap()) {
1247ffe3c632Sopenharmony_ci                if (is_null($value)) {
1248ffe3c632Sopenharmony_ci                    continue;
1249ffe3c632Sopenharmony_ci                }
1250ffe3c632Sopenharmony_ci                $key_field = $field->getMessageType()->getFieldByNumber(1);
1251ffe3c632Sopenharmony_ci                $value_field = $field->getMessageType()->getFieldByNumber(2);
1252ffe3c632Sopenharmony_ci                foreach ($value as $tmp_key => $tmp_value) {
1253ffe3c632Sopenharmony_ci                    if (is_null($tmp_value)) {
1254ffe3c632Sopenharmony_ci                        throw new \Exception(
1255ffe3c632Sopenharmony_ci                            "Map value field element cannot be null.");
1256ffe3c632Sopenharmony_ci                    }
1257ffe3c632Sopenharmony_ci                    $proto_key = $this->convertJsonValueToProtoValue(
1258ffe3c632Sopenharmony_ci                        $tmp_key,
1259ffe3c632Sopenharmony_ci                        $key_field,
1260ffe3c632Sopenharmony_ci                        $ignore_unknown,
1261ffe3c632Sopenharmony_ci                        true);
1262ffe3c632Sopenharmony_ci                    $proto_value = $this->convertJsonValueToProtoValue(
1263ffe3c632Sopenharmony_ci                        $tmp_value,
1264ffe3c632Sopenharmony_ci                        $value_field,
1265ffe3c632Sopenharmony_ci                        $ignore_unknown);
1266ffe3c632Sopenharmony_ci                    self::kvUpdateHelper($field, $proto_key, $proto_value);
1267ffe3c632Sopenharmony_ci                }
1268ffe3c632Sopenharmony_ci            } else if ($field->isRepeated()) {
1269ffe3c632Sopenharmony_ci                if (is_null($value)) {
1270ffe3c632Sopenharmony_ci                    continue;
1271ffe3c632Sopenharmony_ci                }
1272ffe3c632Sopenharmony_ci                foreach ($value as $tmp) {
1273ffe3c632Sopenharmony_ci                    if (is_null($tmp)) {
1274ffe3c632Sopenharmony_ci                        throw new \Exception(
1275ffe3c632Sopenharmony_ci                            "Repeated field elements cannot be null.");
1276ffe3c632Sopenharmony_ci                    }
1277ffe3c632Sopenharmony_ci                    $proto_value = $this->convertJsonValueToProtoValue(
1278ffe3c632Sopenharmony_ci                        $tmp,
1279ffe3c632Sopenharmony_ci                        $field,
1280ffe3c632Sopenharmony_ci                        $ignore_unknown);
1281ffe3c632Sopenharmony_ci                    self::appendHelper($field, $proto_value);
1282ffe3c632Sopenharmony_ci                }
1283ffe3c632Sopenharmony_ci            } else {
1284ffe3c632Sopenharmony_ci                $setter = $field->getSetter();
1285ffe3c632Sopenharmony_ci                $proto_value = $this->convertJsonValueToProtoValue(
1286ffe3c632Sopenharmony_ci                    $value,
1287ffe3c632Sopenharmony_ci                    $field,
1288ffe3c632Sopenharmony_ci                    $ignore_unknown);
1289ffe3c632Sopenharmony_ci                if ($field->getType() === GPBType::MESSAGE) {
1290ffe3c632Sopenharmony_ci                    if (is_null($proto_value)) {
1291ffe3c632Sopenharmony_ci                        continue;
1292ffe3c632Sopenharmony_ci                    }
1293ffe3c632Sopenharmony_ci                    $getter = $field->getGetter();
1294ffe3c632Sopenharmony_ci                    $submsg = $this->$getter();
1295ffe3c632Sopenharmony_ci                    if (!is_null($submsg)) {
1296ffe3c632Sopenharmony_ci                        $submsg->mergeFrom($proto_value);
1297ffe3c632Sopenharmony_ci                        continue;
1298ffe3c632Sopenharmony_ci                    }
1299ffe3c632Sopenharmony_ci                }
1300ffe3c632Sopenharmony_ci                $this->$setter($proto_value);
1301ffe3c632Sopenharmony_ci            }
1302ffe3c632Sopenharmony_ci        }
1303ffe3c632Sopenharmony_ci    }
1304ffe3c632Sopenharmony_ci
1305ffe3c632Sopenharmony_ci    /**
1306ffe3c632Sopenharmony_ci     * @ignore
1307ffe3c632Sopenharmony_ci     */
1308ffe3c632Sopenharmony_ci    public function parseFromJsonStream($input, $ignore_unknown)
1309ffe3c632Sopenharmony_ci    {
1310ffe3c632Sopenharmony_ci        $array = json_decode($input->getData(), true, 512, JSON_BIGINT_AS_STRING);
1311ffe3c632Sopenharmony_ci        if ($this instanceof \Google\Protobuf\ListValue) {
1312ffe3c632Sopenharmony_ci            $array = ["values"=>$array];
1313ffe3c632Sopenharmony_ci        }
1314ffe3c632Sopenharmony_ci        if (is_null($array)) {
1315ffe3c632Sopenharmony_ci            if ($this instanceof \Google\Protobuf\Value) {
1316ffe3c632Sopenharmony_ci              $this->setNullValue(\Google\Protobuf\NullValue::NULL_VALUE);
1317ffe3c632Sopenharmony_ci              return;
1318ffe3c632Sopenharmony_ci            } else {
1319ffe3c632Sopenharmony_ci              throw new GPBDecodeException(
1320ffe3c632Sopenharmony_ci                  "Cannot decode json string: " . $input->getData());
1321ffe3c632Sopenharmony_ci            }
1322ffe3c632Sopenharmony_ci        }
1323ffe3c632Sopenharmony_ci        try {
1324ffe3c632Sopenharmony_ci            $this->mergeFromJsonArray($array, $ignore_unknown);
1325ffe3c632Sopenharmony_ci        } catch (\Exception $e) {
1326ffe3c632Sopenharmony_ci            throw new GPBDecodeException($e->getMessage());
1327ffe3c632Sopenharmony_ci        }
1328ffe3c632Sopenharmony_ci    }
1329ffe3c632Sopenharmony_ci
1330ffe3c632Sopenharmony_ci    /**
1331ffe3c632Sopenharmony_ci     * @ignore
1332ffe3c632Sopenharmony_ci     */
1333ffe3c632Sopenharmony_ci    private function serializeSingularFieldToStream($field, &$output)
1334ffe3c632Sopenharmony_ci    {
1335ffe3c632Sopenharmony_ci        if (!$this->existField($field)) {
1336ffe3c632Sopenharmony_ci            return true;
1337ffe3c632Sopenharmony_ci        }
1338ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1339ffe3c632Sopenharmony_ci        $value = $this->$getter();
1340ffe3c632Sopenharmony_ci        if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) {
1341ffe3c632Sopenharmony_ci            return false;
1342ffe3c632Sopenharmony_ci        }
1343ffe3c632Sopenharmony_ci        return true;
1344ffe3c632Sopenharmony_ci    }
1345ffe3c632Sopenharmony_ci
1346ffe3c632Sopenharmony_ci    /**
1347ffe3c632Sopenharmony_ci     * @ignore
1348ffe3c632Sopenharmony_ci     */
1349ffe3c632Sopenharmony_ci    private function serializeRepeatedFieldToStream($field, &$output)
1350ffe3c632Sopenharmony_ci    {
1351ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1352ffe3c632Sopenharmony_ci        $values = $this->$getter();
1353ffe3c632Sopenharmony_ci        $count = count($values);
1354ffe3c632Sopenharmony_ci        if ($count === 0) {
1355ffe3c632Sopenharmony_ci            return true;
1356ffe3c632Sopenharmony_ci        }
1357ffe3c632Sopenharmony_ci
1358ffe3c632Sopenharmony_ci        $packed = $field->getPacked();
1359ffe3c632Sopenharmony_ci        if ($packed) {
1360ffe3c632Sopenharmony_ci            if (!GPBWire::writeTag(
1361ffe3c632Sopenharmony_ci                $output,
1362ffe3c632Sopenharmony_ci                GPBWire::makeTag($field->getNumber(), GPBType::STRING))) {
1363ffe3c632Sopenharmony_ci                return false;
1364ffe3c632Sopenharmony_ci            }
1365ffe3c632Sopenharmony_ci            $size = 0;
1366ffe3c632Sopenharmony_ci            foreach ($values as $value) {
1367ffe3c632Sopenharmony_ci                $size += $this->fieldDataOnlyByteSize($field, $value);
1368ffe3c632Sopenharmony_ci            }
1369ffe3c632Sopenharmony_ci            if (!$output->writeVarint32($size, true)) {
1370ffe3c632Sopenharmony_ci                return false;
1371ffe3c632Sopenharmony_ci            }
1372ffe3c632Sopenharmony_ci        }
1373ffe3c632Sopenharmony_ci
1374ffe3c632Sopenharmony_ci        foreach ($values as $value) {
1375ffe3c632Sopenharmony_ci            if (!GPBWire::serializeFieldToStream(
1376ffe3c632Sopenharmony_ci                $value,
1377ffe3c632Sopenharmony_ci                $field,
1378ffe3c632Sopenharmony_ci                !$packed,
1379ffe3c632Sopenharmony_ci                $output)) {
1380ffe3c632Sopenharmony_ci                return false;
1381ffe3c632Sopenharmony_ci            }
1382ffe3c632Sopenharmony_ci        }
1383ffe3c632Sopenharmony_ci        return true;
1384ffe3c632Sopenharmony_ci    }
1385ffe3c632Sopenharmony_ci
1386ffe3c632Sopenharmony_ci    /**
1387ffe3c632Sopenharmony_ci     * @ignore
1388ffe3c632Sopenharmony_ci     */
1389ffe3c632Sopenharmony_ci    private function serializeMapFieldToStream($field, $output)
1390ffe3c632Sopenharmony_ci    {
1391ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1392ffe3c632Sopenharmony_ci        $values = $this->$getter();
1393ffe3c632Sopenharmony_ci        $count = count($values);
1394ffe3c632Sopenharmony_ci        if ($count === 0) {
1395ffe3c632Sopenharmony_ci            return true;
1396ffe3c632Sopenharmony_ci        }
1397ffe3c632Sopenharmony_ci
1398ffe3c632Sopenharmony_ci        foreach ($values as $key => $value) {
1399ffe3c632Sopenharmony_ci            $map_entry = new MapEntry($field->getMessageType());
1400ffe3c632Sopenharmony_ci            $map_entry->setKey($key);
1401ffe3c632Sopenharmony_ci            $map_entry->setValue($value);
1402ffe3c632Sopenharmony_ci            if (!GPBWire::serializeFieldToStream(
1403ffe3c632Sopenharmony_ci                $map_entry,
1404ffe3c632Sopenharmony_ci                $field,
1405ffe3c632Sopenharmony_ci                true,
1406ffe3c632Sopenharmony_ci                $output)) {
1407ffe3c632Sopenharmony_ci                return false;
1408ffe3c632Sopenharmony_ci            }
1409ffe3c632Sopenharmony_ci        }
1410ffe3c632Sopenharmony_ci        return true;
1411ffe3c632Sopenharmony_ci    }
1412ffe3c632Sopenharmony_ci
1413ffe3c632Sopenharmony_ci    /**
1414ffe3c632Sopenharmony_ci     * @ignore
1415ffe3c632Sopenharmony_ci     */
1416ffe3c632Sopenharmony_ci    private function serializeFieldToStream(&$output, $field)
1417ffe3c632Sopenharmony_ci    {
1418ffe3c632Sopenharmony_ci        if ($field->isMap()) {
1419ffe3c632Sopenharmony_ci            return $this->serializeMapFieldToStream($field, $output);
1420ffe3c632Sopenharmony_ci        } elseif ($field->isRepeated()) {
1421ffe3c632Sopenharmony_ci            return $this->serializeRepeatedFieldToStream($field, $output);
1422ffe3c632Sopenharmony_ci        } else {
1423ffe3c632Sopenharmony_ci            return $this->serializeSingularFieldToStream($field, $output);
1424ffe3c632Sopenharmony_ci        }
1425ffe3c632Sopenharmony_ci    }
1426ffe3c632Sopenharmony_ci
1427ffe3c632Sopenharmony_ci    /**
1428ffe3c632Sopenharmony_ci     * @ignore
1429ffe3c632Sopenharmony_ci     */
1430ffe3c632Sopenharmony_ci    private function serializeFieldToJsonStream(&$output, $field)
1431ffe3c632Sopenharmony_ci    {
1432ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1433ffe3c632Sopenharmony_ci        $values = $this->$getter();
1434ffe3c632Sopenharmony_ci        return GPBJsonWire::serializeFieldToStream(
1435ffe3c632Sopenharmony_ci            $values, $field, $output, !GPBUtil::hasSpecialJsonMapping($this));
1436ffe3c632Sopenharmony_ci    }
1437ffe3c632Sopenharmony_ci
1438ffe3c632Sopenharmony_ci    /**
1439ffe3c632Sopenharmony_ci     * @ignore
1440ffe3c632Sopenharmony_ci     */
1441ffe3c632Sopenharmony_ci    public function serializeToStream(&$output)
1442ffe3c632Sopenharmony_ci    {
1443ffe3c632Sopenharmony_ci        $fields = $this->desc->getField();
1444ffe3c632Sopenharmony_ci        foreach ($fields as $field) {
1445ffe3c632Sopenharmony_ci            if (!$this->serializeFieldToStream($output, $field)) {
1446ffe3c632Sopenharmony_ci                return false;
1447ffe3c632Sopenharmony_ci            }
1448ffe3c632Sopenharmony_ci        }
1449ffe3c632Sopenharmony_ci        $output->writeRaw($this->unknown, strlen($this->unknown));
1450ffe3c632Sopenharmony_ci        return true;
1451ffe3c632Sopenharmony_ci    }
1452ffe3c632Sopenharmony_ci
1453ffe3c632Sopenharmony_ci    /**
1454ffe3c632Sopenharmony_ci     * @ignore
1455ffe3c632Sopenharmony_ci     */
1456ffe3c632Sopenharmony_ci    public function serializeToJsonStream(&$output)
1457ffe3c632Sopenharmony_ci    {
1458ffe3c632Sopenharmony_ci        if (is_a($this, 'Google\Protobuf\Any')) {
1459ffe3c632Sopenharmony_ci            $output->writeRaw("{", 1);
1460ffe3c632Sopenharmony_ci            $type_field = $this->desc->getFieldByNumber(1);
1461ffe3c632Sopenharmony_ci            $value_msg = $this->unpack();
1462ffe3c632Sopenharmony_ci
1463ffe3c632Sopenharmony_ci            // Serialize type url.
1464ffe3c632Sopenharmony_ci            $output->writeRaw("\"@type\":", 8);
1465ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1466ffe3c632Sopenharmony_ci            $output->writeRaw($this->getTypeUrl(), strlen($this->getTypeUrl()));
1467ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1468ffe3c632Sopenharmony_ci
1469ffe3c632Sopenharmony_ci            // Serialize value
1470ffe3c632Sopenharmony_ci            if (GPBUtil::hasSpecialJsonMapping($value_msg)) {
1471ffe3c632Sopenharmony_ci                $output->writeRaw(",\"value\":", 9);
1472ffe3c632Sopenharmony_ci                $value_msg->serializeToJsonStream($output);
1473ffe3c632Sopenharmony_ci            } else {
1474ffe3c632Sopenharmony_ci                $value_fields = $value_msg->desc->getField();
1475ffe3c632Sopenharmony_ci                foreach ($value_fields as $field) {
1476ffe3c632Sopenharmony_ci                    if ($value_msg->existField($field)) {
1477ffe3c632Sopenharmony_ci                        $output->writeRaw(",", 1);
1478ffe3c632Sopenharmony_ci                        if (!$value_msg->serializeFieldToJsonStream($output, $field)) {
1479ffe3c632Sopenharmony_ci                            return false;
1480ffe3c632Sopenharmony_ci                        }
1481ffe3c632Sopenharmony_ci                    }
1482ffe3c632Sopenharmony_ci                }
1483ffe3c632Sopenharmony_ci            }
1484ffe3c632Sopenharmony_ci
1485ffe3c632Sopenharmony_ci            $output->writeRaw("}", 1);
1486ffe3c632Sopenharmony_ci        } elseif (is_a($this, 'Google\Protobuf\FieldMask')) {
1487ffe3c632Sopenharmony_ci            $field_mask = GPBUtil::formatFieldMask($this);
1488ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1489ffe3c632Sopenharmony_ci            $output->writeRaw($field_mask, strlen($field_mask));
1490ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1491ffe3c632Sopenharmony_ci        } elseif (is_a($this, 'Google\Protobuf\Duration')) {
1492ffe3c632Sopenharmony_ci            $duration = GPBUtil::formatDuration($this) . "s";
1493ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1494ffe3c632Sopenharmony_ci            $output->writeRaw($duration, strlen($duration));
1495ffe3c632Sopenharmony_ci            $output->writeRaw("\"", 1);
1496ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\Timestamp') {
1497ffe3c632Sopenharmony_ci            $timestamp = GPBUtil::formatTimestamp($this);
1498ffe3c632Sopenharmony_ci            $timestamp = json_encode($timestamp);
1499ffe3c632Sopenharmony_ci            $output->writeRaw($timestamp, strlen($timestamp));
1500ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\ListValue') {
1501ffe3c632Sopenharmony_ci            $field = $this->desc->getField()[1];
1502ffe3c632Sopenharmony_ci            if (!$this->existField($field)) {
1503ffe3c632Sopenharmony_ci                $output->writeRaw("[]", 2);
1504ffe3c632Sopenharmony_ci            } else {
1505ffe3c632Sopenharmony_ci                if (!$this->serializeFieldToJsonStream($output, $field)) {
1506ffe3c632Sopenharmony_ci                    return false;
1507ffe3c632Sopenharmony_ci                }
1508ffe3c632Sopenharmony_ci            }
1509ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\Struct') {
1510ffe3c632Sopenharmony_ci            $field = $this->desc->getField()[1];
1511ffe3c632Sopenharmony_ci            if (!$this->existField($field)) {
1512ffe3c632Sopenharmony_ci                $output->writeRaw("{}", 2);
1513ffe3c632Sopenharmony_ci            } else {
1514ffe3c632Sopenharmony_ci                if (!$this->serializeFieldToJsonStream($output, $field)) {
1515ffe3c632Sopenharmony_ci                    return false;
1516ffe3c632Sopenharmony_ci                }
1517ffe3c632Sopenharmony_ci            }
1518ffe3c632Sopenharmony_ci        } else {
1519ffe3c632Sopenharmony_ci            if (!GPBUtil::hasSpecialJsonMapping($this)) {
1520ffe3c632Sopenharmony_ci                $output->writeRaw("{", 1);
1521ffe3c632Sopenharmony_ci            }
1522ffe3c632Sopenharmony_ci            $fields = $this->desc->getField();
1523ffe3c632Sopenharmony_ci            $first = true;
1524ffe3c632Sopenharmony_ci            foreach ($fields as $field) {
1525ffe3c632Sopenharmony_ci                if ($this->existField($field) ||
1526ffe3c632Sopenharmony_ci                    GPBUtil::hasJsonValue($this)) {
1527ffe3c632Sopenharmony_ci                    if ($first) {
1528ffe3c632Sopenharmony_ci                        $first = false;
1529ffe3c632Sopenharmony_ci                    } else {
1530ffe3c632Sopenharmony_ci                        $output->writeRaw(",", 1);
1531ffe3c632Sopenharmony_ci                    }
1532ffe3c632Sopenharmony_ci                    if (!$this->serializeFieldToJsonStream($output, $field)) {
1533ffe3c632Sopenharmony_ci                        return false;
1534ffe3c632Sopenharmony_ci                    }
1535ffe3c632Sopenharmony_ci                }
1536ffe3c632Sopenharmony_ci            }
1537ffe3c632Sopenharmony_ci            if (!GPBUtil::hasSpecialJsonMapping($this)) {
1538ffe3c632Sopenharmony_ci                $output->writeRaw("}", 1);
1539ffe3c632Sopenharmony_ci            }
1540ffe3c632Sopenharmony_ci        }
1541ffe3c632Sopenharmony_ci        return true;
1542ffe3c632Sopenharmony_ci    }
1543ffe3c632Sopenharmony_ci
1544ffe3c632Sopenharmony_ci    /**
1545ffe3c632Sopenharmony_ci     * Serialize the message to string.
1546ffe3c632Sopenharmony_ci     * @return string Serialized binary protobuf data.
1547ffe3c632Sopenharmony_ci     */
1548ffe3c632Sopenharmony_ci    public function serializeToString()
1549ffe3c632Sopenharmony_ci    {
1550ffe3c632Sopenharmony_ci        $output = new CodedOutputStream($this->byteSize());
1551ffe3c632Sopenharmony_ci        $this->serializeToStream($output);
1552ffe3c632Sopenharmony_ci        return $output->getData();
1553ffe3c632Sopenharmony_ci    }
1554ffe3c632Sopenharmony_ci
1555ffe3c632Sopenharmony_ci    /**
1556ffe3c632Sopenharmony_ci     * Serialize the message to json string.
1557ffe3c632Sopenharmony_ci     * @return string Serialized json protobuf data.
1558ffe3c632Sopenharmony_ci     */
1559ffe3c632Sopenharmony_ci    public function serializeToJsonString()
1560ffe3c632Sopenharmony_ci    {
1561ffe3c632Sopenharmony_ci        $output = new CodedOutputStream($this->jsonByteSize());
1562ffe3c632Sopenharmony_ci        $this->serializeToJsonStream($output);
1563ffe3c632Sopenharmony_ci        return $output->getData();
1564ffe3c632Sopenharmony_ci    }
1565ffe3c632Sopenharmony_ci
1566ffe3c632Sopenharmony_ci    /**
1567ffe3c632Sopenharmony_ci     * @ignore
1568ffe3c632Sopenharmony_ci     */
1569ffe3c632Sopenharmony_ci    private function existField($field)
1570ffe3c632Sopenharmony_ci    {
1571ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1572ffe3c632Sopenharmony_ci        $hazzer = "has" . substr($getter, 3);
1573ffe3c632Sopenharmony_ci
1574ffe3c632Sopenharmony_ci        if (method_exists($this, $hazzer)) {
1575ffe3c632Sopenharmony_ci          return $this->$hazzer();
1576ffe3c632Sopenharmony_ci        } else if ($field->getOneofIndex() !== -1) {
1577ffe3c632Sopenharmony_ci          // For old generated code, which does not have hazzers for oneof
1578ffe3c632Sopenharmony_ci          // fields.
1579ffe3c632Sopenharmony_ci          $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
1580ffe3c632Sopenharmony_ci          $oneof_name = $oneof->getName();
1581ffe3c632Sopenharmony_ci          return $this->$oneof_name->getNumber() === $field->getNumber();
1582ffe3c632Sopenharmony_ci        }
1583ffe3c632Sopenharmony_ci
1584ffe3c632Sopenharmony_ci        $values = $this->$getter();
1585ffe3c632Sopenharmony_ci        if ($field->isMap()) {
1586ffe3c632Sopenharmony_ci            return count($values) !== 0;
1587ffe3c632Sopenharmony_ci        } elseif ($field->isRepeated()) {
1588ffe3c632Sopenharmony_ci            return count($values) !== 0;
1589ffe3c632Sopenharmony_ci        } else {
1590ffe3c632Sopenharmony_ci            return $values !== $this->defaultValue($field);
1591ffe3c632Sopenharmony_ci        }
1592ffe3c632Sopenharmony_ci    }
1593ffe3c632Sopenharmony_ci
1594ffe3c632Sopenharmony_ci    /**
1595ffe3c632Sopenharmony_ci     * @ignore
1596ffe3c632Sopenharmony_ci     */
1597ffe3c632Sopenharmony_ci    private function repeatedFieldDataOnlyByteSize($field)
1598ffe3c632Sopenharmony_ci    {
1599ffe3c632Sopenharmony_ci        $size = 0;
1600ffe3c632Sopenharmony_ci
1601ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1602ffe3c632Sopenharmony_ci        $values = $this->$getter();
1603ffe3c632Sopenharmony_ci        $count = count($values);
1604ffe3c632Sopenharmony_ci        if ($count !== 0) {
1605ffe3c632Sopenharmony_ci            $size += $count * GPBWire::tagSize($field);
1606ffe3c632Sopenharmony_ci            foreach ($values as $value) {
1607ffe3c632Sopenharmony_ci                $size += $this->singularFieldDataOnlyByteSize($field);
1608ffe3c632Sopenharmony_ci            }
1609ffe3c632Sopenharmony_ci        }
1610ffe3c632Sopenharmony_ci    }
1611ffe3c632Sopenharmony_ci
1612ffe3c632Sopenharmony_ci    /**
1613ffe3c632Sopenharmony_ci     * @ignore
1614ffe3c632Sopenharmony_ci     */
1615ffe3c632Sopenharmony_ci    private function fieldDataOnlyByteSize($field, $value)
1616ffe3c632Sopenharmony_ci    {
1617ffe3c632Sopenharmony_ci        $size = 0;
1618ffe3c632Sopenharmony_ci
1619ffe3c632Sopenharmony_ci        switch ($field->getType()) {
1620ffe3c632Sopenharmony_ci            case GPBType::BOOL:
1621ffe3c632Sopenharmony_ci                $size += 1;
1622ffe3c632Sopenharmony_ci                break;
1623ffe3c632Sopenharmony_ci            case GPBType::FLOAT:
1624ffe3c632Sopenharmony_ci            case GPBType::FIXED32:
1625ffe3c632Sopenharmony_ci            case GPBType::SFIXED32:
1626ffe3c632Sopenharmony_ci                $size += 4;
1627ffe3c632Sopenharmony_ci                break;
1628ffe3c632Sopenharmony_ci            case GPBType::DOUBLE:
1629ffe3c632Sopenharmony_ci            case GPBType::FIXED64:
1630ffe3c632Sopenharmony_ci            case GPBType::SFIXED64:
1631ffe3c632Sopenharmony_ci                $size += 8;
1632ffe3c632Sopenharmony_ci                break;
1633ffe3c632Sopenharmony_ci            case GPBType::INT32:
1634ffe3c632Sopenharmony_ci            case GPBType::ENUM:
1635ffe3c632Sopenharmony_ci                $size += GPBWire::varint32Size($value, true);
1636ffe3c632Sopenharmony_ci                break;
1637ffe3c632Sopenharmony_ci            case GPBType::UINT32:
1638ffe3c632Sopenharmony_ci                $size += GPBWire::varint32Size($value);
1639ffe3c632Sopenharmony_ci                break;
1640ffe3c632Sopenharmony_ci            case GPBType::UINT64:
1641ffe3c632Sopenharmony_ci            case GPBType::INT64:
1642ffe3c632Sopenharmony_ci                $size += GPBWire::varint64Size($value);
1643ffe3c632Sopenharmony_ci                break;
1644ffe3c632Sopenharmony_ci            case GPBType::SINT32:
1645ffe3c632Sopenharmony_ci                $size += GPBWire::sint32Size($value);
1646ffe3c632Sopenharmony_ci                break;
1647ffe3c632Sopenharmony_ci            case GPBType::SINT64:
1648ffe3c632Sopenharmony_ci                $size += GPBWire::sint64Size($value);
1649ffe3c632Sopenharmony_ci                break;
1650ffe3c632Sopenharmony_ci            case GPBType::STRING:
1651ffe3c632Sopenharmony_ci            case GPBType::BYTES:
1652ffe3c632Sopenharmony_ci                $size += strlen($value);
1653ffe3c632Sopenharmony_ci                $size += GPBWire::varint32Size($size);
1654ffe3c632Sopenharmony_ci                break;
1655ffe3c632Sopenharmony_ci            case GPBType::MESSAGE:
1656ffe3c632Sopenharmony_ci                $size += $value->byteSize();
1657ffe3c632Sopenharmony_ci                $size += GPBWire::varint32Size($size);
1658ffe3c632Sopenharmony_ci                break;
1659ffe3c632Sopenharmony_ci            case GPBType::GROUP:
1660ffe3c632Sopenharmony_ci                // TODO(teboring): Add support.
1661ffe3c632Sopenharmony_ci                user_error("Unsupported type.");
1662ffe3c632Sopenharmony_ci                break;
1663ffe3c632Sopenharmony_ci            default:
1664ffe3c632Sopenharmony_ci                user_error("Unsupported type.");
1665ffe3c632Sopenharmony_ci                return 0;
1666ffe3c632Sopenharmony_ci        }
1667ffe3c632Sopenharmony_ci
1668ffe3c632Sopenharmony_ci        return $size;
1669ffe3c632Sopenharmony_ci    }
1670ffe3c632Sopenharmony_ci
1671ffe3c632Sopenharmony_ci    /**
1672ffe3c632Sopenharmony_ci     * @ignore
1673ffe3c632Sopenharmony_ci     */
1674ffe3c632Sopenharmony_ci    private function fieldDataOnlyJsonByteSize($field, $value)
1675ffe3c632Sopenharmony_ci    {
1676ffe3c632Sopenharmony_ci        $size = 0;
1677ffe3c632Sopenharmony_ci
1678ffe3c632Sopenharmony_ci        switch ($field->getType()) {
1679ffe3c632Sopenharmony_ci            case GPBType::SFIXED32:
1680ffe3c632Sopenharmony_ci            case GPBType::SINT32:
1681ffe3c632Sopenharmony_ci            case GPBType::INT32:
1682ffe3c632Sopenharmony_ci                $size += strlen(strval($value));
1683ffe3c632Sopenharmony_ci                break;
1684ffe3c632Sopenharmony_ci            case GPBType::FIXED32:
1685ffe3c632Sopenharmony_ci            case GPBType::UINT32:
1686ffe3c632Sopenharmony_ci                if ($value < 0) {
1687ffe3c632Sopenharmony_ci                    $value = bcadd($value, "4294967296");
1688ffe3c632Sopenharmony_ci                }
1689ffe3c632Sopenharmony_ci                $size += strlen(strval($value));
1690ffe3c632Sopenharmony_ci                break;
1691ffe3c632Sopenharmony_ci            case GPBType::FIXED64:
1692ffe3c632Sopenharmony_ci            case GPBType::UINT64:
1693ffe3c632Sopenharmony_ci                if ($value < 0) {
1694ffe3c632Sopenharmony_ci                    $value = bcadd($value, "18446744073709551616");
1695ffe3c632Sopenharmony_ci                }
1696ffe3c632Sopenharmony_ci                // Intentional fall through.
1697ffe3c632Sopenharmony_ci            case GPBType::SFIXED64:
1698ffe3c632Sopenharmony_ci            case GPBType::INT64:
1699ffe3c632Sopenharmony_ci            case GPBType::SINT64:
1700ffe3c632Sopenharmony_ci                $size += 2;  // size for ""
1701ffe3c632Sopenharmony_ci                $size += strlen(strval($value));
1702ffe3c632Sopenharmony_ci                break;
1703ffe3c632Sopenharmony_ci            case GPBType::FLOAT:
1704ffe3c632Sopenharmony_ci                if (is_nan($value)) {
1705ffe3c632Sopenharmony_ci                    $size += strlen("NaN") + 2;
1706ffe3c632Sopenharmony_ci                } elseif ($value === INF) {
1707ffe3c632Sopenharmony_ci                    $size += strlen("Infinity") + 2;
1708ffe3c632Sopenharmony_ci                } elseif ($value === -INF) {
1709ffe3c632Sopenharmony_ci                    $size += strlen("-Infinity") + 2;
1710ffe3c632Sopenharmony_ci                } else {
1711ffe3c632Sopenharmony_ci                    $size += strlen(sprintf("%.8g", $value));
1712ffe3c632Sopenharmony_ci                }
1713ffe3c632Sopenharmony_ci                break;
1714ffe3c632Sopenharmony_ci            case GPBType::DOUBLE:
1715ffe3c632Sopenharmony_ci                if (is_nan($value)) {
1716ffe3c632Sopenharmony_ci                    $size += strlen("NaN") + 2;
1717ffe3c632Sopenharmony_ci                } elseif ($value === INF) {
1718ffe3c632Sopenharmony_ci                    $size += strlen("Infinity") + 2;
1719ffe3c632Sopenharmony_ci                } elseif ($value === -INF) {
1720ffe3c632Sopenharmony_ci                    $size += strlen("-Infinity") + 2;
1721ffe3c632Sopenharmony_ci                } else {
1722ffe3c632Sopenharmony_ci                    $size += strlen(sprintf("%.17g", $value));
1723ffe3c632Sopenharmony_ci                }
1724ffe3c632Sopenharmony_ci                break;
1725ffe3c632Sopenharmony_ci            case GPBType::ENUM:
1726ffe3c632Sopenharmony_ci                $enum_desc = $field->getEnumType();
1727ffe3c632Sopenharmony_ci                if ($enum_desc->getClass() === "Google\Protobuf\NullValue") {
1728ffe3c632Sopenharmony_ci                    $size += 4;
1729ffe3c632Sopenharmony_ci                    break;
1730ffe3c632Sopenharmony_ci                }
1731ffe3c632Sopenharmony_ci                $enum_value_desc = $enum_desc->getValueByNumber($value);
1732ffe3c632Sopenharmony_ci                if (!is_null($enum_value_desc)) {
1733ffe3c632Sopenharmony_ci                    $size += 2;  // size for ""
1734ffe3c632Sopenharmony_ci                    $size += strlen($enum_value_desc->getName());
1735ffe3c632Sopenharmony_ci                } else {
1736ffe3c632Sopenharmony_ci                    $str_value = strval($value);
1737ffe3c632Sopenharmony_ci                    $size += strlen($str_value);
1738ffe3c632Sopenharmony_ci                }
1739ffe3c632Sopenharmony_ci                break;
1740ffe3c632Sopenharmony_ci            case GPBType::BOOL:
1741ffe3c632Sopenharmony_ci                if ($value) {
1742ffe3c632Sopenharmony_ci                    $size += 4;
1743ffe3c632Sopenharmony_ci                } else {
1744ffe3c632Sopenharmony_ci                    $size += 5;
1745ffe3c632Sopenharmony_ci                }
1746ffe3c632Sopenharmony_ci                break;
1747ffe3c632Sopenharmony_ci            case GPBType::STRING:
1748ffe3c632Sopenharmony_ci                $value = json_encode($value, JSON_UNESCAPED_UNICODE);
1749ffe3c632Sopenharmony_ci                $size += strlen($value);
1750ffe3c632Sopenharmony_ci                break;
1751ffe3c632Sopenharmony_ci            case GPBType::BYTES:
1752ffe3c632Sopenharmony_ci                # if (is_a($this, "Google\Protobuf\BytesValue")) {
1753ffe3c632Sopenharmony_ci                #     $size += strlen(json_encode($value));
1754ffe3c632Sopenharmony_ci                # } else {
1755ffe3c632Sopenharmony_ci                #     $size += strlen(base64_encode($value));
1756ffe3c632Sopenharmony_ci                #     $size += 2;  // size for \"\"
1757ffe3c632Sopenharmony_ci                # }
1758ffe3c632Sopenharmony_ci                $size += strlen(base64_encode($value));
1759ffe3c632Sopenharmony_ci                $size += 2;  // size for \"\"
1760ffe3c632Sopenharmony_ci                break;
1761ffe3c632Sopenharmony_ci            case GPBType::MESSAGE:
1762ffe3c632Sopenharmony_ci                $size += $value->jsonByteSize();
1763ffe3c632Sopenharmony_ci                break;
1764ffe3c632Sopenharmony_ci#             case GPBType::GROUP:
1765ffe3c632Sopenharmony_ci#                 // TODO(teboring): Add support.
1766ffe3c632Sopenharmony_ci#                 user_error("Unsupported type.");
1767ffe3c632Sopenharmony_ci#                 break;
1768ffe3c632Sopenharmony_ci            default:
1769ffe3c632Sopenharmony_ci                user_error("Unsupported type " . $field->getType());
1770ffe3c632Sopenharmony_ci                return 0;
1771ffe3c632Sopenharmony_ci        }
1772ffe3c632Sopenharmony_ci
1773ffe3c632Sopenharmony_ci        return $size;
1774ffe3c632Sopenharmony_ci    }
1775ffe3c632Sopenharmony_ci
1776ffe3c632Sopenharmony_ci    /**
1777ffe3c632Sopenharmony_ci     * @ignore
1778ffe3c632Sopenharmony_ci     */
1779ffe3c632Sopenharmony_ci    private function fieldByteSize($field)
1780ffe3c632Sopenharmony_ci    {
1781ffe3c632Sopenharmony_ci        $size = 0;
1782ffe3c632Sopenharmony_ci        if ($field->isMap()) {
1783ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1784ffe3c632Sopenharmony_ci            $values = $this->$getter();
1785ffe3c632Sopenharmony_ci            $count = count($values);
1786ffe3c632Sopenharmony_ci            if ($count !== 0) {
1787ffe3c632Sopenharmony_ci                $size += $count * GPBWire::tagSize($field);
1788ffe3c632Sopenharmony_ci                $message_type = $field->getMessageType();
1789ffe3c632Sopenharmony_ci                $key_field = $message_type->getFieldByNumber(1);
1790ffe3c632Sopenharmony_ci                $value_field = $message_type->getFieldByNumber(2);
1791ffe3c632Sopenharmony_ci                foreach ($values as $key => $value) {
1792ffe3c632Sopenharmony_ci                    $data_size = 0;
1793ffe3c632Sopenharmony_ci                    if ($key != $this->defaultValue($key_field)) {
1794ffe3c632Sopenharmony_ci                        $data_size += $this->fieldDataOnlyByteSize(
1795ffe3c632Sopenharmony_ci                            $key_field,
1796ffe3c632Sopenharmony_ci                            $key);
1797ffe3c632Sopenharmony_ci                        $data_size += GPBWire::tagSize($key_field);
1798ffe3c632Sopenharmony_ci                    }
1799ffe3c632Sopenharmony_ci                    if ($value != $this->defaultValue($value_field)) {
1800ffe3c632Sopenharmony_ci                        $data_size += $this->fieldDataOnlyByteSize(
1801ffe3c632Sopenharmony_ci                            $value_field,
1802ffe3c632Sopenharmony_ci                            $value);
1803ffe3c632Sopenharmony_ci                        $data_size += GPBWire::tagSize($value_field);
1804ffe3c632Sopenharmony_ci                    }
1805ffe3c632Sopenharmony_ci                    $size += GPBWire::varint32Size($data_size) + $data_size;
1806ffe3c632Sopenharmony_ci                }
1807ffe3c632Sopenharmony_ci            }
1808ffe3c632Sopenharmony_ci        } elseif ($field->isRepeated()) {
1809ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1810ffe3c632Sopenharmony_ci            $values = $this->$getter();
1811ffe3c632Sopenharmony_ci            $count = count($values);
1812ffe3c632Sopenharmony_ci            if ($count !== 0) {
1813ffe3c632Sopenharmony_ci                if ($field->getPacked()) {
1814ffe3c632Sopenharmony_ci                    $data_size = 0;
1815ffe3c632Sopenharmony_ci                    foreach ($values as $value) {
1816ffe3c632Sopenharmony_ci                        $data_size += $this->fieldDataOnlyByteSize($field, $value);
1817ffe3c632Sopenharmony_ci                    }
1818ffe3c632Sopenharmony_ci                    $size += GPBWire::tagSize($field);
1819ffe3c632Sopenharmony_ci                    $size += GPBWire::varint32Size($data_size);
1820ffe3c632Sopenharmony_ci                    $size += $data_size;
1821ffe3c632Sopenharmony_ci                } else {
1822ffe3c632Sopenharmony_ci                    $size += $count * GPBWire::tagSize($field);
1823ffe3c632Sopenharmony_ci                    foreach ($values as $value) {
1824ffe3c632Sopenharmony_ci                        $size += $this->fieldDataOnlyByteSize($field, $value);
1825ffe3c632Sopenharmony_ci                    }
1826ffe3c632Sopenharmony_ci                }
1827ffe3c632Sopenharmony_ci            }
1828ffe3c632Sopenharmony_ci        } elseif ($this->existField($field)) {
1829ffe3c632Sopenharmony_ci            $size += GPBWire::tagSize($field);
1830ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1831ffe3c632Sopenharmony_ci            $value = $this->$getter();
1832ffe3c632Sopenharmony_ci            $size += $this->fieldDataOnlyByteSize($field, $value);
1833ffe3c632Sopenharmony_ci        }
1834ffe3c632Sopenharmony_ci        return $size;
1835ffe3c632Sopenharmony_ci    }
1836ffe3c632Sopenharmony_ci
1837ffe3c632Sopenharmony_ci    /**
1838ffe3c632Sopenharmony_ci     * @ignore
1839ffe3c632Sopenharmony_ci     */
1840ffe3c632Sopenharmony_ci    private function fieldJsonByteSize($field)
1841ffe3c632Sopenharmony_ci    {
1842ffe3c632Sopenharmony_ci        $size = 0;
1843ffe3c632Sopenharmony_ci
1844ffe3c632Sopenharmony_ci        if ($field->isMap()) {
1845ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1846ffe3c632Sopenharmony_ci            $values = $this->$getter();
1847ffe3c632Sopenharmony_ci            $count = count($values);
1848ffe3c632Sopenharmony_ci            if ($count !== 0) {
1849ffe3c632Sopenharmony_ci                if (!GPBUtil::hasSpecialJsonMapping($this)) {
1850ffe3c632Sopenharmony_ci                    $size += 3;                              // size for "\"\":".
1851ffe3c632Sopenharmony_ci                    $size += strlen($field->getJsonName());  // size for field name
1852ffe3c632Sopenharmony_ci                }
1853ffe3c632Sopenharmony_ci                $size += 2;  // size for "{}".
1854ffe3c632Sopenharmony_ci                $size += $count - 1;                     // size for commas
1855ffe3c632Sopenharmony_ci                $getter = $field->getGetter();
1856ffe3c632Sopenharmony_ci                $map_entry = $field->getMessageType();
1857ffe3c632Sopenharmony_ci                $key_field = $map_entry->getFieldByNumber(1);
1858ffe3c632Sopenharmony_ci                $value_field = $map_entry->getFieldByNumber(2);
1859ffe3c632Sopenharmony_ci                switch ($key_field->getType()) {
1860ffe3c632Sopenharmony_ci                case GPBType::STRING:
1861ffe3c632Sopenharmony_ci                case GPBType::SFIXED64:
1862ffe3c632Sopenharmony_ci                case GPBType::INT64:
1863ffe3c632Sopenharmony_ci                case GPBType::SINT64:
1864ffe3c632Sopenharmony_ci                case GPBType::FIXED64:
1865ffe3c632Sopenharmony_ci                case GPBType::UINT64:
1866ffe3c632Sopenharmony_ci                    $additional_quote = false;
1867ffe3c632Sopenharmony_ci                    break;
1868ffe3c632Sopenharmony_ci                default:
1869ffe3c632Sopenharmony_ci                    $additional_quote = true;
1870ffe3c632Sopenharmony_ci                }
1871ffe3c632Sopenharmony_ci                foreach ($values as $key => $value) {
1872ffe3c632Sopenharmony_ci                    if ($additional_quote) {
1873ffe3c632Sopenharmony_ci                        $size += 2;  // size for ""
1874ffe3c632Sopenharmony_ci                    }
1875ffe3c632Sopenharmony_ci                    $size += $this->fieldDataOnlyJsonByteSize($key_field, $key);
1876ffe3c632Sopenharmony_ci                    $size += $this->fieldDataOnlyJsonByteSize($value_field, $value);
1877ffe3c632Sopenharmony_ci                    $size += 1;  // size for :
1878ffe3c632Sopenharmony_ci                }
1879ffe3c632Sopenharmony_ci            }
1880ffe3c632Sopenharmony_ci        } elseif ($field->isRepeated()) {
1881ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1882ffe3c632Sopenharmony_ci            $values = $this->$getter();
1883ffe3c632Sopenharmony_ci            $count = count($values);
1884ffe3c632Sopenharmony_ci            if ($count !== 0) {
1885ffe3c632Sopenharmony_ci                if (!GPBUtil::hasSpecialJsonMapping($this)) {
1886ffe3c632Sopenharmony_ci                    $size += 3;                              // size for "\"\":".
1887ffe3c632Sopenharmony_ci                    $size += strlen($field->getJsonName());  // size for field name
1888ffe3c632Sopenharmony_ci                }
1889ffe3c632Sopenharmony_ci                $size += 2;  // size for "[]".
1890ffe3c632Sopenharmony_ci                $size += $count - 1;                     // size for commas
1891ffe3c632Sopenharmony_ci                $getter = $field->getGetter();
1892ffe3c632Sopenharmony_ci                foreach ($values as $value) {
1893ffe3c632Sopenharmony_ci                    $size += $this->fieldDataOnlyJsonByteSize($field, $value);
1894ffe3c632Sopenharmony_ci                }
1895ffe3c632Sopenharmony_ci            }
1896ffe3c632Sopenharmony_ci        } elseif ($this->existField($field) || GPBUtil::hasJsonValue($this)) {
1897ffe3c632Sopenharmony_ci            if (!GPBUtil::hasSpecialJsonMapping($this)) {
1898ffe3c632Sopenharmony_ci                $size += 3;                              // size for "\"\":".
1899ffe3c632Sopenharmony_ci                $size += strlen($field->getJsonName());  // size for field name
1900ffe3c632Sopenharmony_ci            }
1901ffe3c632Sopenharmony_ci            $getter = $field->getGetter();
1902ffe3c632Sopenharmony_ci            $value = $this->$getter();
1903ffe3c632Sopenharmony_ci            $size += $this->fieldDataOnlyJsonByteSize($field, $value);
1904ffe3c632Sopenharmony_ci        }
1905ffe3c632Sopenharmony_ci        return $size;
1906ffe3c632Sopenharmony_ci    }
1907ffe3c632Sopenharmony_ci
1908ffe3c632Sopenharmony_ci    /**
1909ffe3c632Sopenharmony_ci     * @ignore
1910ffe3c632Sopenharmony_ci     */
1911ffe3c632Sopenharmony_ci    public function byteSize()
1912ffe3c632Sopenharmony_ci    {
1913ffe3c632Sopenharmony_ci        $size = 0;
1914ffe3c632Sopenharmony_ci
1915ffe3c632Sopenharmony_ci        $fields = $this->desc->getField();
1916ffe3c632Sopenharmony_ci        foreach ($fields as $field) {
1917ffe3c632Sopenharmony_ci            $size += $this->fieldByteSize($field);
1918ffe3c632Sopenharmony_ci        }
1919ffe3c632Sopenharmony_ci        $size += strlen($this->unknown);
1920ffe3c632Sopenharmony_ci        return $size;
1921ffe3c632Sopenharmony_ci    }
1922ffe3c632Sopenharmony_ci
1923ffe3c632Sopenharmony_ci    private function appendHelper($field, $append_value)
1924ffe3c632Sopenharmony_ci    {
1925ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1926ffe3c632Sopenharmony_ci        $setter = $field->getSetter();
1927ffe3c632Sopenharmony_ci
1928ffe3c632Sopenharmony_ci        $field_arr_value = $this->$getter();
1929ffe3c632Sopenharmony_ci        $field_arr_value[] = $append_value;
1930ffe3c632Sopenharmony_ci
1931ffe3c632Sopenharmony_ci        if (!is_object($field_arr_value)) {
1932ffe3c632Sopenharmony_ci            $this->$setter($field_arr_value);
1933ffe3c632Sopenharmony_ci        }
1934ffe3c632Sopenharmony_ci    }
1935ffe3c632Sopenharmony_ci
1936ffe3c632Sopenharmony_ci    private function kvUpdateHelper($field, $update_key, $update_value)
1937ffe3c632Sopenharmony_ci    {
1938ffe3c632Sopenharmony_ci        $getter = $field->getGetter();
1939ffe3c632Sopenharmony_ci        $setter = $field->getSetter();
1940ffe3c632Sopenharmony_ci
1941ffe3c632Sopenharmony_ci        $field_arr_value = $this->$getter();
1942ffe3c632Sopenharmony_ci        $field_arr_value[$update_key] = $update_value;
1943ffe3c632Sopenharmony_ci
1944ffe3c632Sopenharmony_ci        if (!is_object($field_arr_value)) {
1945ffe3c632Sopenharmony_ci            $this->$setter($field_arr_value);
1946ffe3c632Sopenharmony_ci        }
1947ffe3c632Sopenharmony_ci    }
1948ffe3c632Sopenharmony_ci
1949ffe3c632Sopenharmony_ci    /**
1950ffe3c632Sopenharmony_ci     * @ignore
1951ffe3c632Sopenharmony_ci     */
1952ffe3c632Sopenharmony_ci    public function jsonByteSize()
1953ffe3c632Sopenharmony_ci    {
1954ffe3c632Sopenharmony_ci        $size = 0;
1955ffe3c632Sopenharmony_ci        if (is_a($this, 'Google\Protobuf\Any')) {
1956ffe3c632Sopenharmony_ci            // Size for "{}".
1957ffe3c632Sopenharmony_ci            $size += 2;
1958ffe3c632Sopenharmony_ci
1959ffe3c632Sopenharmony_ci            // Size for "\"@type\":".
1960ffe3c632Sopenharmony_ci            $size += 8;
1961ffe3c632Sopenharmony_ci
1962ffe3c632Sopenharmony_ci            // Size for url. +2 for "" /.
1963ffe3c632Sopenharmony_ci            $size += strlen($this->getTypeUrl()) + 2;
1964ffe3c632Sopenharmony_ci
1965ffe3c632Sopenharmony_ci            $value_msg = $this->unpack();
1966ffe3c632Sopenharmony_ci            if (GPBUtil::hasSpecialJsonMapping($value_msg)) {
1967ffe3c632Sopenharmony_ci                // Size for "\",value\":".
1968ffe3c632Sopenharmony_ci                $size += 9;
1969ffe3c632Sopenharmony_ci                $size += $value_msg->jsonByteSize();
1970ffe3c632Sopenharmony_ci            } else {
1971ffe3c632Sopenharmony_ci                // Size for value. +1 for comma, -2 for "{}".
1972ffe3c632Sopenharmony_ci                $size += $value_msg->jsonByteSize() -1;
1973ffe3c632Sopenharmony_ci            }
1974ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\FieldMask') {
1975ffe3c632Sopenharmony_ci            $field_mask = GPBUtil::formatFieldMask($this);
1976ffe3c632Sopenharmony_ci            $size += strlen($field_mask) + 2;  // 2 for ""
1977ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\Duration') {
1978ffe3c632Sopenharmony_ci            $duration = GPBUtil::formatDuration($this) . "s";
1979ffe3c632Sopenharmony_ci            $size += strlen($duration) + 2;  // 2 for ""
1980ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\Timestamp') {
1981ffe3c632Sopenharmony_ci            $timestamp = GPBUtil::formatTimestamp($this);
1982ffe3c632Sopenharmony_ci            $timestamp = json_encode($timestamp);
1983ffe3c632Sopenharmony_ci            $size += strlen($timestamp);
1984ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\ListValue') {
1985ffe3c632Sopenharmony_ci            $field = $this->desc->getField()[1];
1986ffe3c632Sopenharmony_ci            if ($this->existField($field)) {
1987ffe3c632Sopenharmony_ci                $field_size = $this->fieldJsonByteSize($field);
1988ffe3c632Sopenharmony_ci                $size += $field_size;
1989ffe3c632Sopenharmony_ci            } else {
1990ffe3c632Sopenharmony_ci                // Size for "[]".
1991ffe3c632Sopenharmony_ci                $size += 2;
1992ffe3c632Sopenharmony_ci            }
1993ffe3c632Sopenharmony_ci        } elseif (get_class($this) === 'Google\Protobuf\Struct') {
1994ffe3c632Sopenharmony_ci            $field = $this->desc->getField()[1];
1995ffe3c632Sopenharmony_ci            if ($this->existField($field)) {
1996ffe3c632Sopenharmony_ci                $field_size = $this->fieldJsonByteSize($field);
1997ffe3c632Sopenharmony_ci                $size += $field_size;
1998ffe3c632Sopenharmony_ci            } else {
1999ffe3c632Sopenharmony_ci                // Size for "{}".
2000ffe3c632Sopenharmony_ci                $size += 2;
2001ffe3c632Sopenharmony_ci            }
2002ffe3c632Sopenharmony_ci        } else {
2003ffe3c632Sopenharmony_ci            if (!GPBUtil::hasSpecialJsonMapping($this)) {
2004ffe3c632Sopenharmony_ci                // Size for "{}".
2005ffe3c632Sopenharmony_ci                $size += 2;
2006ffe3c632Sopenharmony_ci            }
2007ffe3c632Sopenharmony_ci
2008ffe3c632Sopenharmony_ci            $fields = $this->desc->getField();
2009ffe3c632Sopenharmony_ci            $count = 0;
2010ffe3c632Sopenharmony_ci            foreach ($fields as $field) {
2011ffe3c632Sopenharmony_ci                $field_size = $this->fieldJsonByteSize($field);
2012ffe3c632Sopenharmony_ci                $size += $field_size;
2013ffe3c632Sopenharmony_ci                if ($field_size != 0) {
2014ffe3c632Sopenharmony_ci                  $count++;
2015ffe3c632Sopenharmony_ci                }
2016ffe3c632Sopenharmony_ci            }
2017ffe3c632Sopenharmony_ci            // size for comma
2018ffe3c632Sopenharmony_ci            $size += $count > 0 ? ($count - 1) : 0;
2019ffe3c632Sopenharmony_ci        }
2020ffe3c632Sopenharmony_ci        return $size;
2021ffe3c632Sopenharmony_ci    }
2022ffe3c632Sopenharmony_ci}
2023