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