PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/protocol/TCompactProtocol.php

https://github.com/brucemj/showHbase
PHP | 678 lines | 537 code | 95 blank | 46 comment | 81 complexity | 5df5f66c9f04a22855d72a167f4b798e MD5 | raw file
  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. include_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
  23. /**
  24. * Compact implementation of the Thrift protocol.
  25. *
  26. */
  27. class TCompactProtocol extends TProtocol {
  28. const COMPACT_STOP = 0x00;
  29. const COMPACT_TRUE = 0x01;
  30. const COMPACT_FALSE = 0x02;
  31. const COMPACT_BYTE = 0x03;
  32. const COMPACT_I16 = 0x04;
  33. const COMPACT_I32 = 0x05;
  34. const COMPACT_I64 = 0x06;
  35. const COMPACT_DOUBLE = 0x07;
  36. const COMPACT_BINARY = 0x08;
  37. const COMPACT_LIST = 0x09;
  38. const COMPACT_SET = 0x0A;
  39. const COMPACT_MAP = 0x0B;
  40. const COMPACT_STRUCT = 0x0C;
  41. const STATE_CLEAR = 0;
  42. const STATE_FIELD_WRITE = 1;
  43. const STATE_VALUE_WRITE = 2;
  44. const STATE_CONTAINER_WRITE = 3;
  45. const STATE_BOOL_WRITE = 4;
  46. const STATE_FIELD_READ = 5;
  47. const STATE_CONTAINER_READ = 6;
  48. const STATE_VALUE_READ = 7;
  49. const STATE_BOOL_READ = 8;
  50. const VERSION_MASK = 0x1f;
  51. const VERSION = 1;
  52. const PROTOCOL_ID = 0x82;
  53. const TYPE_MASK = 0xe0;
  54. const TYPE_SHIFT_AMOUNT = 5;
  55. protected static $ctypes = array(
  56. TType::STOP => TCompactProtocol::COMPACT_STOP,
  57. TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection
  58. TType::BYTE => TCompactProtocol::COMPACT_BYTE,
  59. TType::I16 => TCompactProtocol::COMPACT_I16,
  60. TType::I32 => TCompactProtocol::COMPACT_I32,
  61. TType::I64 => TCompactProtocol::COMPACT_I64,
  62. TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE,
  63. TType::STRING => TCompactProtocol::COMPACT_BINARY,
  64. TType::STRUCT => TCompactProtocol::COMPACT_STRUCT,
  65. TType::LST => TCompactProtocol::COMPACT_LIST,
  66. TType::SET => TCompactProtocol::COMPACT_SET,
  67. TType::MAP => TCompactProtocol::COMPACT_MAP,
  68. );
  69. protected static $ttypes = array(
  70. TCompactProtocol::COMPACT_STOP => TType::STOP ,
  71. TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection
  72. TCompactProtocol::COMPACT_FALSE => TType::BOOL,
  73. TCompactProtocol::COMPACT_BYTE => TType::BYTE,
  74. TCompactProtocol::COMPACT_I16 => TType::I16,
  75. TCompactProtocol::COMPACT_I32 => TType::I32,
  76. TCompactProtocol::COMPACT_I64 => TType::I64,
  77. TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE,
  78. TCompactProtocol::COMPACT_BINARY => TType::STRING,
  79. TCompactProtocol::COMPACT_STRUCT => TType::STRUCT,
  80. TCompactProtocol::COMPACT_LIST => TType::LST,
  81. TCompactProtocol::COMPACT_SET => TType::SET,
  82. TCompactProtocol::COMPACT_MAP => TType::MAP,
  83. );
  84. protected $state = TCompactProtocol::STATE_CLEAR;
  85. protected $lastFid = 0;
  86. protected $boolFid = null;
  87. protected $boolValue = null;
  88. protected $structs = array();
  89. protected $containers = array();
  90. // Some varint / zigzag helper methods
  91. public function toZigZag($n, $bits) {
  92. return ($n << 1) ^ ($n >> ($bits - 1));
  93. }
  94. public function fromZigZag($n) {
  95. return ($n >> 1) ^ -($n & 1);
  96. }
  97. public function getVarint($data) {
  98. $out = "";
  99. while (true) {
  100. if (($data & ~0x7f) === 0) {
  101. $out .= chr($data);
  102. break;
  103. } else {
  104. $out .= chr(($data & 0xff) | 0x80);
  105. $data = $data >> 7;
  106. }
  107. }
  108. return $out;
  109. }
  110. public function writeVarint($data) {
  111. $out = $this->getVarint($data);
  112. $result = strlen($out);
  113. $this->trans_->write($out, $result);
  114. return $result;
  115. }
  116. public function readVarint(&$result) {
  117. $idx = 0;
  118. $shift = 0;
  119. $result = 0;
  120. while (true) {
  121. $x = $this->trans_->readAll(1);
  122. $arr = unpack('C', $x);
  123. $byte = $arr[1];
  124. $idx += 1;
  125. $result |= ($byte & 0x7f) << $shift;
  126. if (($byte >> 7) === 0) {
  127. return $idx;
  128. }
  129. $shift += 7;
  130. }
  131. return $idx;
  132. }
  133. public function __construct($trans) {
  134. parent::__construct($trans);
  135. }
  136. public function writeMessageBegin($name, $type, $seqid) {
  137. $written =
  138. $this->writeUByte(TCompactProtocol::PROTOCOL_ID) +
  139. $this->writeUByte(TCompactProtocol::VERSION |
  140. ($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) +
  141. $this->writeVarint($seqid) +
  142. $this->writeString($name);
  143. $this->state = TCompactProtocol::STATE_VALUE_WRITE;
  144. return $written;
  145. }
  146. public function writeMessageEnd() {
  147. $this->state = TCompactProtocol::STATE_CLEAR;
  148. return 0;
  149. }
  150. public function writeStructBegin($name) {
  151. $this->structs[] = array($this->state, $this->lastFid);
  152. $this->state = TCompactProtocol::STATE_FIELD_WRITE;
  153. $this->lastFid = 0;
  154. return 0;
  155. }
  156. public function writeStructEnd() {
  157. $old_values = array_pop($this->structs);
  158. $this->state = $old_values[0];
  159. $this->lastFid = $old_values[1];
  160. return 0;
  161. }
  162. public function writeFieldStop() {
  163. return $this->writeByte(0);
  164. }
  165. public function writeFieldHeader($type, $fid) {
  166. $written = 0;
  167. $delta = $fid - $this->lastFid;
  168. if (0 < $delta && $delta <= 15) {
  169. $written = $this->writeUByte(($delta << 4) | $type);
  170. } else {
  171. $written = $this->writeByte($type) +
  172. $this->writeI16($fid);
  173. }
  174. $this->lastFid = $fid;
  175. return $written;
  176. }
  177. public function writeFieldBegin($field_name, $field_type, $field_id) {
  178. if ($field_type == TTYPE::BOOL) {
  179. $this->state = TCompactProtocol::STATE_BOOL_WRITE;
  180. $this->boolFid = $field_id;
  181. return 0;
  182. } else {
  183. $this->state = TCompactProtocol::STATE_VALUE_WRITE;
  184. return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id);
  185. }
  186. }
  187. public function writeFieldEnd() {
  188. $this->state = TCompactProtocol::STATE_FIELD_WRITE;
  189. return 0;
  190. }
  191. public function writeCollectionBegin($etype, $size) {
  192. $written = 0;
  193. if ($size <= 14) {
  194. $written = $this->writeUByte($size << 4 |
  195. self::$ctypes[$etype]);
  196. } else {
  197. $written = $this->writeUByte(0xf0 |
  198. self::$ctypes[$etype]) +
  199. $this->writeVarint($size);
  200. }
  201. $this->containers[] = $this->state;
  202. $this->state = TCompactProtocol::STATE_CONTAINER_WRITE;
  203. return $written;
  204. }
  205. public function writeMapBegin($key_type, $val_type, $size) {
  206. $written = 0;
  207. if ($size == 0) {
  208. $written = $this->writeByte(0);
  209. } else {
  210. $written = $this->writeVarint($size) +
  211. $this->writeUByte(self::$ctypes[$key_type] << 4 |
  212. self::$ctypes[$val_type]);
  213. }
  214. $this->containers[] = $this->state;
  215. return $written;
  216. }
  217. public function writeCollectionEnd() {
  218. $this->state = array_pop($this->containers);
  219. return 0;
  220. }
  221. public function writeMapEnd() {
  222. return $this->writeCollectionEnd();
  223. }
  224. public function writeListBegin($elem_type, $size) {
  225. return $this->writeCollectionBegin($elem_type, $size);
  226. }
  227. public function writeListEnd() {
  228. return $this->writeCollectionEnd();
  229. }
  230. public function writeSetBegin($elem_type, $size) {
  231. return $this->writeCollectionBegin($elem_type, $size);
  232. }
  233. public function writeSetEnd() {
  234. return $this->writeCollectionEnd();
  235. }
  236. public function writeBool($value) {
  237. if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) {
  238. $ctype = TCompactProtocol::COMPACT_FALSE;
  239. if ($value) {
  240. $ctype = TCompactProtocol::COMPACT_TRUE;
  241. }
  242. return $this->writeFieldHeader($ctype, $this->boolFid);
  243. } else if ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) {
  244. return $this->writeByte($value ? 1 : 0);
  245. } else {
  246. throw new TProtocolException('Invalid state in compact protocol');
  247. }
  248. }
  249. public function writeByte($value) {
  250. $data = pack('c', $value);
  251. $this->trans_->write($data, 1);
  252. return 1;
  253. }
  254. public function writeUByte($byte) {
  255. $this->trans_->write(pack('C', $byte), 1);
  256. return 1;
  257. }
  258. public function writeI16($value) {
  259. $thing = $this->toZigZag($value, 16);
  260. return $this->writeVarint($thing);
  261. }
  262. public function writeI32($value) {
  263. $thing = $this->toZigZag($value, 32);
  264. return $this->writeVarint($thing);
  265. }
  266. public function writeDouble($value) {
  267. $data = pack('d', $value);
  268. $this->trans_->write(strrev($data), 8);
  269. return 8;
  270. }
  271. public function writeString($value) {
  272. $len = strlen($value);
  273. $result = $this->writeVarint($len);
  274. if ($len) {
  275. $this->trans_->write($value, $len);
  276. }
  277. return $result + $len;
  278. }
  279. public function readFieldBegin(&$name, &$field_type, &$field_id) {
  280. $result = $this->readUByte($field_type);
  281. if (($field_type & 0x0f) == TType::STOP) {
  282. $field_id = 0;
  283. return $result;
  284. }
  285. $delta = $field_type >> 4;
  286. if ($delta == 0) {
  287. $result += $this->readI16($field_id);
  288. } else {
  289. $field_id = $this->lastFid + $delta;
  290. }
  291. $this->lastFid = $field_id;
  292. $field_type = $this->getTType($field_type & 0x0f);
  293. if ($field_type == TCompactProtocol::COMPACT_TRUE) {
  294. $this->state = TCompactProtocol::STATE_BOOL_READ;
  295. $this->boolValue = true;
  296. } else if ($field_type == TCompactProtocol::COMPACT_FALSE) {
  297. $this->state = TCompactProtocol::STATE_BOOL_READ;
  298. $this->boolValue = false;
  299. } else {
  300. $this->state = TCompactProtocol::STATE_VALUE_READ;
  301. }
  302. return $result;
  303. }
  304. public function readFieldEnd() {
  305. $this->state = TCompactProtocol::STATE_FIELD_READ;
  306. return 0;
  307. }
  308. public function readUByte(&$value) {
  309. $data = $this->trans_->readAll(1);
  310. $arr = unpack('C', $data);
  311. $value = $arr[1];
  312. return 1;
  313. }
  314. public function readByte(&$value) {
  315. $data = $this->trans_->readAll(1);
  316. $arr = unpack('c', $data);
  317. $value = $arr[1];
  318. return 1;
  319. }
  320. public function readZigZag(&$value) {
  321. $result = $this->readVarint($value);
  322. $value = $this->fromZigZag($value);
  323. return $result;
  324. }
  325. public function readMessageBegin(&$name, &$type, &$seqid) {
  326. $protoId = 0;
  327. $result = $this->readUByte($protoId);
  328. if ($protoId != TCompactProtocol::PROTOCOL_ID) {
  329. throw new TProtocolException('Bad protocol id in TCompact message');
  330. }
  331. $verType = 0;
  332. $result += $this->readUByte($verType);
  333. $type = ($verType & TCompactProtocol::TYPE_MASK) >>
  334. TCompactProtocol::TYPE_SHIFT_AMOUNT;
  335. $version = $verType & TCompactProtocol::VERSION_MASK;
  336. if ($version != TCompactProtocol::VERSION) {
  337. throw new TProtocolException('Bad version in TCompact message');
  338. }
  339. $result += $this->readVarint($seqId);
  340. $name += $this->readString($name);
  341. return $result;
  342. }
  343. public function readMessageEnd() {
  344. return 0;
  345. }
  346. public function readStructBegin(&$name) {
  347. $name = ''; // unused
  348. $this->structs[] = array($this->state, $this->lastFid);
  349. $this->state = TCompactProtocol::STATE_FIELD_READ;
  350. $this->lastFid = 0;
  351. return 0;
  352. }
  353. public function readStructEnd() {
  354. $last = array_pop($this->structs);
  355. $this->state = $last[0];
  356. $this->lastFid = $last[1];
  357. return 0;
  358. }
  359. public function readCollectionBegin(&$type, &$size) {
  360. $sizeType = 0;
  361. $result = $this->readUByte($sizeType);
  362. $size = $sizeType >> 4;
  363. $type = $this->getTType($sizeType);
  364. if ($size == 15) {
  365. $result += $this->readVarint($size);
  366. }
  367. $this->containers[] = $this->state;
  368. $this->state = TCompactProtocol::STATE_CONTAINER_READ;
  369. return $result;
  370. }
  371. public function readMapBegin(&$key_type, &$val_type, &$size) {
  372. $result = $this->readVarint($size);
  373. $types = 0;
  374. if ($size > 0) {
  375. $result += $this->readUByte($types);
  376. }
  377. $val_type = $this->getTType($types);
  378. $key_type = $this->getTType($types >> 4);
  379. $this->containers[] = $this->state;
  380. $this->state = TCompactProtocol::STATE_CONTAINER_READ;
  381. return $result;
  382. }
  383. public function readCollectionEnd() {
  384. $this->state = array_pop($this->containers);
  385. return 0;
  386. }
  387. public function readMapEnd() {
  388. return $this->readCollectionEnd();
  389. }
  390. public function readListBegin(&$elem_type, &$size) {
  391. return $this->readCollectionBegin($elem_type, $size);
  392. }
  393. public function readListEnd() {
  394. return $this->readCollectionEnd();
  395. }
  396. public function readSetBegin(&$elem_type, &$size) {
  397. return $this->readCollectionBegin($elem_type, $size);
  398. }
  399. public function readSetEnd() {
  400. return $this->readCollectionEnd();
  401. }
  402. public function readBool(&$value) {
  403. if ($this->state == TCompactProtocol::STATE_BOOL_READ) {
  404. $value = $this->boolValue;
  405. return 0;
  406. } else if ($this->state == TCompactProtocol::STATE_CONTAINER_READ) {
  407. return $this->readByte($value);
  408. } else {
  409. throw new TProtocolException('Invalid state in compact protocol');
  410. }
  411. }
  412. public function readI16(&$value) {
  413. return $this->readZigZag($value);
  414. }
  415. public function readI32(&$value) {
  416. return $this->readZigZag($value);
  417. }
  418. public function readDouble(&$value) {
  419. $data = strrev($this->trans_->readAll(8));
  420. $arr = unpack('d', $data);
  421. $value = $arr[1];
  422. return 8;
  423. }
  424. public function readString(&$value) {
  425. $result = $this->readVarint($len);
  426. if ($len) {
  427. $value = $this->trans_->readAll($len);
  428. } else {
  429. $value = '';
  430. }
  431. return $result + $len;
  432. }
  433. public function getTType($byte) {
  434. return self::$ttypes[$byte & 0x0f];
  435. }
  436. // If we are on a 32bit architecture we have to explicitly deal with
  437. // 64-bit twos-complement arithmetic since PHP wants to treat all ints
  438. // as signed and any int over 2^31 - 1 as a float
  439. // Read and write I64 as two 32 bit numbers $hi and $lo
  440. public function readI64(&$value) {
  441. // Read varint from wire
  442. $hi = 0;
  443. $lo = 0;
  444. $idx = 0;
  445. $shift = 0;
  446. while (true) {
  447. $x = $this->trans_->readAll(1);
  448. $arr = unpack('C', $x);
  449. $byte = $arr[1];
  450. $idx += 1;
  451. if ($shift < 32) {
  452. $lo |= (($byte & 0x7f) << $shift) &
  453. 0x00000000ffffffff;
  454. }
  455. // Shift hi and lo together.
  456. if ($shift >= 32) {
  457. $hi |= (($byte & 0x7f) << ($shift - 32));
  458. } else if ($shift > 25) {
  459. $hi |= (($byte & 0x7f) >> ($shift - 25));
  460. }
  461. if (($byte >> 7) === 0) {
  462. break;
  463. }
  464. $shift += 7;
  465. }
  466. // Now, unzig it.
  467. $xorer = 0;
  468. if ($lo & 1) {
  469. $xorer = 0xffffffff;
  470. }
  471. $lo = ($lo >> 1) & 0x7fffffff;
  472. $lo = $lo | (($hi & 1) << 31);
  473. $hi = ($hi >> 1) ^ $xorer;
  474. $lo = $lo ^ $xorer;
  475. // Now put $hi and $lo back together
  476. if (true) {
  477. $isNeg = $hi < 0;
  478. // Check for a negative
  479. if ($isNeg) {
  480. $hi = ~$hi & (int)0xffffffff;
  481. $lo = ~$lo & (int)0xffffffff;
  482. if ($lo == (int)0xffffffff) {
  483. $hi++;
  484. $lo = 0;
  485. } else {
  486. $lo++;
  487. }
  488. }
  489. // Force 32bit words in excess of 2G to be positive - we deal with sign
  490. // explicitly below
  491. if ($hi & (int)0x80000000) {
  492. $hi &= (int)0x7fffffff;
  493. $hi += 0x80000000;
  494. }
  495. if ($lo & (int)0x80000000) {
  496. $lo &= (int)0x7fffffff;
  497. $lo += 0x80000000;
  498. }
  499. $value = $hi * 4294967296 + $lo;
  500. if ($isNeg) {
  501. $value = 0 - $value;
  502. }
  503. } else {
  504. // Upcast negatives in LSB bit
  505. if ($arr[2] & 0x80000000) {
  506. $arr[2] = $arr[2] & 0xffffffff;
  507. }
  508. // Check for a negative
  509. if ($arr[1] & 0x80000000) {
  510. $arr[1] = $arr[1] & 0xffffffff;
  511. $arr[1] = $arr[1] ^ 0xffffffff;
  512. $arr[2] = $arr[2] ^ 0xffffffff;
  513. $value = 0 - $arr[1] * 4294967296 - $arr[2] - 1;
  514. } else {
  515. $value = $arr[1] * 4294967296 + $arr[2];
  516. }
  517. }
  518. return $idx;
  519. }
  520. public function writeI64($value) {
  521. // If we are in an I32 range, use the easy method below.
  522. if (($value > 4294967296) || ($value < -4294967296)) {
  523. // Convert $value to $hi and $lo
  524. $neg = $value < 0;
  525. if ($neg) {
  526. $value *= -1;
  527. }
  528. $hi = (int)$value >> 32;
  529. $lo = (int)$value & 0xffffffff;
  530. if ($neg) {
  531. $hi = ~$hi;
  532. $lo = ~$lo;
  533. if (($lo & (int)0xffffffff) == (int)0xffffffff) {
  534. $lo = 0;
  535. $hi++;
  536. } else {
  537. $lo++;
  538. }
  539. }
  540. // Now do the zigging and zagging.
  541. $xorer = 0;
  542. if ($neg) {
  543. $xorer = 0xffffffff;
  544. }
  545. $lowbit = ($lo >> 31) & 1;
  546. $hi = ($hi << 1) | $lowbit;
  547. $lo = ($lo << 1);
  548. $lo = ($lo ^ $xorer) & 0xffffffff;
  549. $hi = ($hi ^ $xorer) & 0xffffffff;
  550. // now write out the varint, ensuring we shift both hi and lo
  551. $out = "";
  552. while (true) {
  553. if (($lo & ~0x7f) === 0 &&
  554. $hi === 0) {
  555. $out .= chr($lo);
  556. break;
  557. } else {
  558. $out .= chr(($lo & 0xff) | 0x80);
  559. $lo = $lo >> 7;
  560. $lo = $lo | ($hi << 25);
  561. $hi = $hi >> 7;
  562. // Right shift carries sign, but we don't want it to.
  563. $hi = $hi & (127 << 25);
  564. }
  565. }
  566. $ret = strlen($out);
  567. $this->trans_->write($out, $ret);
  568. return $ret;
  569. } else {
  570. return $this->writeVarint($this->toZigZag($value, 64));
  571. }
  572. }
  573. }
  574. /**
  575. * Compact Protocol Factory
  576. */
  577. class TCompcatProtocolFactory implements TProtocolFactory {
  578. public function __construct() {
  579. }
  580. public function getProtocol($trans) {
  581. return new TCompactProtocol($trans);
  582. }
  583. }