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