blob: 63b10bfbea30e146f5a87e5bdce7dd376fe6ff14 [file] [log] [blame]
Mark Slee4902c052007-03-01 00:31:30 +00001<?php
dweatherford80940b72007-10-31 23:30:56 +00002include_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
Mark Slee4902c052007-03-01 00:31:30 +00003
4/**
5 * Copyright (c) 2006- Facebook
6 * Distributed under the Thrift Software License
7 *
8 * See accompanying file LICENSE or visit the Thrift site at:
9 * http://developers.facebook.com/thrift/
10 *
11 * @package thrift.protocol
12 * @author Mark Slee <mcslee@facebook.com>
13 */
Mark Slee6e536442006-06-30 18:28:50 +000014
Mark Slee6e536442006-06-30 18:28:50 +000015/**
16 * Binary implementation of the Thrift protocol.
17 *
Mark Slee6e536442006-06-30 18:28:50 +000018 * @author Mark Slee <mcslee@facebook.com>
Mark Sleeadde9682007-03-01 00:37:56 +000019 * @author Marc Kwiatkowski <marc@facebook.com>
Mark Slee6e536442006-06-30 18:28:50 +000020 */
21class TBinaryProtocol extends TProtocol {
22
Mark Slee808454e2007-06-20 21:51:57 +000023 const VERSION_MASK = 0xffff0000;
24 const VERSION_1 = 0x80010000;
25
26 private $strictRead_ = false;
27 private $strictWrite_ = true;
28
29 public function __construct($trans, $strictRead=false, $strictWrite=true) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +000030 parent::__construct($trans);
Mark Slee808454e2007-06-20 21:51:57 +000031 $this->strictRead_ = $strictRead;
32 $this->strictWrite_ = $strictWrite;
Mark Slee5f8237d2006-10-26 04:57:03 +000033 }
34
35 public function writeMessageBegin($name, $type, $seqid) {
Mark Slee808454e2007-06-20 21:51:57 +000036 if ($this->strictWrite_) {
37 $version = self::VERSION_1 | $type;
38 return
39 $this->writeI32($version) +
40 $this->writeString($name) +
41 $this->writeI32($seqid);
42 } else {
43 return
44 $this->writeString($name) +
45 $this->writeByte($type) +
46 $this->writeI32($seqid);
47 }
Marc Slemkod97eb612006-08-24 23:37:36 +000048 }
49
Mark Slee5f8237d2006-10-26 04:57:03 +000050 public function writeMessageEnd() {
Marc Slemkod97eb612006-08-24 23:37:36 +000051 return 0;
52 }
53
Mark Slee5f8237d2006-10-26 04:57:03 +000054 public function writeStructBegin($name) {
Mark Slee6e536442006-06-30 18:28:50 +000055 return 0;
56 }
57
Mark Slee5f8237d2006-10-26 04:57:03 +000058 public function writeStructEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000059 return 0;
60 }
61
Mark Slee5f8237d2006-10-26 04:57:03 +000062 public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
Mark Slee6e536442006-06-30 18:28:50 +000063 return
Mark Slee5f8237d2006-10-26 04:57:03 +000064 $this->writeByte($fieldType) +
65 $this->writeI16($fieldId);
Mark Slee6e536442006-06-30 18:28:50 +000066 }
67
Mark Slee5f8237d2006-10-26 04:57:03 +000068 public function writeFieldEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000069 return 0;
Mark Slee808454e2007-06-20 21:51:57 +000070 }
Mark Slee6e536442006-06-30 18:28:50 +000071
Mark Slee5f8237d2006-10-26 04:57:03 +000072 public function writeFieldStop() {
Mark Slee6e536442006-06-30 18:28:50 +000073 return
Mark Slee5f8237d2006-10-26 04:57:03 +000074 $this->writeByte(TType::STOP);
Mark Slee6e536442006-06-30 18:28:50 +000075 }
76
Mark Slee5f8237d2006-10-26 04:57:03 +000077 public function writeMapBegin($keyType, $valType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000078 return
Mark Slee5f8237d2006-10-26 04:57:03 +000079 $this->writeByte($keyType) +
80 $this->writeByte($valType) +
81 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +000082 }
83
Mark Slee5f8237d2006-10-26 04:57:03 +000084 public function writeMapEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000085 return 0;
86 }
87
Mark Slee5f8237d2006-10-26 04:57:03 +000088 public function writeListBegin($elemType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000089 return
Mark Slee5f8237d2006-10-26 04:57:03 +000090 $this->writeByte($elemType) +
91 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +000092 }
93
Mark Slee5f8237d2006-10-26 04:57:03 +000094 public function writeListEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000095 return 0;
96 }
97
Mark Slee5f8237d2006-10-26 04:57:03 +000098 public function writeSetBegin($elemType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000099 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000100 $this->writeByte($elemType) +
101 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000102 }
103
Mark Slee5f8237d2006-10-26 04:57:03 +0000104 public function writeSetEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000105 return 0;
106 }
107
Mark Slee5f8237d2006-10-26 04:57:03 +0000108 public function writeBool($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000109 $data = pack('c', $value ? 1 : 0);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000110 $this->trans_->write($data, 1);
Mark Slee6e536442006-06-30 18:28:50 +0000111 return 1;
112 }
113
Mark Slee5f8237d2006-10-26 04:57:03 +0000114 public function writeByte($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000115 $data = pack('c', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000116 $this->trans_->write($data, 1);
Marc Slemkod97eb612006-08-24 23:37:36 +0000117 return 1;
118 }
119
Mark Slee5f8237d2006-10-26 04:57:03 +0000120 public function writeI16($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000121 $data = pack('n', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000122 $this->trans_->write($data, 2);
Marc Slemkod97eb612006-08-24 23:37:36 +0000123 return 2;
124 }
125
Mark Slee5f8237d2006-10-26 04:57:03 +0000126 public function writeI32($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000127 $data = pack('N', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000128 $this->trans_->write($data, 4);
Mark Slee6e536442006-06-30 18:28:50 +0000129 return 4;
130 }
131
Mark Slee5f8237d2006-10-26 04:57:03 +0000132 public function writeI64($value) {
Mark Sleecfc01932006-09-01 22:18:16 +0000133 // If we are on a 32bit architecture we have to explicitly deal with
134 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
Mark Slee808454e2007-06-20 21:51:57 +0000135 // as signed and any int over 2^31 - 1 as a float
Mark Sleecfc01932006-09-01 22:18:16 +0000136 if (PHP_INT_SIZE == 4) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000137 $neg = $value < 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000138
139 if ($neg) {
Mark Slee808454e2007-06-20 21:51:57 +0000140 $value *= -1;
Marc Slemkod97eb612006-08-24 23:37:36 +0000141 }
Mark Slee808454e2007-06-20 21:51:57 +0000142
Marc Slemkod97eb612006-08-24 23:37:36 +0000143 $hi = (int)($value / 4294967296);
144 $lo = (int)$value;
Mark Slee808454e2007-06-20 21:51:57 +0000145
Mark Sleecfc01932006-09-01 22:18:16 +0000146 if ($neg) {
Mark Slee808454e2007-06-20 21:51:57 +0000147 $hi = ~$hi;
148 $lo = ~$lo;
149 if (($lo & (int)0xffffffff) == (int)0xffffffff) {
150 $lo = 0;
151 $hi++;
152 } else {
153 $lo++;
154 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000155 }
Mark Slee6e536442006-06-30 18:28:50 +0000156 $data = pack('N2', $hi, $lo);
Mark Slee808454e2007-06-20 21:51:57 +0000157
Mark Slee6e536442006-06-30 18:28:50 +0000158 } else {
Marc Slemkod97eb612006-08-24 23:37:36 +0000159 $hi = $value >> 32;
160 $lo = $value & 0xFFFFFFFF;
161 $data = pack('N2', $hi, $lo);
Mark Slee6e536442006-06-30 18:28:50 +0000162 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000163
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000164 $this->trans_->write($data, 8);
Mark Slee6e536442006-06-30 18:28:50 +0000165 return 8;
166 }
167
Mark Slee5f8237d2006-10-26 04:57:03 +0000168 public function writeDouble($value) {
Mark Sleec98d0502006-09-06 02:42:25 +0000169 $data = pack('d', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000170 $this->trans_->write(strrev($data), 8);
Mark Sleec98d0502006-09-06 02:42:25 +0000171 return 8;
172 }
173
Mark Slee5f8237d2006-10-26 04:57:03 +0000174 public function writeString($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000175 $len = strlen($value);
Mark Slee5f8237d2006-10-26 04:57:03 +0000176 $result = $this->writeI32($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000177 if ($len) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000178 $this->trans_->write($value, $len);
Mark Sleeade2c832006-09-08 03:41:50 +0000179 }
Mark Slee6e536442006-06-30 18:28:50 +0000180 return $result + $len;
181 }
182
Mark Slee5f8237d2006-10-26 04:57:03 +0000183 public function readMessageBegin(&$name, &$type, &$seqid) {
Mark Slee808454e2007-06-20 21:51:57 +0000184 $result = $this->readI32($sz);
185 if ($sz < 0) {
186 $version = $sz & self::VERSION_MASK;
187 if ($version != self::VERSION_1) {
188 throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
189 }
190 $type = $sz & 0x000000ff;
191 $result +=
192 $this->readString($name) +
193 $this->readI32($seqid);
194 } else {
195 if ($this->strictRead_) {
196 throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
197 } else {
198 // Handle pre-versioned input
199 $name = $this->trans_->readAll($sz);
200 $result +=
201 $sz +
202 $this->readByte($type) +
203 $this->readI32($seqid);
204 }
205 }
206 return $result;
Marc Slemkod97eb612006-08-24 23:37:36 +0000207 }
208
Mark Slee5f8237d2006-10-26 04:57:03 +0000209 public function readMessageEnd() {
Marc Slemkod97eb612006-08-24 23:37:36 +0000210 return 0;
211 }
212
Mark Slee5f8237d2006-10-26 04:57:03 +0000213 public function readStructBegin(&$name) {
Mark Slee6e536442006-06-30 18:28:50 +0000214 $name = '';
215 return 0;
216 }
217
Mark Slee5f8237d2006-10-26 04:57:03 +0000218 public function readStructEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000219 return 0;
220 }
221
Mark Slee5f8237d2006-10-26 04:57:03 +0000222 public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
223 $result = $this->readByte($fieldType);
Mark Slee6e536442006-06-30 18:28:50 +0000224 if ($fieldType == TType::STOP) {
225 $fieldId = 0;
226 return $result;
227 }
Mark Slee5f8237d2006-10-26 04:57:03 +0000228 $result += $this->readI16($fieldId);
Mark Slee6e536442006-06-30 18:28:50 +0000229 return $result;
230 }
231
Mark Slee5f8237d2006-10-26 04:57:03 +0000232 public function readFieldEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000233 return 0;
234 }
235
Mark Slee5f8237d2006-10-26 04:57:03 +0000236 public function readMapBegin(&$keyType, &$valType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000237 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000238 $this->readByte($keyType) +
239 $this->readByte($valType) +
240 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000241 }
242
Mark Slee5f8237d2006-10-26 04:57:03 +0000243 public function readMapEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000244 return 0;
245 }
246
Mark Slee5f8237d2006-10-26 04:57:03 +0000247 public function readListBegin(&$elemType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000248 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000249 $this->readByte($elemType) +
250 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000251 }
252
Mark Slee5f8237d2006-10-26 04:57:03 +0000253 public function readListEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000254 return 0;
255 }
256
Mark Slee5f8237d2006-10-26 04:57:03 +0000257 public function readSetBegin(&$elemType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000258 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000259 $this->readByte($elemType) +
260 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000261 }
262
Mark Slee5f8237d2006-10-26 04:57:03 +0000263 public function readSetEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000264 return 0;
265 }
266
Mark Slee5f8237d2006-10-26 04:57:03 +0000267 public function readBool(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000268 $data = $this->trans_->readAll(1);
Mark Slee6e536442006-06-30 18:28:50 +0000269 $arr = unpack('c', $data);
Marc Slemkod97eb612006-08-24 23:37:36 +0000270 $value = $arr[1] == 1;
Mark Slee6e536442006-06-30 18:28:50 +0000271 return 1;
272 }
273
Mark Slee5f8237d2006-10-26 04:57:03 +0000274 public function readByte(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000275 $data = $this->trans_->readAll(1);
Marc Slemkod97eb612006-08-24 23:37:36 +0000276 $arr = unpack('c', $data);
277 $value = $arr[1];
278 return 1;
279 }
280
Mark Slee5f8237d2006-10-26 04:57:03 +0000281 public function readI16(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000282 $data = $this->trans_->readAll(2);
Marc Slemkod97eb612006-08-24 23:37:36 +0000283 $arr = unpack('n', $data);
284 $value = $arr[1];
Mark Sleecfc01932006-09-01 22:18:16 +0000285 if ($value > 0x7fff) {
286 $value = 0 - (($value - 1) ^ 0xffff);
Mark Slee6e536442006-06-30 18:28:50 +0000287 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000288 return 2;
289 }
290
Mark Slee5f8237d2006-10-26 04:57:03 +0000291 public function readI32(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000292 $data = $this->trans_->readAll(4);
Marc Slemkod97eb612006-08-24 23:37:36 +0000293 $arr = unpack('N', $data);
294 $value = $arr[1];
Mark Sleecfc01932006-09-01 22:18:16 +0000295 if ($value > 0x7fffffff) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000296 $value = 0 - (($value - 1) ^ 0xffffffff);
297 }
Mark Slee6e536442006-06-30 18:28:50 +0000298 return 4;
299 }
300
Mark Slee5f8237d2006-10-26 04:57:03 +0000301 public function readI64(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000302 $data = $this->trans_->readAll(8);
Marc Slemkod97eb612006-08-24 23:37:36 +0000303
304 $arr = unpack('N2', $data);
Mark Slee808454e2007-06-20 21:51:57 +0000305
Mark Sleecfc01932006-09-01 22:18:16 +0000306 // If we are on a 32bit architecture we have to explicitly deal with
307 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
308 // as signed and any int over 2^31 - 1 as a float
309 if (PHP_INT_SIZE == 4) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000310
311 $hi = $arr[1];
312 $lo = $arr[2];
313 $isNeg = $hi < 0;
314
315 // Check for a negative
Mark Sleecfc01932006-09-01 22:18:16 +0000316 if ($isNeg) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000317 $hi = ~$hi & (int)0xffffffff;
318 $lo = ~$lo & (int)0xffffffff;
319
Mark Sleecfc01932006-09-01 22:18:16 +0000320 if ($lo == (int)0xffffffff) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000321 $hi++;
322 $lo = 0;
323 } else {
324 $lo++;
325 }
326 }
327
Mark Sleecfc01932006-09-01 22:18:16 +0000328 // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
329 // explicitly below
Marc Slemkod97eb612006-08-24 23:37:36 +0000330
Mark Sleecfc01932006-09-01 22:18:16 +0000331 if ($hi & (int)0x80000000) {
332 $hi &= (int)0x7fffffff;
Marc Slemkod97eb612006-08-24 23:37:36 +0000333 $hi += 0x80000000;
334 }
335
Mark Sleecfc01932006-09-01 22:18:16 +0000336 if ($lo & (int)0x80000000) {
337 $lo &= (int)0x7fffffff;
Marc Slemkod97eb612006-08-24 23:37:36 +0000338 $lo += 0x80000000;
339 }
340
341 $value = $hi * 4294967296 + $lo;
342
Mark Sleecfc01932006-09-01 22:18:16 +0000343 if ($isNeg) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000344 $value = 0 - $value;
345 }
346 } else {
347
Mark Slee13a0d4a2007-04-03 03:16:11 +0000348 // Upcast negatives in LSB bit
349 if ($arr[2] & 0x80000000) {
350 $arr[2] = $arr[2] & 0xffffffff;
351 }
352
Marc Slemkod97eb612006-08-24 23:37:36 +0000353 // Check for a negative
354 if ($arr[1] & 0x80000000) {
Mark Slee13a0d4a2007-04-03 03:16:11 +0000355 $arr[1] = $arr[1] & 0xffffffff;
356 $arr[1] = $arr[1] ^ 0xffffffff;
357 $arr[2] = $arr[2] ^ 0xffffffff;
358 $value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
Marc Slemkod97eb612006-08-24 23:37:36 +0000359 } else {
Mark Slee13a0d4a2007-04-03 03:16:11 +0000360 $value = $arr[1]*4294967296 + $arr[2];
Marc Slemkod97eb612006-08-24 23:37:36 +0000361 }
362 }
363
364 return 8;
365 }
366
Mark Slee5f8237d2006-10-26 04:57:03 +0000367 public function readDouble(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000368 $data = strrev($this->trans_->readAll(8));
Mark Sleec98d0502006-09-06 02:42:25 +0000369 $arr = unpack('d', $data);
370 $value = $arr[1];
371 return 8;
372 }
373
Mark Slee5f8237d2006-10-26 04:57:03 +0000374 public function readString(&$value) {
375 $result = $this->readI32($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000376 if ($len) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000377 $value = $this->trans_->readAll($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000378 } else {
379 $value = '';
380 }
Mark Slee6e536442006-06-30 18:28:50 +0000381 return $result + $len;
382 }
383}
384
Mark Slee5f8237d2006-10-26 04:57:03 +0000385/**
386 * Binary Protocol Factory
387 */
388class TBinaryProtocolFactory implements TProtocolFactory {
Mark Slee808454e2007-06-20 21:51:57 +0000389 private $strictRead_ = false;
390 private $strictWrite_ = false;
391
392 public function __construct($strictRead=false, $strictWrite=false) {
393 $this->strictRead_ = $strictRead;
394 $this->strictWrite_ = $strictWrite;
395 }
396
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000397 public function getProtocol($trans) {
Mark Slee808454e2007-06-20 21:51:57 +0000398 return new TBinaryProtocol($trans, $this->strictRead, $this->strictWrite);
Mark Slee5f8237d2006-10-26 04:57:03 +0000399 }
400}
401
dweatherford80940b72007-10-31 23:30:56 +0000402/**
403 * Accelerated binary protocol: used in conjunction with the thrift_protocol
404 * extension for faster deserialization
405 */
406class TBinaryProtocolAccelerated extends TBinaryProtocol {
407 public function __construct($trans, $strictRead=false, $strictWrite=true) {
408 // If the transport doesn't implement putBack, wrap it in a
409 // TBufferedTransport (which does)
410 if (!method_exists($trans, 'putBack')) {
411 $trans = new TBufferedTransport($trans);
412 }
413 parent::__construct($trans, $strictRead, $strictWrite);
414 }
415}
416
Marc Slemkod97eb612006-08-24 23:37:36 +0000417?>