blob: 31bbbf9d0ca1f66f9b9980a8da9dafc2a6ed64cb [file] [log] [blame]
Gavin McDonald0b75e1a2010-10-28 02:12:01 +00001<?php
2/*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 * @package thrift.protocol
21 */
22
23include_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
24
25/**
26 * Binary implementation of the Thrift protocol.
27 *
28 */
29class TBinaryProtocol extends TProtocol {
30
31 const VERSION_MASK = 0xffff0000;
32 const VERSION_1 = 0x80010000;
33
34 protected $strictRead_ = false;
35 protected $strictWrite_ = true;
36
37 public function __construct($trans, $strictRead=false, $strictWrite=true) {
38 parent::__construct($trans);
39 $this->strictRead_ = $strictRead;
40 $this->strictWrite_ = $strictWrite;
41 }
42
43 public function writeMessageBegin($name, $type, $seqid) {
44 if ($this->strictWrite_) {
45 $version = self::VERSION_1 | $type;
46 return
47 $this->writeI32($version) +
48 $this->writeString($name) +
49 $this->writeI32($seqid);
50 } else {
51 return
52 $this->writeString($name) +
53 $this->writeByte($type) +
54 $this->writeI32($seqid);
55 }
56 }
57
58 public function writeMessageEnd() {
59 return 0;
60 }
61
62 public function writeStructBegin($name) {
63 return 0;
64 }
65
66 public function writeStructEnd() {
67 return 0;
68 }
69
70 public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
71 return
72 $this->writeByte($fieldType) +
73 $this->writeI16($fieldId);
74 }
75
76 public function writeFieldEnd() {
77 return 0;
78 }
79
80 public function writeFieldStop() {
81 return
82 $this->writeByte(TType::STOP);
83 }
84
85 public function writeMapBegin($keyType, $valType, $size) {
86 return
87 $this->writeByte($keyType) +
88 $this->writeByte($valType) +
89 $this->writeI32($size);
90 }
91
92 public function writeMapEnd() {
93 return 0;
94 }
95
96 public function writeListBegin($elemType, $size) {
97 return
98 $this->writeByte($elemType) +
99 $this->writeI32($size);
100 }
101
102 public function writeListEnd() {
103 return 0;
104 }
105
106 public function writeSetBegin($elemType, $size) {
107 return
108 $this->writeByte($elemType) +
109 $this->writeI32($size);
110 }
111
112 public function writeSetEnd() {
113 return 0;
114 }
115
116 public function writeBool($value) {
117 $data = pack('c', $value ? 1 : 0);
118 $this->trans_->write($data, 1);
119 return 1;
120 }
121
122 public function writeByte($value) {
123 $data = pack('c', $value);
124 $this->trans_->write($data, 1);
125 return 1;
126 }
127
128 public function writeI16($value) {
129 $data = pack('n', $value);
130 $this->trans_->write($data, 2);
131 return 2;
132 }
133
134 public function writeI32($value) {
135 $data = pack('N', $value);
136 $this->trans_->write($data, 4);
137 return 4;
138 }
139
140 public function writeI64($value) {
141 // If we are on a 32bit architecture we have to explicitly deal with
142 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
143 // as signed and any int over 2^31 - 1 as a float
144 if (PHP_INT_SIZE == 4) {
145 $neg = $value < 0;
146
147 if ($neg) {
148 $value *= -1;
149 }
150
151 $hi = (int)($value / 4294967296);
152 $lo = (int)$value;
153
154 if ($neg) {
155 $hi = ~$hi;
156 $lo = ~$lo;
157 if (($lo & (int)0xffffffff) == (int)0xffffffff) {
158 $lo = 0;
159 $hi++;
160 } else {
161 $lo++;
162 }
163 }
164 $data = pack('N2', $hi, $lo);
165
166 } else {
167 $hi = $value >> 32;
168 $lo = $value & 0xFFFFFFFF;
169 $data = pack('N2', $hi, $lo);
170 }
171
172 $this->trans_->write($data, 8);
173 return 8;
174 }
175
176 public function writeDouble($value) {
177 $data = pack('d', $value);
178 $this->trans_->write(strrev($data), 8);
179 return 8;
180 }
181
182 public function writeString($value) {
183 $len = strlen($value);
184 $result = $this->writeI32($len);
185 if ($len) {
186 $this->trans_->write($value, $len);
187 }
188 return $result + $len;
189 }
190
191 public function readMessageBegin(&$name, &$type, &$seqid) {
192 $result = $this->readI32($sz);
193 if ($sz < 0) {
194 $version = (int) ($sz & self::VERSION_MASK);
195 if ($version != (int) self::VERSION_1) {
196 throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
197 }
198 $type = $sz & 0x000000ff;
199 $result +=
200 $this->readString($name) +
201 $this->readI32($seqid);
202 } else {
203 if ($this->strictRead_) {
204 throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
205 } else {
206 // Handle pre-versioned input
207 $name = $this->trans_->readAll($sz);
208 $result +=
209 $sz +
210 $this->readByte($type) +
211 $this->readI32($seqid);
212 }
213 }
214 return $result;
215 }
216
217 public function readMessageEnd() {
218 return 0;
219 }
220
221 public function readStructBegin(&$name) {
222 $name = '';
223 return 0;
224 }
225
226 public function readStructEnd() {
227 return 0;
228 }
229
230 public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
231 $result = $this->readByte($fieldType);
232 if ($fieldType == TType::STOP) {
233 $fieldId = 0;
234 return $result;
235 }
236 $result += $this->readI16($fieldId);
237 return $result;
238 }
239
240 public function readFieldEnd() {
241 return 0;
242 }
243
244 public function readMapBegin(&$keyType, &$valType, &$size) {
245 return
246 $this->readByte($keyType) +
247 $this->readByte($valType) +
248 $this->readI32($size);
249 }
250
251 public function readMapEnd() {
252 return 0;
253 }
254
255 public function readListBegin(&$elemType, &$size) {
256 return
257 $this->readByte($elemType) +
258 $this->readI32($size);
259 }
260
261 public function readListEnd() {
262 return 0;
263 }
264
265 public function readSetBegin(&$elemType, &$size) {
266 return
267 $this->readByte($elemType) +
268 $this->readI32($size);
269 }
270
271 public function readSetEnd() {
272 return 0;
273 }
274
275 public function readBool(&$value) {
276 $data = $this->trans_->readAll(1);
277 $arr = unpack('c', $data);
278 $value = $arr[1] == 1;
279 return 1;
280 }
281
282 public function readByte(&$value) {
283 $data = $this->trans_->readAll(1);
284 $arr = unpack('c', $data);
285 $value = $arr[1];
286 return 1;
287 }
288
289 public function readI16(&$value) {
290 $data = $this->trans_->readAll(2);
291 $arr = unpack('n', $data);
292 $value = $arr[1];
293 if ($value > 0x7fff) {
294 $value = 0 - (($value - 1) ^ 0xffff);
295 }
296 return 2;
297 }
298
299 public function readI32(&$value) {
300 $data = $this->trans_->readAll(4);
301 $arr = unpack('N', $data);
302 $value = $arr[1];
303 if ($value > 0x7fffffff) {
304 $value = 0 - (($value - 1) ^ 0xffffffff);
305 }
306 return 4;
307 }
308
309 public function readI64(&$value) {
310 $data = $this->trans_->readAll(8);
311
312 $arr = unpack('N2', $data);
313
314 // If we are on a 32bit architecture we have to explicitly deal with
315 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
316 // as signed and any int over 2^31 - 1 as a float
317 if (PHP_INT_SIZE == 4) {
318
319 $hi = $arr[1];
320 $lo = $arr[2];
321 $isNeg = $hi < 0;
322
323 // Check for a negative
324 if ($isNeg) {
325 $hi = ~$hi & (int)0xffffffff;
326 $lo = ~$lo & (int)0xffffffff;
327
328 if ($lo == (int)0xffffffff) {
329 $hi++;
330 $lo = 0;
331 } else {
332 $lo++;
333 }
334 }
335
336 // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
337 // explicitly below
338
339 if ($hi & (int)0x80000000) {
340 $hi &= (int)0x7fffffff;
341 $hi += 0x80000000;
342 }
343
344 if ($lo & (int)0x80000000) {
345 $lo &= (int)0x7fffffff;
346 $lo += 0x80000000;
347 }
348
349 $value = $hi * 4294967296 + $lo;
350
351 if ($isNeg) {
352 $value = 0 - $value;
353 }
354 } else {
355
356 // Upcast negatives in LSB bit
357 if ($arr[2] & 0x80000000) {
358 $arr[2] = $arr[2] & 0xffffffff;
359 }
360
361 // Check for a negative
362 if ($arr[1] & 0x80000000) {
363 $arr[1] = $arr[1] & 0xffffffff;
364 $arr[1] = $arr[1] ^ 0xffffffff;
365 $arr[2] = $arr[2] ^ 0xffffffff;
366 $value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
367 } else {
368 $value = $arr[1]*4294967296 + $arr[2];
369 }
370 }
371
372 return 8;
373 }
374
375 public function readDouble(&$value) {
376 $data = strrev($this->trans_->readAll(8));
377 $arr = unpack('d', $data);
378 $value = $arr[1];
379 return 8;
380 }
381
382 public function readString(&$value) {
383 $result = $this->readI32($len);
384 if ($len) {
385 $value = $this->trans_->readAll($len);
386 } else {
387 $value = '';
388 }
389 return $result + $len;
390 }
391}
392
393/**
394 * Binary Protocol Factory
395 */
396class TBinaryProtocolFactory implements TProtocolFactory {
397 private $strictRead_ = false;
398 private $strictWrite_ = false;
399
400 public function __construct($strictRead=false, $strictWrite=false) {
401 $this->strictRead_ = $strictRead;
402 $this->strictWrite_ = $strictWrite;
403 }
404
405 public function getProtocol($trans) {
406 return new TBinaryProtocol($trans, $this->strictRead, $this->strictWrite);
407 }
408}
409
410/**
411 * Accelerated binary protocol: used in conjunction with the thrift_protocol
412 * extension for faster deserialization
413 */
414class TBinaryProtocolAccelerated extends TBinaryProtocol {
415 public function __construct($trans, $strictRead=false, $strictWrite=true) {
416 // If the transport doesn't implement putBack, wrap it in a
417 // TBufferedTransport (which does)
418 if (!method_exists($trans, 'putBack')) {
419 $trans = new TBufferedTransport($trans);
420 }
421 parent::__construct($trans, $strictRead, $strictWrite);
422 }
423 public function isStrictRead() {
424 return $this->strictRead_;
425 }
426 public function isStrictWrite() {
427 return $this->strictWrite_;
428 }
429}
430
431?>