1<?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 */ 13 14/** 15 * Protocol module. Contains all the types and definitions needed to implement 16 * a protocol encoder/decoder. 17 * 18 * @package thrift.protocol 19 * @author Mark Slee <mcslee@facebook.com> 20 * @author Aditya Agarwal <aditya@facebook.com> 21 */ 22 23/** 24 * Protocol exceptions 25 */ 26class TProtocolException extends TException { 27 const UNKNOWN = 0; 28 const INVALID_DATA = 1; 29 const NEGATIVE_SIZE = 2; 30 const SIZE_LIMIT = 3; 31 const BAD_VERSION = 4; 32 33 function __construct($message=null, $code=0) { 34 parent::__construct($message, $code); 35 } 36} 37 38/** 39 * Protocol base class module. 40 */ 41abstract class TProtocol { 42 // The below may seem silly, but it is to get around the problem that the 43 // "instanceof" operator can only take in a T_VARIABLE and not a T_STRING 44 // or T_CONSTANT_ENCAPSED_STRING. Using "is_a()" instead of "instanceof" is 45 // a workaround but is deprecated in PHP5. This is used in the generated 46 // deserialization code. 47 static $TBINARYPROTOCOLACCELERATED = 'TBinaryProtocolAccelerated'; 48 49 /** 50 * Underlying transport 51 * 52 * @var TTransport 53 */ 54 protected $trans_; 55 56 /** 57 * Constructor 58 */ 59 protected function __construct($trans) { 60 $this->trans_ = $trans; 61 } 62 63 /** 64 * Accessor for transport 65 * 66 * @return TTransport 67 */ 68 public function getTransport() { 69 return $this->trans_; 70 } 71 72 /** 73 * Writes the message header 74 * 75 * @param string $name Function name 76 * @param int $type message type TMessageType::CALL or TMessageType::REPLY 77 * @param int $seqid The sequence id of this message 78 */ 79 public abstract function writeMessageBegin($name, $type, $seqid); 80 81 /** 82 * Close the message 83 */ 84 public abstract function writeMessageEnd(); 85 86 /** 87 * Writes a struct header. 88 * 89 * @param string $name Struct name 90 * @throws TException on write error 91 * @return int How many bytes written 92 */ 93 public abstract function writeStructBegin($name); 94 95 /** 96 * Close a struct. 97 * 98 * @throws TException on write error 99 * @return int How many bytes written 100 */ 101 public abstract function writeStructEnd(); 102 103 /* 104 * Starts a field. 105 * 106 * @param string $name Field name 107 * @param int $type Field type 108 * @param int $fid Field id 109 * @throws TException on write error 110 * @return int How many bytes written 111 */ 112 public abstract function writeFieldBegin($fieldName, $fieldType, $fieldId); 113 114 public abstract function writeFieldEnd(); 115 116 public abstract function writeFieldStop(); 117 118 public abstract function writeMapBegin($keyType, $valType, $size); 119 120 public abstract function writeMapEnd(); 121 122 public abstract function writeListBegin($elemType, $size); 123 124 public abstract function writeListEnd(); 125 126 public abstract function writeSetBegin($elemType, $size); 127 128 public abstract function writeSetEnd(); 129 130 public abstract function writeBool($bool); 131 132 public abstract function writeByte($byte); 133 134 public abstract function writeI16($i16); 135 136 public abstract function writeI32($i32); 137 138 public abstract function writeI64($i64); 139 140 public abstract function writeDouble($dub); 141 142 public abstract function writeString($str); 143 144 /** 145 * Reads the message header 146 * 147 * @param string $name Function name 148 * @param int $type message type TMessageType::CALL or TMessageType::REPLY 149 * @parem int $seqid The sequence id of this message 150 */ 151 public abstract function readMessageBegin(&$name, &$type, &$seqid); 152 153 /** 154 * Read the close of message 155 */ 156 public abstract function readMessageEnd(); 157 158 public abstract function readStructBegin(&$name); 159 160 public abstract function readStructEnd(); 161 162 public abstract function readFieldBegin(&$name, &$fieldType, &$fieldId); 163 164 public abstract function readFieldEnd(); 165 166 public abstract function readMapBegin(&$keyType, &$valType, &$size); 167 168 public abstract function readMapEnd(); 169 170 public abstract function readListBegin(&$elemType, &$size); 171 172 public abstract function readListEnd(); 173 174 public abstract function readSetBegin(&$elemType, &$size); 175 176 public abstract function readSetEnd(); 177 178 public abstract function readBool(&$bool); 179 180 public abstract function readByte(&$byte); 181 182 public abstract function readI16(&$i16); 183 184 public abstract function readI32(&$i32); 185 186 public abstract function readI64(&$i64); 187 188 public abstract function readDouble(&$dub); 189 190 public abstract function readString(&$str); 191 192 /** 193 * The skip function is a utility to parse over unrecognized date without 194 * causing corruption. 195 * 196 * @param TType $type What type is it 197 */ 198 public function skip($type) { 199 switch ($type) { 200 case TType::BOOL: 201 return $this->readBool($bool); 202 case TType::BYTE: 203 return $this->readByte($byte); 204 case TType::I16: 205 return $this->readI16($i16); 206 case TType::I32: 207 return $this->readI32($i32); 208 case TType::I64: 209 return $this->readI64($i64); 210 case TType::DOUBLE: 211 return $this->readDouble($dub); 212 case TType::STRING: 213 return $this->readString($str); 214 case TType::STRUCT: 215 { 216 $result = $this->readStructBegin($name); 217 while (true) { 218 $result += $this->readFieldBegin($name, $ftype, $fid); 219 if ($ftype == TType::STOP) { 220 break; 221 } 222 $result += $this->skip($ftype); 223 $result += $this->readFieldEnd(); 224 } 225 $result += $this->readStructEnd(); 226 return $result; 227 } 228 case TType::MAP: 229 { 230 $result = $this->readMapBegin($keyType, $valType, $size); 231 for ($i = 0; $i < $size; $i++) { 232 $result += $this->skip($keyType); 233 $result += $this->skip($valType); 234 } 235 $result += $this->readMapEnd(); 236 return $result; 237 } 238 case TType::SET: 239 { 240 $result = $this->readSetBegin($elemType, $size); 241 for ($i = 0; $i < $size; $i++) { 242 $result += $this->skip($elemType); 243 } 244 $result += $this->readSetEnd(); 245 return $result; 246 } 247 case TType::LST: 248 { 249 $result = $this->readListBegin($elemType, $size); 250 for ($i = 0; $i < $size; $i++) { 251 $result += $this->skip($elemType); 252 } 253 $result += $this->readListEnd(); 254 return $result; 255 } 256 default: 257 return 0; 258 } 259 } 260 261 /** 262 * Utility for skipping binary data 263 * 264 * @param TTransport $itrans TTransport object 265 * @param int $type Field type 266 */ 267 public static function skipBinary($itrans, $type) { 268 switch ($type) { 269 case TType::BOOL: 270 return $itrans->readAll(1); 271 case TType::BYTE: 272 return $itrans->readAll(1); 273 case TType::I16: 274 return $itrans->readAll(2); 275 case TType::I32: 276 return $itrans->readAll(4); 277 case TType::I64: 278 return $itrans->readAll(8); 279 case TType::DOUBLE: 280 return $itrans->readAll(8); 281 case TType::STRING: 282 $len = unpack('N', $itrans->readAll(4)); 283 $len = $len[1]; 284 if ($len > 0x7fffffff) { 285 $len = 0 - (($len - 1) ^ 0xffffffff); 286 } 287 return 4 + $itrans->readAll($len); 288 case TType::STRUCT: 289 { 290 $result = 0; 291 while (true) { 292 $ftype = 0; 293 $fid = 0; 294 $data = $itrans->readAll(1); 295 $arr = unpack('c', $data); 296 $ftype = $arr[1]; 297 if ($ftype == TType::STOP) { 298 break; 299 } 300 // I16 field id 301 $result += $itrans->readAll(2); 302 $result += self::skipBinary($itrans, $ftype); 303 } 304 return $result; 305 } 306 case TType::MAP: 307 { 308 // Ktype 309 $data = $itrans->readAll(1); 310 $arr = unpack('c', $data); 311 $ktype = $arr[1]; 312 // Vtype 313 $data = $itrans->readAll(1); 314 $arr = unpack('c', $data); 315 $vtype = $arr[1]; 316 // Size 317 $data = $itrans->readAll(4); 318 $arr = unpack('N', $data); 319 $size = $arr[1]; 320 if ($size > 0x7fffffff) { 321 $size = 0 - (($size - 1) ^ 0xffffffff); 322 } 323 $result = 6; 324 for ($i = 0; $i < $size; $i++) { 325 $result += self::skipBinary($itrans, $ktype); 326 $result += self::skipBinary($itrans, $vtype); 327 } 328 return $result; 329 } 330 case TType::SET: 331 case TType::LST: 332 { 333 // Vtype 334 $data = $itrans->readAll(1); 335 $arr = unpack('c', $data); 336 $vtype = $arr[1]; 337 // Size 338 $data = $itrans->readAll(4); 339 $arr = unpack('N', $data); 340 $size = $arr[1]; 341 if ($size > 0x7fffffff) { 342 $size = 0 - (($size - 1) ^ 0xffffffff); 343 } 344 $result = 5; 345 for ($i = 0; $i < $size; $i++) { 346 $result += self::skipBinary($itrans, $vtype); 347 } 348 return $result; 349 } 350 default: 351 return 0; 352 } 353 } 354} 355 356/** 357 * Protocol factory creates protocol objects from transports 358 */ 359interface TProtocolFactory { 360 /** 361 * Build a protocol from the base transport 362 * 363 * @return TProtcol protocol 364 */ 365 public function getProtocol($trans); 366} 367 368 369?> 370