blob: 69723da71f2d0c7e8461a04e801146b0ad6d6433 [file] [log] [blame]
Mark Slee4902c052007-03-01 00:31:30 +00001<?php
2
3/**
4 * Copyright (c) 2006- Facebook
5 * Distributed under the Thrift Software License
6 *
7 * See accompanying file LICENSE or visit the Thrift site at:
8 * http://developers.facebook.com/thrift/
9 *
10 * @package thrift.protocol
11 * @author Mark Slee <mcslee@facebook.com>
12 */
Mark Slee6e536442006-06-30 18:28:50 +000013
Mark Slee6e536442006-06-30 18:28:50 +000014/**
15 * Binary implementation of the Thrift protocol.
16 *
Mark Slee6e536442006-06-30 18:28:50 +000017 * @author Mark Slee <mcslee@facebook.com>
Mark Sleeadde9682007-03-01 00:37:56 +000018 * @author Marc Kwiatkowski <marc@facebook.com>
Mark Slee6e536442006-06-30 18:28:50 +000019 */
20class TBinaryProtocol extends TProtocol {
21
Mark Slee808454e2007-06-20 21:51:57 +000022 const VERSION_MASK = 0xffff0000;
23 const VERSION_1 = 0x80010000;
24
25 private $strictRead_ = false;
26 private $strictWrite_ = true;
27
28 public function __construct($trans, $strictRead=false, $strictWrite=true) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +000029 parent::__construct($trans);
Mark Slee808454e2007-06-20 21:51:57 +000030 $this->strictRead_ = $strictRead;
31 $this->strictWrite_ = $strictWrite;
Mark Slee5f8237d2006-10-26 04:57:03 +000032 }
33
34 public function writeMessageBegin($name, $type, $seqid) {
Mark Slee808454e2007-06-20 21:51:57 +000035 if ($this->strictWrite_) {
36 $version = self::VERSION_1 | $type;
37 return
38 $this->writeI32($version) +
39 $this->writeString($name) +
40 $this->writeI32($seqid);
41 } else {
42 return
43 $this->writeString($name) +
44 $this->writeByte($type) +
45 $this->writeI32($seqid);
46 }
Marc Slemkod97eb612006-08-24 23:37:36 +000047 }
48
Mark Slee5f8237d2006-10-26 04:57:03 +000049 public function writeMessageEnd() {
Marc Slemkod97eb612006-08-24 23:37:36 +000050 return 0;
51 }
52
Mark Slee5f8237d2006-10-26 04:57:03 +000053 public function writeStructBegin($name) {
Mark Slee6e536442006-06-30 18:28:50 +000054 return 0;
55 }
56
Mark Slee5f8237d2006-10-26 04:57:03 +000057 public function writeStructEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000058 return 0;
59 }
60
Mark Slee5f8237d2006-10-26 04:57:03 +000061 public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
Mark Slee6e536442006-06-30 18:28:50 +000062 return
Mark Slee5f8237d2006-10-26 04:57:03 +000063 $this->writeByte($fieldType) +
64 $this->writeI16($fieldId);
Mark Slee6e536442006-06-30 18:28:50 +000065 }
66
Mark Slee5f8237d2006-10-26 04:57:03 +000067 public function writeFieldEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000068 return 0;
Mark Slee808454e2007-06-20 21:51:57 +000069 }
Mark Slee6e536442006-06-30 18:28:50 +000070
Mark Slee5f8237d2006-10-26 04:57:03 +000071 public function writeFieldStop() {
Mark Slee6e536442006-06-30 18:28:50 +000072 return
Mark Slee5f8237d2006-10-26 04:57:03 +000073 $this->writeByte(TType::STOP);
Mark Slee6e536442006-06-30 18:28:50 +000074 }
75
Mark Slee5f8237d2006-10-26 04:57:03 +000076 public function writeMapBegin($keyType, $valType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000077 return
Mark Slee5f8237d2006-10-26 04:57:03 +000078 $this->writeByte($keyType) +
79 $this->writeByte($valType) +
80 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +000081 }
82
Mark Slee5f8237d2006-10-26 04:57:03 +000083 public function writeMapEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000084 return 0;
85 }
86
Mark Slee5f8237d2006-10-26 04:57:03 +000087 public function writeListBegin($elemType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000088 return
Mark Slee5f8237d2006-10-26 04:57:03 +000089 $this->writeByte($elemType) +
90 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +000091 }
92
Mark Slee5f8237d2006-10-26 04:57:03 +000093 public function writeListEnd() {
Mark Slee6e536442006-06-30 18:28:50 +000094 return 0;
95 }
96
Mark Slee5f8237d2006-10-26 04:57:03 +000097 public function writeSetBegin($elemType, $size) {
Mark Slee6e536442006-06-30 18:28:50 +000098 return
Mark Slee5f8237d2006-10-26 04:57:03 +000099 $this->writeByte($elemType) +
100 $this->writeI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000101 }
102
Mark Slee5f8237d2006-10-26 04:57:03 +0000103 public function writeSetEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000104 return 0;
105 }
106
Mark Slee5f8237d2006-10-26 04:57:03 +0000107 public function writeBool($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000108 $data = pack('c', $value ? 1 : 0);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000109 $this->trans_->write($data, 1);
Mark Slee6e536442006-06-30 18:28:50 +0000110 return 1;
111 }
112
Mark Slee5f8237d2006-10-26 04:57:03 +0000113 public function writeByte($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000114 $data = pack('c', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000115 $this->trans_->write($data, 1);
Marc Slemkod97eb612006-08-24 23:37:36 +0000116 return 1;
117 }
118
Mark Slee5f8237d2006-10-26 04:57:03 +0000119 public function writeI16($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000120 $data = pack('n', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000121 $this->trans_->write($data, 2);
Marc Slemkod97eb612006-08-24 23:37:36 +0000122 return 2;
123 }
124
Mark Slee5f8237d2006-10-26 04:57:03 +0000125 public function writeI32($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000126 $data = pack('N', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000127 $this->trans_->write($data, 4);
Mark Slee6e536442006-06-30 18:28:50 +0000128 return 4;
129 }
130
Mark Slee5f8237d2006-10-26 04:57:03 +0000131 public function writeI64($value) {
Mark Sleecfc01932006-09-01 22:18:16 +0000132 // If we are on a 32bit architecture we have to explicitly deal with
133 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
Mark Slee808454e2007-06-20 21:51:57 +0000134 // as signed and any int over 2^31 - 1 as a float
Mark Sleecfc01932006-09-01 22:18:16 +0000135 if (PHP_INT_SIZE == 4) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000136 $neg = $value < 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000137
138 if ($neg) {
Mark Slee808454e2007-06-20 21:51:57 +0000139 $value *= -1;
Marc Slemkod97eb612006-08-24 23:37:36 +0000140 }
Mark Slee808454e2007-06-20 21:51:57 +0000141
Marc Slemkod97eb612006-08-24 23:37:36 +0000142 $hi = (int)($value / 4294967296);
143 $lo = (int)$value;
Mark Slee808454e2007-06-20 21:51:57 +0000144
Mark Sleecfc01932006-09-01 22:18:16 +0000145 if ($neg) {
Mark Slee808454e2007-06-20 21:51:57 +0000146 $hi = ~$hi;
147 $lo = ~$lo;
148 if (($lo & (int)0xffffffff) == (int)0xffffffff) {
149 $lo = 0;
150 $hi++;
151 } else {
152 $lo++;
153 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000154 }
Mark Slee6e536442006-06-30 18:28:50 +0000155 $data = pack('N2', $hi, $lo);
Mark Slee808454e2007-06-20 21:51:57 +0000156
Mark Slee6e536442006-06-30 18:28:50 +0000157 } else {
Marc Slemkod97eb612006-08-24 23:37:36 +0000158 $hi = $value >> 32;
159 $lo = $value & 0xFFFFFFFF;
160 $data = pack('N2', $hi, $lo);
Mark Slee6e536442006-06-30 18:28:50 +0000161 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000162
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000163 $this->trans_->write($data, 8);
Mark Slee6e536442006-06-30 18:28:50 +0000164 return 8;
165 }
166
Mark Slee5f8237d2006-10-26 04:57:03 +0000167 public function writeDouble($value) {
Mark Sleec98d0502006-09-06 02:42:25 +0000168 $data = pack('d', $value);
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000169 $this->trans_->write(strrev($data), 8);
Mark Sleec98d0502006-09-06 02:42:25 +0000170 return 8;
171 }
172
Mark Slee5f8237d2006-10-26 04:57:03 +0000173 public function writeString($value) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000174 $len = strlen($value);
Mark Slee5f8237d2006-10-26 04:57:03 +0000175 $result = $this->writeI32($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000176 if ($len) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000177 $this->trans_->write($value, $len);
Mark Sleeade2c832006-09-08 03:41:50 +0000178 }
Mark Slee6e536442006-06-30 18:28:50 +0000179 return $result + $len;
180 }
181
Mark Slee5f8237d2006-10-26 04:57:03 +0000182 public function readMessageBegin(&$name, &$type, &$seqid) {
Mark Slee808454e2007-06-20 21:51:57 +0000183 $result = $this->readI32($sz);
184 if ($sz < 0) {
185 $version = $sz & self::VERSION_MASK;
186 if ($version != self::VERSION_1) {
187 throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
188 }
189 $type = $sz & 0x000000ff;
190 $result +=
191 $this->readString($name) +
192 $this->readI32($seqid);
193 } else {
194 if ($this->strictRead_) {
195 throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
196 } else {
197 // Handle pre-versioned input
198 $name = $this->trans_->readAll($sz);
199 $result +=
200 $sz +
201 $this->readByte($type) +
202 $this->readI32($seqid);
203 }
204 }
205 return $result;
Marc Slemkod97eb612006-08-24 23:37:36 +0000206 }
207
Mark Slee5f8237d2006-10-26 04:57:03 +0000208 public function readMessageEnd() {
Marc Slemkod97eb612006-08-24 23:37:36 +0000209 return 0;
210 }
211
Mark Slee5f8237d2006-10-26 04:57:03 +0000212 public function readStructBegin(&$name) {
Mark Slee6e536442006-06-30 18:28:50 +0000213 $name = '';
214 return 0;
215 }
216
Mark Slee5f8237d2006-10-26 04:57:03 +0000217 public function readStructEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000218 return 0;
219 }
220
Mark Slee5f8237d2006-10-26 04:57:03 +0000221 public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
222 $result = $this->readByte($fieldType);
Mark Slee6e536442006-06-30 18:28:50 +0000223 if ($fieldType == TType::STOP) {
224 $fieldId = 0;
225 return $result;
226 }
Mark Slee5f8237d2006-10-26 04:57:03 +0000227 $result += $this->readI16($fieldId);
Mark Slee6e536442006-06-30 18:28:50 +0000228 return $result;
229 }
230
Mark Slee5f8237d2006-10-26 04:57:03 +0000231 public function readFieldEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000232 return 0;
233 }
234
Mark Slee5f8237d2006-10-26 04:57:03 +0000235 public function readMapBegin(&$keyType, &$valType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000236 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000237 $this->readByte($keyType) +
238 $this->readByte($valType) +
239 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000240 }
241
Mark Slee5f8237d2006-10-26 04:57:03 +0000242 public function readMapEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000243 return 0;
244 }
245
Mark Slee5f8237d2006-10-26 04:57:03 +0000246 public function readListBegin(&$elemType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000247 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000248 $this->readByte($elemType) +
249 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000250 }
251
Mark Slee5f8237d2006-10-26 04:57:03 +0000252 public function readListEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000253 return 0;
254 }
255
Mark Slee5f8237d2006-10-26 04:57:03 +0000256 public function readSetBegin(&$elemType, &$size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000257 return
Mark Slee5f8237d2006-10-26 04:57:03 +0000258 $this->readByte($elemType) +
259 $this->readI32($size);
Mark Slee6e536442006-06-30 18:28:50 +0000260 }
261
Mark Slee5f8237d2006-10-26 04:57:03 +0000262 public function readSetEnd() {
Mark Slee6e536442006-06-30 18:28:50 +0000263 return 0;
264 }
265
Mark Slee5f8237d2006-10-26 04:57:03 +0000266 public function readBool(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000267 $data = $this->trans_->readAll(1);
Mark Slee6e536442006-06-30 18:28:50 +0000268 $arr = unpack('c', $data);
Marc Slemkod97eb612006-08-24 23:37:36 +0000269 $value = $arr[1] == 1;
Mark Slee6e536442006-06-30 18:28:50 +0000270 return 1;
271 }
272
Mark Slee5f8237d2006-10-26 04:57:03 +0000273 public function readByte(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000274 $data = $this->trans_->readAll(1);
Marc Slemkod97eb612006-08-24 23:37:36 +0000275 $arr = unpack('c', $data);
276 $value = $arr[1];
277 return 1;
278 }
279
Mark Slee5f8237d2006-10-26 04:57:03 +0000280 public function readI16(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000281 $data = $this->trans_->readAll(2);
Marc Slemkod97eb612006-08-24 23:37:36 +0000282 $arr = unpack('n', $data);
283 $value = $arr[1];
Mark Sleecfc01932006-09-01 22:18:16 +0000284 if ($value > 0x7fff) {
285 $value = 0 - (($value - 1) ^ 0xffff);
Mark Slee6e536442006-06-30 18:28:50 +0000286 }
Marc Slemkod97eb612006-08-24 23:37:36 +0000287 return 2;
288 }
289
Mark Slee5f8237d2006-10-26 04:57:03 +0000290 public function readI32(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000291 $data = $this->trans_->readAll(4);
Marc Slemkod97eb612006-08-24 23:37:36 +0000292 $arr = unpack('N', $data);
293 $value = $arr[1];
Mark Sleecfc01932006-09-01 22:18:16 +0000294 if ($value > 0x7fffffff) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000295 $value = 0 - (($value - 1) ^ 0xffffffff);
296 }
Mark Slee6e536442006-06-30 18:28:50 +0000297 return 4;
298 }
299
Mark Slee5f8237d2006-10-26 04:57:03 +0000300 public function readI64(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000301 $data = $this->trans_->readAll(8);
Marc Slemkod97eb612006-08-24 23:37:36 +0000302
303 $arr = unpack('N2', $data);
Mark Slee808454e2007-06-20 21:51:57 +0000304
Mark Sleecfc01932006-09-01 22:18:16 +0000305 // If we are on a 32bit architecture we have to explicitly deal with
306 // 64-bit twos-complement arithmetic since PHP wants to treat all ints
307 // as signed and any int over 2^31 - 1 as a float
308 if (PHP_INT_SIZE == 4) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000309
310 $hi = $arr[1];
311 $lo = $arr[2];
312 $isNeg = $hi < 0;
313
314 // Check for a negative
Mark Sleecfc01932006-09-01 22:18:16 +0000315 if ($isNeg) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000316 $hi = ~$hi & (int)0xffffffff;
317 $lo = ~$lo & (int)0xffffffff;
318
Mark Sleecfc01932006-09-01 22:18:16 +0000319 if ($lo == (int)0xffffffff) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000320 $hi++;
321 $lo = 0;
322 } else {
323 $lo++;
324 }
325 }
326
Mark Sleecfc01932006-09-01 22:18:16 +0000327 // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
328 // explicitly below
Marc Slemkod97eb612006-08-24 23:37:36 +0000329
Mark Sleecfc01932006-09-01 22:18:16 +0000330 if ($hi & (int)0x80000000) {
331 $hi &= (int)0x7fffffff;
Marc Slemkod97eb612006-08-24 23:37:36 +0000332 $hi += 0x80000000;
333 }
334
Mark Sleecfc01932006-09-01 22:18:16 +0000335 if ($lo & (int)0x80000000) {
336 $lo &= (int)0x7fffffff;
Marc Slemkod97eb612006-08-24 23:37:36 +0000337 $lo += 0x80000000;
338 }
339
340 $value = $hi * 4294967296 + $lo;
341
Mark Sleecfc01932006-09-01 22:18:16 +0000342 if ($isNeg) {
Marc Slemkod97eb612006-08-24 23:37:36 +0000343 $value = 0 - $value;
344 }
345 } else {
346
Mark Slee13a0d4a2007-04-03 03:16:11 +0000347 // Upcast negatives in LSB bit
348 if ($arr[2] & 0x80000000) {
349 $arr[2] = $arr[2] & 0xffffffff;
350 }
351
Marc Slemkod97eb612006-08-24 23:37:36 +0000352 // Check for a negative
353 if ($arr[1] & 0x80000000) {
Mark Slee13a0d4a2007-04-03 03:16:11 +0000354 $arr[1] = $arr[1] & 0xffffffff;
355 $arr[1] = $arr[1] ^ 0xffffffff;
356 $arr[2] = $arr[2] ^ 0xffffffff;
357 $value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
Marc Slemkod97eb612006-08-24 23:37:36 +0000358 } else {
Mark Slee13a0d4a2007-04-03 03:16:11 +0000359 $value = $arr[1]*4294967296 + $arr[2];
Marc Slemkod97eb612006-08-24 23:37:36 +0000360 }
361 }
362
363 return 8;
364 }
365
Mark Slee5f8237d2006-10-26 04:57:03 +0000366 public function readDouble(&$value) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000367 $data = strrev($this->trans_->readAll(8));
Mark Sleec98d0502006-09-06 02:42:25 +0000368 $arr = unpack('d', $data);
369 $value = $arr[1];
370 return 8;
371 }
372
Mark Slee5f8237d2006-10-26 04:57:03 +0000373 public function readString(&$value) {
374 $result = $this->readI32($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000375 if ($len) {
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000376 $value = $this->trans_->readAll($len);
Mark Sleeade2c832006-09-08 03:41:50 +0000377 } else {
378 $value = '';
379 }
Mark Slee6e536442006-06-30 18:28:50 +0000380 return $result + $len;
381 }
382}
383
Mark Slee5f8237d2006-10-26 04:57:03 +0000384/**
385 * Binary Protocol Factory
386 */
387class TBinaryProtocolFactory implements TProtocolFactory {
Mark Slee808454e2007-06-20 21:51:57 +0000388 private $strictRead_ = false;
389 private $strictWrite_ = false;
390
391 public function __construct($strictRead=false, $strictWrite=false) {
392 $this->strictRead_ = $strictRead;
393 $this->strictWrite_ = $strictWrite;
394 }
395
Aditya Agarwal6a5bcaa2007-02-06 02:50:56 +0000396 public function getProtocol($trans) {
Mark Slee808454e2007-06-20 21:51:57 +0000397 return new TBinaryProtocol($trans, $this->strictRead, $this->strictWrite);
Mark Slee5f8237d2006-10-26 04:57:03 +0000398 }
399}
400
Marc Slemkod97eb612006-08-24 23:37:36 +0000401?>