Project

General

Profile

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

    
23
include_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
24

    
25
/**
26
 * Binary implementation of the Thrift protocol.
27
 *
28
 */
29
class TBinaryProtocol extends TProtocol {
30

    
31
  const VERSION_MASK = 0xffff0000;
32
  const VERSION_1 = 0x80010000;
33

    
34
  protected $strictRead_ = false;
35
  protected $strictWrite_ = true;
36

    
37
  public function __construct($trans, $strictRead=false, $strictWrite=true) {
38
    parent::__construct($trans);
39
    $this->strictRead_ = $strictRead;
40
    $this->strictWrite_ = $strictWrite;
41
  }
42

    
43
  public function writeMessageBegin($name, $type, $seqid) {
44
    if ($this->strictWrite_) {
45
      $version = self::VERSION_1 | $type;
46
      return
47
        $this->writeI32($version) +
48
        $this->writeString($name) +
49
        $this->writeI32($seqid);
50
    } else {
51
      return
52
        $this->writeString($name) +
53
        $this->writeByte($type) +
54
        $this->writeI32($seqid);
55
    }
56
  }
57

    
58
  public function writeMessageEnd() {
59
    return 0;
60
  }
61

    
62
  public function writeStructBegin($name) {
63
    return 0;
64
  }
65

    
66
  public function writeStructEnd() {
67
    return 0;
68
  }
69

    
70
  public function writeFieldBegin($fieldName, $fieldType, $fieldId) {
71
    return
72
      $this->writeByte($fieldType) +
73
      $this->writeI16($fieldId);
74
  }
75

    
76
  public function writeFieldEnd() {
77
    return 0;
78
  }
79

    
80
  public function writeFieldStop() {
81
    return
82
      $this->writeByte(TType::STOP);
83
  }
84

    
85
  public function writeMapBegin($keyType, $valType, $size) {
86
    return
87
      $this->writeByte($keyType) +
88
      $this->writeByte($valType) +
89
      $this->writeI32($size);
90
  }
91

    
92
  public function writeMapEnd() {
93
    return 0;
94
  }
95

    
96
  public function writeListBegin($elemType, $size) {
97
    return
98
      $this->writeByte($elemType) +
99
      $this->writeI32($size);
100
  }
101

    
102
  public function writeListEnd() {
103
    return 0;
104
  }
105

    
106
  public function writeSetBegin($elemType, $size) {
107
    return
108
      $this->writeByte($elemType) +
109
      $this->writeI32($size);
110
  }
111

    
112
  public function writeSetEnd() {
113
    return 0;
114
  }
115

    
116
  public function writeBool($value) {
117
    $data = pack('c', $value ? 1 : 0);
118
    $this->trans_->write($data, 1);
119
    return 1;
120
  }
121

    
122
  public function writeByte($value) {
123
    $data = pack('c', $value);
124
    $this->trans_->write($data, 1);
125
    return 1;
126
  }
127

    
128
  public function writeI16($value) {
129
    $data = pack('n', $value);
130
    $this->trans_->write($data, 2);
131
    return 2;
132
  }
133

    
134
  public function writeI32($value) {
135
    $data = pack('N', $value);
136
    $this->trans_->write($data, 4);
137
    return 4;
138
  }
139

    
140
  public function writeI64($value) {
141
    // If we are on a 32bit architecture we have to explicitly deal with
142
    // 64-bit twos-complement arithmetic since PHP wants to treat all ints
143
    // as signed and any int over 2^31 - 1 as a float
144
    if (PHP_INT_SIZE == 4) {
145
      $neg = $value < 0;
146

    
147
      if ($neg) {
148
        $value *= -1;
149
      }
150

    
151
      $hi = (int)($value / 4294967296);
152
      $lo = (int)$value;
153

    
154
      if ($neg) {
155
        $hi = ~$hi;
156
        $lo = ~$lo;
157
        if (($lo & (int)0xffffffff) == (int)0xffffffff) {
158
          $lo = 0;
159
          $hi++;
160
        } else {
161
          $lo++;
162
        }
163
      }
164
      $data = pack('N2', $hi, $lo);
165

    
166
    } else {
167
      $hi = $value >> 32;
168
      $lo = $value & 0xFFFFFFFF;
169
      $data = pack('N2', $hi, $lo);
170
    }
171

    
172
    $this->trans_->write($data, 8);
173
    return 8;
174
  }
175

    
176
  public function writeDouble($value) {
177
    $data = pack('d', $value);
178
    $this->trans_->write(strrev($data), 8);
179
    return 8;
180
  }
181

    
182
  public function writeString($value) {
183
    $len = strlen($value);
184
    $result = $this->writeI32($len);
185
    if ($len) {
186
      $this->trans_->write($value, $len);
187
    }
188
    return $result + $len;
189
  }
190

    
191
  public function readMessageBegin(&$name, &$type, &$seqid) {
192
    $result = $this->readI32($sz);
193
    if ($sz < 0) {
194
      $version = (int) ($sz & self::VERSION_MASK);
195
      if ($version != (int) self::VERSION_1) {
196
        throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
197
      }
198
      $type = $sz & 0x000000ff;
199
      $result +=
200
        $this->readString($name) +
201
        $this->readI32($seqid);
202
    } else {
203
      if ($this->strictRead_) {
204
        throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
205
      } else {
206
        // Handle pre-versioned input
207
        $name = $this->trans_->readAll($sz);
208
        $result +=
209
          $sz +
210
          $this->readByte($type) +
211
          $this->readI32($seqid);
212
      }
213
    }
214
    return $result;
215
  }
216

    
217
  public function readMessageEnd() {
218
    return 0;
219
  }
220

    
221
  public function readStructBegin(&$name) {
222
    $name = '';
223
    return 0;
224
  }
225

    
226
  public function readStructEnd() {
227
    return 0;
228
  }
229

    
230
  public function readFieldBegin(&$name, &$fieldType, &$fieldId) {
231
    $result = $this->readByte($fieldType);
232
    if ($fieldType == TType::STOP) {
233
      $fieldId = 0;
234
      return $result;
235
    }
236
    $result += $this->readI16($fieldId);
237
    return $result;
238
  }
239

    
240
  public function readFieldEnd() {
241
    return 0;
242
  }
243

    
244
  public function readMapBegin(&$keyType, &$valType, &$size) {
245
    return
246
      $this->readByte($keyType) +
247
      $this->readByte($valType) +
248
      $this->readI32($size);
249
  }
250

    
251
  public function readMapEnd() {
252
    return 0;
253
  }
254

    
255
  public function readListBegin(&$elemType, &$size) {
256
    return
257
      $this->readByte($elemType) +
258
      $this->readI32($size);
259
  }
260

    
261
  public function readListEnd() {
262
    return 0;
263
  }
264

    
265
  public function readSetBegin(&$elemType, &$size) {
266
    return
267
      $this->readByte($elemType) +
268
      $this->readI32($size);
269
  }
270

    
271
  public function readSetEnd() {
272
    return 0;
273
  }
274

    
275
  public function readBool(&$value) {
276
    $data = $this->trans_->readAll(1);
277
    $arr = unpack('c', $data);
278
    $value = $arr[1] == 1;
279
    return 1;
280
  }
281

    
282
  public function readByte(&$value) {
283
    $data = $this->trans_->readAll(1);
284
    $arr = unpack('c', $data);
285
    $value = $arr[1];
286
    return 1;
287
  }
288

    
289
  public function readI16(&$value) {
290
    $data = $this->trans_->readAll(2);
291
    $arr = unpack('n', $data);
292
    $value = $arr[1];
293
    if ($value > 0x7fff) {
294
      $value = 0 - (($value - 1) ^ 0xffff);
295
    }
296
    return 2;
297
  }
298

    
299
  public function readI32(&$value) {
300
    $data = $this->trans_->readAll(4);
301
    $arr = unpack('N', $data);
302
    $value = $arr[1];
303
    if ($value > 0x7fffffff) {
304
      $value = 0 - (($value - 1) ^ 0xffffffff);
305
    }
306
    return 4;
307
  }
308

    
309
  public function readI64(&$value) {
310
    $data = $this->trans_->readAll(8);
311

    
312
    $arr = unpack('N2', $data);
313

    
314
    // If we are on a 32bit architecture we have to explicitly deal with
315
    // 64-bit twos-complement arithmetic since PHP wants to treat all ints
316
    // as signed and any int over 2^31 - 1 as a float
317
    if (PHP_INT_SIZE == 4) {
318

    
319
      $hi = $arr[1];
320
      $lo = $arr[2];
321
      $isNeg = $hi  < 0;
322

    
323
      // Check for a negative
324
      if ($isNeg) {
325
        $hi = ~$hi & (int)0xffffffff;
326
        $lo = ~$lo & (int)0xffffffff;
327

    
328
        if ($lo == (int)0xffffffff) {
329
          $hi++;
330
          $lo = 0;
331
        } else {
332
          $lo++;
333
        }
334
      }
335

    
336
      // Force 32bit words in excess of 2G to pe positive - we deal wigh sign
337
      // explicitly below
338

    
339
      if ($hi & (int)0x80000000) {
340
        $hi &= (int)0x7fffffff;
341
        $hi += 0x80000000;
342
      }
343

    
344
      if ($lo & (int)0x80000000) {
345
        $lo &= (int)0x7fffffff;
346
        $lo += 0x80000000;
347
      }
348

    
349
      $value = $hi * 4294967296 + $lo;
350

    
351
      if ($isNeg) {
352
        $value = 0 - $value;
353
      }
354
    } else {
355

    
356
      // Upcast negatives in LSB bit
357
      if ($arr[2] & 0x80000000) {
358
        $arr[2] = $arr[2] & 0xffffffff;
359
      }
360

    
361
      // Check for a negative
362
      if ($arr[1] & 0x80000000) {
363
        $arr[1] = $arr[1] & 0xffffffff;
364
        $arr[1] = $arr[1] ^ 0xffffffff;
365
        $arr[2] = $arr[2] ^ 0xffffffff;
366
        $value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
367
      } else {
368
        $value = $arr[1]*4294967296 + $arr[2];
369
      }
370
    }
371

    
372
    return 8;
373
  }
374

    
375
  public function readDouble(&$value) {
376
    $data = strrev($this->trans_->readAll(8));
377
    $arr = unpack('d', $data);
378
    $value = $arr[1];
379
    return 8;
380
  }
381

    
382
  public function readString(&$value) {
383
    $result = $this->readI32($len);
384
    if ($len) {
385
      $value = $this->trans_->readAll($len);
386
    } else {
387
      $value = '';
388
    }
389
    return $result + $len;
390
  }
391
}
392

    
393
/**
394
 * Binary Protocol Factory
395
 */
