1<?php
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc.  All rights reserved.
5// https://developers.google.com/protocol-buffers/
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11//     * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//     * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17//     * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33namespace Google\Protobuf\Internal;
34
35class CodedOutputStream
36{
37
38    private $buffer;
39    private $buffer_size;
40    private $current;
41
42    const MAX_VARINT64_BYTES = 10;
43
44    public function __construct($size)
45    {
46        $this->current = 0;
47        $this->buffer_size = $size;
48        $this->buffer = str_repeat(chr(0), $this->buffer_size);
49    }
50
51    public function getData()
52    {
53        return $this->buffer;
54    }
55
56    public function writeVarint32($value, $trim)
57    {
58        $bytes = str_repeat(chr(0), self::MAX_VARINT64_BYTES);
59        $size = self::writeVarintToArray($value, $bytes, $trim);
60        return $this->writeRaw($bytes, $size);
61    }
62
63    public function writeVarint64($value)
64    {
65        $bytes = str_repeat(chr(0), self::MAX_VARINT64_BYTES);
66        $size = self::writeVarintToArray($value, $bytes);
67        return $this->writeRaw($bytes, $size);
68    }
69
70    public function writeLittleEndian32($value)
71    {
72        $bytes = str_repeat(chr(0), 4);
73        $size = self::writeLittleEndian32ToArray($value, $bytes);
74        return $this->writeRaw($bytes, $size);
75    }
76
77    public function writeLittleEndian64($value)
78    {
79        $bytes = str_repeat(chr(0), 8);
80        $size = self::writeLittleEndian64ToArray($value, $bytes);
81        return $this->writeRaw($bytes, $size);
82    }
83
84    public function writeTag($tag)
85    {
86        return $this->writeVarint32($tag, true);
87    }
88
89    public function writeRaw($data, $size)
90    {
91        if ($this->buffer_size < $size) {
92            trigger_error("Output stream doesn't have enough buffer.");
93            return false;
94        }
95
96        for ($i = 0; $i < $size; $i++) {
97            $this->buffer[$this->current] = $data[$i];
98            $this->current++;
99            $this->buffer_size--;
100        }
101        return true;
102    }
103
104    public static function writeVarintToArray($value, &$buffer, $trim = false)
105    {
106        $current = 0;
107
108        $high = 0;
109        $low = 0;
110        if (PHP_INT_SIZE == 4) {
111            GPBUtil::divideInt64ToInt32($value, $high, $low, $trim);
112        } else {
113            $low = $value;
114        }
115
116        while (($low >= 0x80 || $low < 0) || $high != 0) {
117            $buffer[$current] = chr($low | 0x80);
118            $value = ($value >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7));
119            $carry = ($high & 0x7F) << ((PHP_INT_SIZE << 3) - 7);
120            $high = ($high >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7));
121            $low = (($low >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7)) | $carry);
122            $current++;
123        }
124        $buffer[$current] = chr($low);
125        return $current + 1;
126    }
127
128    private static function writeLittleEndian32ToArray($value, &$buffer)
129    {
130        $buffer[0] = chr($value & 0x000000FF);
131        $buffer[1] = chr(($value >> 8) & 0x000000FF);
132        $buffer[2] = chr(($value >> 16) & 0x000000FF);
133        $buffer[3] = chr(($value >> 24) & 0x000000FF);
134        return 4;
135    }
136
137    private static function writeLittleEndian64ToArray($value, &$buffer)
138    {
139        $high = 0;
140        $low = 0;
141        if (PHP_INT_SIZE == 4) {
142            GPBUtil::divideInt64ToInt32($value, $high, $low);
143        } else {
144            $low = $value & 0xFFFFFFFF;
145            $high = ($value >> 32) & 0xFFFFFFFF;
146        }
147
148        $buffer[0] = chr($low & 0x000000FF);
149        $buffer[1] = chr(($low >> 8) & 0x000000FF);
150        $buffer[2] = chr(($low >> 16) & 0x000000FF);
151        $buffer[3] = chr(($low >> 24) & 0x000000FF);
152        $buffer[4] = chr($high & 0x000000FF);
153        $buffer[5] = chr(($high >> 8) & 0x000000FF);
154        $buffer[6] = chr(($high >> 16) & 0x000000FF);
155        $buffer[7] = chr(($high >> 24) & 0x000000FF);
156        return 8;
157    }
158
159}
160