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_cinamespace Google\Protobuf\Internal;
34ffe3c632Sopenharmony_ci
35ffe3c632Sopenharmony_ciuse Google\Protobuf\Internal\Uint64;
36ffe3c632Sopenharmony_ci
37ffe3c632Sopenharmony_ciclass CodedInputStream
38ffe3c632Sopenharmony_ci{
39ffe3c632Sopenharmony_ci
40ffe3c632Sopenharmony_ci    private $buffer;
41ffe3c632Sopenharmony_ci    private $buffer_size_after_limit;
42ffe3c632Sopenharmony_ci    private $buffer_end;
43ffe3c632Sopenharmony_ci    private $current;
44ffe3c632Sopenharmony_ci    private $current_limit;
45ffe3c632Sopenharmony_ci    private $legitimate_message_end;
46ffe3c632Sopenharmony_ci    private $recursion_budget;
47ffe3c632Sopenharmony_ci    private $recursion_limit;
48ffe3c632Sopenharmony_ci    private $total_bytes_limit;
49ffe3c632Sopenharmony_ci    private $total_bytes_read;
50ffe3c632Sopenharmony_ci
51ffe3c632Sopenharmony_ci    const MAX_VARINT_BYTES = 10;
52ffe3c632Sopenharmony_ci    const DEFAULT_RECURSION_LIMIT = 100;
53ffe3c632Sopenharmony_ci    const DEFAULT_TOTAL_BYTES_LIMIT = 33554432; // 32 << 20, 32MB
54ffe3c632Sopenharmony_ci
55ffe3c632Sopenharmony_ci    public function __construct($buffer)
56ffe3c632Sopenharmony_ci    {
57ffe3c632Sopenharmony_ci        $start = 0;
58ffe3c632Sopenharmony_ci        $end = strlen($buffer);
59ffe3c632Sopenharmony_ci        $this->buffer = $buffer;
60ffe3c632Sopenharmony_ci        $this->buffer_size_after_limit = 0;
61ffe3c632Sopenharmony_ci        $this->buffer_end = $end;
62ffe3c632Sopenharmony_ci        $this->current = $start;
63ffe3c632Sopenharmony_ci        $this->current_limit = $end;
64ffe3c632Sopenharmony_ci        $this->legitimate_message_end = false;
65ffe3c632Sopenharmony_ci        $this->recursion_budget = self::DEFAULT_RECURSION_LIMIT;
66ffe3c632Sopenharmony_ci        $this->recursion_limit = self::DEFAULT_RECURSION_LIMIT;
67ffe3c632Sopenharmony_ci        $this->total_bytes_limit = self::DEFAULT_TOTAL_BYTES_LIMIT;
68ffe3c632Sopenharmony_ci        $this->total_bytes_read = $end - $start;
69ffe3c632Sopenharmony_ci    }
70ffe3c632Sopenharmony_ci
71ffe3c632Sopenharmony_ci    private function advance($amount)
72ffe3c632Sopenharmony_ci    {
73ffe3c632Sopenharmony_ci        $this->current += $amount;
74ffe3c632Sopenharmony_ci    }
75ffe3c632Sopenharmony_ci
76ffe3c632Sopenharmony_ci    public function bufferSize()
77ffe3c632Sopenharmony_ci    {
78ffe3c632Sopenharmony_ci        return $this->buffer_end - $this->current;
79ffe3c632Sopenharmony_ci    }
80ffe3c632Sopenharmony_ci
81ffe3c632Sopenharmony_ci    public function current()
82ffe3c632Sopenharmony_ci    {
83ffe3c632Sopenharmony_ci        return $this->total_bytes_read -
84ffe3c632Sopenharmony_ci            ($this->buffer_end - $this->current +
85ffe3c632Sopenharmony_ci            $this->buffer_size_after_limit);
86ffe3c632Sopenharmony_ci    }
87ffe3c632Sopenharmony_ci
88ffe3c632Sopenharmony_ci    public function substr($start, $end)
89ffe3c632Sopenharmony_ci    {
90ffe3c632Sopenharmony_ci        return substr($this->buffer, $start, $end - $start);
91ffe3c632Sopenharmony_ci    }
92ffe3c632Sopenharmony_ci
93ffe3c632Sopenharmony_ci    private function recomputeBufferLimits()
94ffe3c632Sopenharmony_ci    {
95ffe3c632Sopenharmony_ci        $this->buffer_end += $this->buffer_size_after_limit;
96ffe3c632Sopenharmony_ci        $closest_limit = min($this->current_limit, $this->total_bytes_limit);
97ffe3c632Sopenharmony_ci        if ($closest_limit < $this->total_bytes_read) {
98ffe3c632Sopenharmony_ci            // The limit position is in the current buffer.  We must adjust the
99ffe3c632Sopenharmony_ci            // buffer size accordingly.
100ffe3c632Sopenharmony_ci            $this->buffer_size_after_limit = $this->total_bytes_read -
101ffe3c632Sopenharmony_ci                $closest_limit;
102ffe3c632Sopenharmony_ci            $this->buffer_end -= $this->buffer_size_after_limit;
103ffe3c632Sopenharmony_ci        } else {
104ffe3c632Sopenharmony_ci            $this->buffer_size_after_limit = 0;
105ffe3c632Sopenharmony_ci        }
106ffe3c632Sopenharmony_ci    }
107ffe3c632Sopenharmony_ci
108ffe3c632Sopenharmony_ci    private function consumedEntireMessage()
109ffe3c632Sopenharmony_ci    {
110ffe3c632Sopenharmony_ci        return $this->legitimate_message_end;
111ffe3c632Sopenharmony_ci    }
112ffe3c632Sopenharmony_ci
113ffe3c632Sopenharmony_ci    /**
114ffe3c632Sopenharmony_ci     * Read uint32 into $var. Advance buffer with consumed bytes. If the
115ffe3c632Sopenharmony_ci     * contained varint is larger than 32 bits, discard the high order bits.
116ffe3c632Sopenharmony_ci     * @param $var.
117ffe3c632Sopenharmony_ci     */
118ffe3c632Sopenharmony_ci    public function readVarint32(&$var)
119ffe3c632Sopenharmony_ci    {
120ffe3c632Sopenharmony_ci        if (!$this->readVarint64($var)) {
121ffe3c632Sopenharmony_ci            return false;
122ffe3c632Sopenharmony_ci        }
123ffe3c632Sopenharmony_ci
124ffe3c632Sopenharmony_ci        if (PHP_INT_SIZE == 4) {
125ffe3c632Sopenharmony_ci            $var = bcmod($var, 4294967296);
126ffe3c632Sopenharmony_ci        } else {
127ffe3c632Sopenharmony_ci            $var &= 0xFFFFFFFF;
128ffe3c632Sopenharmony_ci        }
129ffe3c632Sopenharmony_ci
130ffe3c632Sopenharmony_ci        // Convert large uint32 to int32.
131ffe3c632Sopenharmony_ci        if ($var > 0x7FFFFFFF) {
132ffe3c632Sopenharmony_ci            if (PHP_INT_SIZE === 8) {
133ffe3c632Sopenharmony_ci                $var = $var | (0xFFFFFFFF << 32);
134ffe3c632Sopenharmony_ci            } else {
135ffe3c632Sopenharmony_ci                $var = bcsub($var, 4294967296);
136ffe3c632Sopenharmony_ci            }
137ffe3c632Sopenharmony_ci        }
138ffe3c632Sopenharmony_ci
139ffe3c632Sopenharmony_ci        $var = intval($var);
140ffe3c632Sopenharmony_ci        return true;
141ffe3c632Sopenharmony_ci    }
142ffe3c632Sopenharmony_ci
143ffe3c632Sopenharmony_ci    /**
144ffe3c632Sopenharmony_ci     * Read Uint64 into $var. Advance buffer with consumed bytes.
145ffe3c632Sopenharmony_ci     * @param $var.
146ffe3c632Sopenharmony_ci     */
147ffe3c632Sopenharmony_ci    public function readVarint64(&$var)
148ffe3c632Sopenharmony_ci    {
149ffe3c632Sopenharmony_ci        $count = 0;
150ffe3c632Sopenharmony_ci
151ffe3c632Sopenharmony_ci        if (PHP_INT_SIZE == 4) {
152ffe3c632Sopenharmony_ci            $high = 0;
153ffe3c632Sopenharmony_ci            $low = 0;
154ffe3c632Sopenharmony_ci            $b = 0;
155ffe3c632Sopenharmony_ci
156ffe3c632Sopenharmony_ci            do {
157ffe3c632Sopenharmony_ci                if ($this->current === $this->buffer_end) {
158ffe3c632Sopenharmony_ci                    return false;
159ffe3c632Sopenharmony_ci                }
160ffe3c632Sopenharmony_ci                if ($count === self::MAX_VARINT_BYTES) {
161ffe3c632Sopenharmony_ci                    return false;
162ffe3c632Sopenharmony_ci                }
163ffe3c632Sopenharmony_ci                $b = ord($this->buffer[$this->current]);
164ffe3c632Sopenharmony_ci                $bits = 7 * $count;
165ffe3c632Sopenharmony_ci                if ($bits >= 32) {
166ffe3c632Sopenharmony_ci                    $high |= (($b & 0x7F) << ($bits - 32));
167ffe3c632Sopenharmony_ci                } else if ($bits > 25){
168ffe3c632Sopenharmony_ci                    // $bits is 28 in this case.
169ffe3c632Sopenharmony_ci                    $low |= (($b & 0x7F) << 28);
170ffe3c632Sopenharmony_ci                    $high = ($b & 0x7F) >> 4;
171ffe3c632Sopenharmony_ci                } else {
172ffe3c632Sopenharmony_ci                    $low |= (($b & 0x7F) << $bits);
173ffe3c632Sopenharmony_ci                }
174ffe3c632Sopenharmony_ci
175ffe3c632Sopenharmony_ci                $this->advance(1);
176ffe3c632Sopenharmony_ci                $count += 1;
177ffe3c632Sopenharmony_ci            } while ($b & 0x80);
178ffe3c632Sopenharmony_ci
179ffe3c632Sopenharmony_ci            $var = GPBUtil::combineInt32ToInt64($high, $low);
180ffe3c632Sopenharmony_ci            if (bccomp($var, 0) < 0) {
181ffe3c632Sopenharmony_ci                $var = bcadd($var, "18446744073709551616");
182ffe3c632Sopenharmony_ci            }
183ffe3c632Sopenharmony_ci        } else {
184ffe3c632Sopenharmony_ci            $result = 0;
185ffe3c632Sopenharmony_ci            $shift = 0;
186ffe3c632Sopenharmony_ci
187ffe3c632Sopenharmony_ci            do {
188ffe3c632Sopenharmony_ci                if ($this->current === $this->buffer_end) {
189ffe3c632Sopenharmony_ci                    return false;
190ffe3c632Sopenharmony_ci                }
191ffe3c632Sopenharmony_ci                if ($count === self::MAX_VARINT_BYTES) {
192ffe3c632Sopenharmony_ci                    return false;
193ffe3c632Sopenharmony_ci                }
194ffe3c632Sopenharmony_ci
195ffe3c632Sopenharmony_ci                $byte = ord($this->buffer[$this->current]);
196ffe3c632Sopenharmony_ci                $result |= ($byte & 0x7f) << $shift;
197ffe3c632Sopenharmony_ci                $shift += 7;
198ffe3c632Sopenharmony_ci                $this->advance(1);
199ffe3c632Sopenharmony_ci                $count += 1;
200ffe3c632Sopenharmony_ci            } while ($byte > 0x7f);
201ffe3c632Sopenharmony_ci
202ffe3c632Sopenharmony_ci            $var = $result;
203ffe3c632Sopenharmony_ci        }
204ffe3c632Sopenharmony_ci
205ffe3c632Sopenharmony_ci        return true;
206ffe3c632Sopenharmony_ci    }
207ffe3c632Sopenharmony_ci
208ffe3c632Sopenharmony_ci    /**
209ffe3c632Sopenharmony_ci     * Read int into $var. If the result is larger than the largest integer, $var
210ffe3c632Sopenharmony_ci     * will be -1. Advance buffer with consumed bytes.
211ffe3c632Sopenharmony_ci     * @param $var.
212ffe3c632Sopenharmony_ci     */
213ffe3c632Sopenharmony_ci    public function readVarintSizeAsInt(&$var)
214ffe3c632Sopenharmony_ci    {
215ffe3c632Sopenharmony_ci        if (!$this->readVarint64($var)) {
216ffe3c632Sopenharmony_ci            return false;
217ffe3c632Sopenharmony_ci        }
218ffe3c632Sopenharmony_ci        $var = (int)$var;
219ffe3c632Sopenharmony_ci        return true;
220ffe3c632Sopenharmony_ci    }
221ffe3c632Sopenharmony_ci
222ffe3c632Sopenharmony_ci    /**
223ffe3c632Sopenharmony_ci     * Read 32-bit unsigned integer to $var. If the buffer has less than 4 bytes,
224ffe3c632Sopenharmony_ci     * return false. Advance buffer with consumed bytes.
225ffe3c632Sopenharmony_ci     * @param $var.
226ffe3c632Sopenharmony_ci     */
227ffe3c632Sopenharmony_ci    public function readLittleEndian32(&$var)
228ffe3c632Sopenharmony_ci    {
229ffe3c632Sopenharmony_ci        $data = null;
230ffe3c632Sopenharmony_ci        if (!$this->readRaw(4, $data)) {
231ffe3c632Sopenharmony_ci            return false;
232ffe3c632Sopenharmony_ci        }
233ffe3c632Sopenharmony_ci        $var = unpack('V', $data);
234ffe3c632Sopenharmony_ci        $var = $var[1];
235ffe3c632Sopenharmony_ci        return true;
236ffe3c632Sopenharmony_ci    }
237ffe3c632Sopenharmony_ci
238ffe3c632Sopenharmony_ci    /**
239ffe3c632Sopenharmony_ci     * Read 64-bit unsigned integer to $var. If the buffer has less than 8 bytes,
240ffe3c632Sopenharmony_ci     * return false. Advance buffer with consumed bytes.
241ffe3c632Sopenharmony_ci     * @param $var.
242ffe3c632Sopenharmony_ci     */
243ffe3c632Sopenharmony_ci    public function readLittleEndian64(&$var)
244ffe3c632Sopenharmony_ci    {
245ffe3c632Sopenharmony_ci        $data = null;
246ffe3c632Sopenharmony_ci        if (!$this->readRaw(4, $data)) {
247ffe3c632Sopenharmony_ci            return false;
248ffe3c632Sopenharmony_ci        }
249ffe3c632Sopenharmony_ci        $low = unpack('V', $data)[1];
250ffe3c632Sopenharmony_ci        if (!$this->readRaw(4, $data)) {
251ffe3c632Sopenharmony_ci            return false;
252ffe3c632Sopenharmony_ci        }
253ffe3c632Sopenharmony_ci        $high = unpack('V', $data)[1];
254ffe3c632Sopenharmony_ci        if (PHP_INT_SIZE == 4) {
255ffe3c632Sopenharmony_ci            $var = GPBUtil::combineInt32ToInt64($high, $low);
256ffe3c632Sopenharmony_ci        } else {
257ffe3c632Sopenharmony_ci            $var = ($high << 32) | $low;
258ffe3c632Sopenharmony_ci        }
259ffe3c632Sopenharmony_ci        return true;
260ffe3c632Sopenharmony_ci    }
261ffe3c632Sopenharmony_ci
262ffe3c632Sopenharmony_ci    /**
263ffe3c632Sopenharmony_ci     * Read tag into $var. Advance buffer with consumed bytes.
264ffe3c632Sopenharmony_ci     * @param $var.
265ffe3c632Sopenharmony_ci     */
266ffe3c632Sopenharmony_ci    public function readTag()
267ffe3c632Sopenharmony_ci    {
268ffe3c632Sopenharmony_ci        if ($this->current === $this->buffer_end) {
269ffe3c632Sopenharmony_ci            // Make sure that it failed due to EOF, not because we hit
270ffe3c632Sopenharmony_ci            // total_bytes_limit, which, unlike normal limits, is not a valid
271ffe3c632Sopenharmony_ci            // place to end a message.
272ffe3c632Sopenharmony_ci            $current_position = $this->total_bytes_read -
273ffe3c632Sopenharmony_ci                $this->buffer_size_after_limit;
274ffe3c632Sopenharmony_ci            if ($current_position >= $this->total_bytes_limit) {
275ffe3c632Sopenharmony_ci                // Hit total_bytes_limit_.  But if we also hit the normal limit,
276ffe3c632Sopenharmony_ci                // we're still OK.
277ffe3c632Sopenharmony_ci                $this->legitimate_message_end =
278ffe3c632Sopenharmony_ci                    ($this->current_limit === $this->total_bytes_limit);
279ffe3c632Sopenharmony_ci            } else {
280ffe3c632Sopenharmony_ci                $this->legitimate_message_end = true;
281ffe3c632Sopenharmony_ci            }
282ffe3c632Sopenharmony_ci            return 0;
283ffe3c632Sopenharmony_ci        }
284ffe3c632Sopenharmony_ci
285ffe3c632Sopenharmony_ci        $result = 0;
286ffe3c632Sopenharmony_ci        // The largest tag is 2^29 - 1, which can be represented by int32.
287ffe3c632Sopenharmony_ci        $success = $this->readVarint32($result);
288ffe3c632Sopenharmony_ci        if ($success) {
289ffe3c632Sopenharmony_ci            return $result;
290ffe3c632Sopenharmony_ci        } else {
291ffe3c632Sopenharmony_ci            return 0;
292ffe3c632Sopenharmony_ci        }
293ffe3c632Sopenharmony_ci    }
294ffe3c632Sopenharmony_ci
295ffe3c632Sopenharmony_ci    public function readRaw($size, &$buffer)
296ffe3c632Sopenharmony_ci    {
297ffe3c632Sopenharmony_ci        $current_buffer_size = 0;
298ffe3c632Sopenharmony_ci        if ($this->bufferSize() < $size) {
299ffe3c632Sopenharmony_ci            return false;
300ffe3c632Sopenharmony_ci        }
301ffe3c632Sopenharmony_ci
302ffe3c632Sopenharmony_ci        if ($size === 0) {
303ffe3c632Sopenharmony_ci          $buffer = "";
304ffe3c632Sopenharmony_ci        } else {
305ffe3c632Sopenharmony_ci          $buffer = substr($this->buffer, $this->current, $size);
306ffe3c632Sopenharmony_ci          $this->advance($size);
307ffe3c632Sopenharmony_ci        }
308ffe3c632Sopenharmony_ci
309ffe3c632Sopenharmony_ci        return true;
310ffe3c632Sopenharmony_ci    }
311ffe3c632Sopenharmony_ci
312ffe3c632Sopenharmony_ci    /* Places a limit on the number of bytes that the stream may read, starting
313ffe3c632Sopenharmony_ci     * from the current position.  Once the stream hits this limit, it will act
314ffe3c632Sopenharmony_ci     * like the end of the input has been reached until popLimit() is called.
315ffe3c632Sopenharmony_ci     *
316ffe3c632Sopenharmony_ci     * As the names imply, the stream conceptually has a stack of limits.  The
317ffe3c632Sopenharmony_ci     * shortest limit on the stack is always enforced, even if it is not the top
318ffe3c632Sopenharmony_ci     * limit.
319ffe3c632Sopenharmony_ci     *
320ffe3c632Sopenharmony_ci     * The value returned by pushLimit() is opaque to the caller, and must be
321ffe3c632Sopenharmony_ci     * passed unchanged to the corresponding call to popLimit().
322ffe3c632Sopenharmony_ci     *
323ffe3c632Sopenharmony_ci     * @param integer $byte_limit
324ffe3c632Sopenharmony_ci     * @throws \Exception Fail to push limit.
325ffe3c632Sopenharmony_ci     */
326ffe3c632Sopenharmony_ci    public function pushLimit($byte_limit)
327ffe3c632Sopenharmony_ci    {
328ffe3c632Sopenharmony_ci        // Current position relative to the beginning of the stream.
329ffe3c632Sopenharmony_ci        $current_position = $this->current();
330ffe3c632Sopenharmony_ci        $old_limit = $this->current_limit;
331ffe3c632Sopenharmony_ci
332ffe3c632Sopenharmony_ci        // security: byte_limit is possibly evil, so check for negative values
333ffe3c632Sopenharmony_ci        // and overflow.
334ffe3c632Sopenharmony_ci        if ($byte_limit >= 0 &&
335ffe3c632Sopenharmony_ci            $byte_limit <= PHP_INT_MAX - $current_position &&
336ffe3c632Sopenharmony_ci            $byte_limit <= $this->current_limit - $current_position) {
337ffe3c632Sopenharmony_ci            $this->current_limit = $current_position + $byte_limit;
338ffe3c632Sopenharmony_ci            $this->recomputeBufferLimits();
339ffe3c632Sopenharmony_ci        } else {
340ffe3c632Sopenharmony_ci            throw new GPBDecodeException("Fail to push limit.");
341ffe3c632Sopenharmony_ci        }
342ffe3c632Sopenharmony_ci
343ffe3c632Sopenharmony_ci        return $old_limit;
344ffe3c632Sopenharmony_ci    }
345ffe3c632Sopenharmony_ci
346ffe3c632Sopenharmony_ci    /* The limit passed in is actually the *old* limit, which we returned from
347ffe3c632Sopenharmony_ci     * PushLimit().
348ffe3c632Sopenharmony_ci     *
349ffe3c632Sopenharmony_ci     * @param integer $byte_limit
350ffe3c632Sopenharmony_ci     */
351ffe3c632Sopenharmony_ci    public function popLimit($byte_limit)
352ffe3c632Sopenharmony_ci    {
353ffe3c632Sopenharmony_ci        $this->current_limit = $byte_limit;
354ffe3c632Sopenharmony_ci        $this->recomputeBufferLimits();
355ffe3c632Sopenharmony_ci        // We may no longer be at a legitimate message end.  ReadTag() needs to
356ffe3c632Sopenharmony_ci        // be called again to find out.
357ffe3c632Sopenharmony_ci        $this->legitimate_message_end = false;
358ffe3c632Sopenharmony_ci    }
359ffe3c632Sopenharmony_ci
360ffe3c632Sopenharmony_ci    public function incrementRecursionDepthAndPushLimit(
361ffe3c632Sopenharmony_ci        $byte_limit, &$old_limit, &$recursion_budget)
362ffe3c632Sopenharmony_ci    {
363ffe3c632Sopenharmony_ci        $old_limit = $this->pushLimit($byte_limit);
364ffe3c632Sopenharmony_ci        $recursion_limit = --$this->recursion_limit;
365ffe3c632Sopenharmony_ci    }
366ffe3c632Sopenharmony_ci
367ffe3c632Sopenharmony_ci    public function decrementRecursionDepthAndPopLimit($byte_limit)
368ffe3c632Sopenharmony_ci    {
369ffe3c632Sopenharmony_ci        $result = $this->consumedEntireMessage();
370ffe3c632Sopenharmony_ci        $this->popLimit($byte_limit);
371ffe3c632Sopenharmony_ci        ++$this->recursion_budget;
372ffe3c632Sopenharmony_ci        return $result;
373ffe3c632Sopenharmony_ci    }
374ffe3c632Sopenharmony_ci
375ffe3c632Sopenharmony_ci    public function bytesUntilLimit()
376ffe3c632Sopenharmony_ci    {
377ffe3c632Sopenharmony_ci        if ($this->current_limit === PHP_INT_MAX) {
378ffe3c632Sopenharmony_ci            return -1;
379ffe3c632Sopenharmony_ci        }
380ffe3c632Sopenharmony_ci        return $this->current_limit - $this->current;
381ffe3c632Sopenharmony_ci    }
382ffe3c632Sopenharmony_ci}
383