396
class TBinaryProtocolFactory implements TProtocolFactory {
397
  private $strictRead_ = false;
398
  private $strictWrite_ = false;
399

    
400
  public function __construct($strictRead=false, $strictWrite=false) {
401
    $this->strictRead_ = $strictRead;
402
    $this->strictWrite_ = $strictWrite;
403
  }
404

    
405
  public function getProtocol($trans) {
406
    return new TBinaryProtocol($trans, $this->strictRead, $this->strictWrite);
407
  }
408
}
409

    
410
/**
411
 * Accelerated binary protocol: used in conjunction with the thrift_protocol
412
 * extension for faster deserialization
413
 */
414
class TBinaryProtocolAccelerated extends TBinaryProtocol {
415
  public function __construct($trans, $strictRead=false, $strictWrite=true) {
416
    // If the transport doesn't implement putBack, wrap it in a
417
    // TBufferedTransport (which does)
418
    if (!method_exists($trans, 'putBack')) {
419
      $trans = new TBufferedTransport($trans);
420
    }
421
    parent::__construct($trans, $strictRead, $strictWrite);
422
  }
423
  public function isStrictRead() {
424
    return $this->strictRead_;
425
  }
426
  public function isStrictWrite() {
427
    return $this->strictWrite_;
428
  }
429
}
(1-1/2)