GPBWire.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. <?php
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. namespace Google\Protobuf\Internal;
  32. class GPBWire
  33. {
  34. const TAG_TYPE_BITS = 3;
  35. const WIRETYPE_VARINT = 0;
  36. const WIRETYPE_FIXED64 = 1;
  37. const WIRETYPE_LENGTH_DELIMITED = 2;
  38. const WIRETYPE_START_GROUP = 3;
  39. const WIRETYPE_END_GROUP = 4;
  40. const WIRETYPE_FIXED32 = 5;
  41. const UNKNOWN = 0;
  42. const NORMAL_FORMAT = 1;
  43. const PACKED_FORMAT = 2;
  44. public static function getTagFieldNumber($tag)
  45. {
  46. // We have to mask because PHP has no arithmetic shift.
  47. return ($tag >> self::TAG_TYPE_BITS) & 0x1fffffff;
  48. }
  49. public static function getTagWireType($tag)
  50. {
  51. return $tag & 0x7;
  52. }
  53. public static function getWireType($type)
  54. {
  55. switch ($type) {
  56. case GPBType::FLOAT:
  57. case GPBType::FIXED32:
  58. case GPBType::SFIXED32:
  59. return self::WIRETYPE_FIXED32;
  60. case GPBType::DOUBLE:
  61. case GPBType::FIXED64:
  62. case GPBType::SFIXED64:
  63. return self::WIRETYPE_FIXED64;
  64. case GPBType::UINT32:
  65. case GPBType::UINT64:
  66. case GPBType::INT32:
  67. case GPBType::INT64:
  68. case GPBType::SINT32:
  69. case GPBType::SINT64:
  70. case GPBType::ENUM:
  71. case GPBType::BOOL:
  72. return self::WIRETYPE_VARINT;
  73. case GPBType::STRING:
  74. case GPBType::BYTES:
  75. case GPBType::MESSAGE:
  76. return self::WIRETYPE_LENGTH_DELIMITED;
  77. case GPBType::GROUP:
  78. user_error("Unsupported type.");
  79. return 0;
  80. default:
  81. user_error("Unsupported type.");
  82. return 0;
  83. }
  84. }
  85. // ZigZag Transform: Encodes signed integers so that they can be effectively
  86. // used with varint encoding.
  87. //
  88. // varint operates on unsigned integers, encoding smaller numbers into fewer
  89. // bytes. If you try to use it on a signed integer, it will treat this
  90. // number as a very large unsigned integer, which means that even small
  91. // signed numbers like -1 will take the maximum number of bytes (10) to
  92. // encode. zigZagEncode() maps signed integers to unsigned in such a way
  93. // that those with a small absolute value will have smaller encoded values,
  94. // making them appropriate for encoding using varint.
  95. //
  96. // int32 -> uint32
  97. // -------------------------
  98. // 0 -> 0
  99. // -1 -> 1
  100. // 1 -> 2
  101. // -2 -> 3
  102. // ... -> ...
  103. // 2147483647 -> 4294967294
  104. // -2147483648 -> 4294967295
  105. //
  106. // >> encode >>
  107. // << decode <<
  108. public static function zigZagEncode32($int32)
  109. {
  110. if (PHP_INT_SIZE == 8) {
  111. $trim_int32 = $int32 & 0xFFFFFFFF;
  112. return (($trim_int32 << 1) ^ ($int32 << 32 >> 63)) & 0xFFFFFFFF;
  113. } else {
  114. return ($int32 << 1) ^ ($int32 >> 31);
  115. }
  116. }
  117. public static function zigZagDecode32($uint32)
  118. {
  119. // Fill high 32 bits.
  120. if (PHP_INT_SIZE === 8) {
  121. $uint32 |= ($uint32 & 0xFFFFFFFF);
  122. }
  123. $int32 = (($uint32 >> 1) & 0x7FFFFFFF) ^ (-($uint32 & 1));
  124. return $int32;
  125. }
  126. public static function zigZagEncode64($int64)
  127. {
  128. if (PHP_INT_SIZE == 4) {
  129. if (bccomp($int64, 0) >= 0) {
  130. return bcmul($int64, 2);
  131. } else {
  132. return bcsub(bcmul(bcsub(0, $int64), 2), 1);
  133. }
  134. } else {
  135. return ($int64 << 1) ^ ($int64 >> 63);
  136. }
  137. }
  138. public static function zigZagDecode64($uint64)
  139. {
  140. if (PHP_INT_SIZE == 4) {
  141. if (bcmod($uint64, 2) == 0) {
  142. return bcdiv($uint64, 2, 0);
  143. } else {
  144. return bcsub(0, bcdiv(bcadd($uint64, 1), 2, 0));
  145. }
  146. } else {
  147. return (($uint64 >> 1) & 0x7FFFFFFFFFFFFFFF) ^ (-($uint64 & 1));
  148. }
  149. }
  150. public static function readInt32(&$input, &$value)
  151. {
  152. return $input->readVarint32($value);
  153. }
  154. public static function readInt64(&$input, &$value)
  155. {
  156. $success = $input->readVarint64($value);
  157. if (PHP_INT_SIZE == 4 && bccomp($value, "9223372036854775807") > 0) {
  158. $value = bcsub($value, "18446744073709551616");
  159. }
  160. return $success;
  161. }
  162. public static function readUint32(&$input, &$value)
  163. {
  164. return self::readInt32($input, $value);
  165. }
  166. public static function readUint64(&$input, &$value)
  167. {
  168. return self::readInt64($input, $value);
  169. }
  170. public static function readSint32(&$input, &$value)
  171. {
  172. if (!$input->readVarint32($value)) {
  173. return false;
  174. }
  175. $value = GPBWire::zigZagDecode32($value);
  176. return true;
  177. }
  178. public static function readSint64(&$input, &$value)
  179. {
  180. if (!$input->readVarint64($value)) {
  181. return false;
  182. }
  183. $value = GPBWire::zigZagDecode64($value);
  184. return true;
  185. }
  186. public static function readFixed32(&$input, &$value)
  187. {
  188. return $input->readLittleEndian32($value);
  189. }
  190. public static function readFixed64(&$input, &$value)
  191. {
  192. return $input->readLittleEndian64($value);
  193. }
  194. public static function readSfixed32(&$input, &$value)
  195. {
  196. if (!self::readFixed32($input, $value)) {
  197. return false;
  198. }
  199. if (PHP_INT_SIZE === 8) {
  200. $value |= (-($value >> 31) << 32);
  201. }
  202. return true;
  203. }
  204. public static function readSfixed64(&$input, &$value)
  205. {
  206. $success = $input->readLittleEndian64($value);
  207. if (PHP_INT_SIZE == 4 && bccomp($value, "9223372036854775807") > 0) {
  208. $value = bcsub($value, "18446744073709551616");
  209. }
  210. return $success;
  211. }
  212. public static function readFloat(&$input, &$value)
  213. {
  214. $data = null;
  215. if (!$input->readRaw(4, $data)) {
  216. return false;
  217. }
  218. $value = unpack('f', $data)[1];
  219. return true;
  220. }
  221. public static function readDouble(&$input, &$value)
  222. {
  223. $data = null;
  224. if (!$input->readRaw(8, $data)) {
  225. return false;
  226. }
  227. $value = unpack('d', $data)[1];
  228. return true;
  229. }
  230. public static function readBool(&$input, &$value)
  231. {
  232. if (!$input->readVarint64($value)) {
  233. return false;
  234. }
  235. if ($value == 0) {
  236. $value = false;
  237. } else {
  238. $value = true;
  239. }
  240. return true;
  241. }
  242. public static function readString(&$input, &$value)
  243. {
  244. $length = 0;
  245. return $input->readVarintSizeAsInt($length) && $input->readRaw($length, $value);
  246. }
  247. public static function readMessage(&$input, &$message)
  248. {
  249. $length = 0;
  250. if (!$input->readVarintSizeAsInt($length)) {
  251. return false;
  252. }
  253. $old_limit = 0;
  254. $recursion_limit = 0;
  255. $input->incrementRecursionDepthAndPushLimit(
  256. $length,
  257. $old_limit,
  258. $recursion_limit);
  259. if ($recursion_limit < 0 || !$message->parseFromStream($input)) {
  260. return false;
  261. }
  262. return $input->decrementRecursionDepthAndPopLimit($old_limit);
  263. }
  264. public static function writeTag(&$output, $tag)
  265. {
  266. return $output->writeTag($tag);
  267. }
  268. public static function writeInt32(&$output, $value)
  269. {
  270. return $output->writeVarint32($value, false);
  271. }
  272. public static function writeInt64(&$output, $value)
  273. {
  274. return $output->writeVarint64($value);
  275. }
  276. public static function writeUint32(&$output, $value)
  277. {
  278. return $output->writeVarint32($value, true);
  279. }
  280. public static function writeUint64(&$output, $value)
  281. {
  282. return $output->writeVarint64($value);
  283. }
  284. public static function writeSint32(&$output, $value)
  285. {
  286. $value = GPBWire::zigZagEncode32($value);
  287. return $output->writeVarint32($value, true);
  288. }
  289. public static function writeSint64(&$output, $value)
  290. {
  291. $value = GPBWire::zigZagEncode64($value);
  292. return $output->writeVarint64($value);
  293. }
  294. public static function writeFixed32(&$output, $value)
  295. {
  296. return $output->writeLittleEndian32($value);
  297. }
  298. public static function writeFixed64(&$output, $value)
  299. {
  300. return $output->writeLittleEndian64($value);
  301. }
  302. public static function writeSfixed32(&$output, $value)
  303. {
  304. return $output->writeLittleEndian32($value);
  305. }
  306. public static function writeSfixed64(&$output, $value)
  307. {
  308. return $output->writeLittleEndian64($value);
  309. }
  310. public static function writeBool(&$output, $value)
  311. {
  312. if ($value) {
  313. return $output->writeVarint32(1, true);
  314. } else {
  315. return $output->writeVarint32(0, true);
  316. }
  317. }
  318. public static function writeFloat(&$output, $value)
  319. {
  320. $data = pack("f", $value);
  321. return $output->writeRaw($data, 4);
  322. }
  323. public static function writeDouble(&$output, $value)
  324. {
  325. $data = pack("d", $value);
  326. return $output->writeRaw($data, 8);
  327. }
  328. public static function writeString(&$output, $value)
  329. {
  330. return self::writeBytes($output, $value);
  331. }
  332. public static function writeBytes(&$output, $value)
  333. {
  334. $size = strlen($value);
  335. if (!$output->writeVarint32($size, true)) {
  336. return false;
  337. }
  338. return $output->writeRaw($value, $size);
  339. }
  340. public static function writeMessage(&$output, $value)
  341. {
  342. $size = $value->byteSize();
  343. if (!$output->writeVarint32($size, true)) {
  344. return false;
  345. }
  346. return $value->serializeToStream($output);
  347. }
  348. public static function makeTag($number, $type)
  349. {
  350. return ($number << 3) | self::getWireType($type);
  351. }
  352. public static function tagSize($field)
  353. {
  354. $tag = self::makeTag($field->getNumber(), $field->getType());
  355. return self::varint32Size($tag);
  356. }
  357. public static function varint32Size($value, $sign_extended = false)
  358. {
  359. if ($value < 0) {
  360. if ($sign_extended) {
  361. return 10;
  362. } else {
  363. return 5;
  364. }
  365. }
  366. if ($value < (1 << 7)) {
  367. return 1;
  368. }
  369. if ($value < (1 << 14)) {
  370. return 2;
  371. }
  372. if ($value < (1 << 21)) {
  373. return 3;
  374. }
  375. if ($value < (1 << 28)) {
  376. return 4;
  377. }
  378. return 5;
  379. }
  380. public static function sint32Size($value)
  381. {
  382. $value = self::zigZagEncode32($value);
  383. return self::varint32Size($value);
  384. }
  385. public static function sint64Size($value)
  386. {
  387. $value = self::zigZagEncode64($value);
  388. return self::varint64Size($value);
  389. }
  390. public static function varint64Size($value)
  391. {
  392. if (PHP_INT_SIZE == 4) {
  393. if (bccomp($value, 0) < 0 ||
  394. bccomp($value, "9223372036854775807") > 0) {
  395. return 10;
  396. }
  397. if (bccomp($value, 1 << 7) < 0) {
  398. return 1;
  399. }
  400. if (bccomp($value, 1 << 14) < 0) {
  401. return 2;
  402. }
  403. if (bccomp($value, 1 << 21) < 0) {
  404. return 3;
  405. }
  406. if (bccomp($value, 1 << 28) < 0) {
  407. return 4;
  408. }
  409. if (bccomp($value, '34359738368') < 0) {
  410. return 5;
  411. }
  412. if (bccomp($value, '4398046511104') < 0) {
  413. return 6;
  414. }
  415. if (bccomp($value, '562949953421312') < 0) {
  416. return 7;
  417. }
  418. if (bccomp($value, '72057594037927936') < 0) {
  419. return 8;
  420. }
  421. return 9;
  422. } else {
  423. if ($value < 0) {
  424. return 10;
  425. }
  426. if ($value < (1 << 7)) {
  427. return 1;
  428. }
  429. if ($value < (1 << 14)) {
  430. return 2;
  431. }
  432. if ($value < (1 << 21)) {
  433. return 3;
  434. }
  435. if ($value < (1 << 28)) {
  436. return 4;
  437. }
  438. if ($value < (1 << 35)) {
  439. return 5;
  440. }
  441. if ($value < (1 << 42)) {
  442. return 6;
  443. }
  444. if ($value < (1 << 49)) {
  445. return 7;
  446. }
  447. if ($value < (1 << 56)) {
  448. return 8;
  449. }
  450. return 9;
  451. }
  452. }
  453. public static function serializeFieldToStream(
  454. $value,
  455. $field,
  456. $need_tag,
  457. &$output)
  458. {
  459. if ($need_tag) {
  460. if (!GPBWire::writeTag(
  461. $output,
  462. self::makeTag(
  463. $field->getNumber(),
  464. $field->getType()))) {
  465. return false;
  466. }
  467. }
  468. switch ($field->getType()) {
  469. case GPBType::DOUBLE:
  470. if (!GPBWire::writeDouble($output, $value)) {
  471. return false;
  472. }
  473. break;
  474. case GPBType::FLOAT:
  475. if (!GPBWire::writeFloat($output, $value)) {
  476. return false;
  477. }
  478. break;
  479. case GPBType::INT64:
  480. if (!GPBWire::writeInt64($output, $value)) {
  481. return false;
  482. }
  483. break;
  484. case GPBType::UINT64:
  485. if (!GPBWire::writeUint64($output, $value)) {
  486. return false;
  487. }
  488. break;
  489. case GPBType::INT32:
  490. if (!GPBWire::writeInt32($output, $value)) {
  491. return false;
  492. }
  493. break;
  494. case GPBType::FIXED32:
  495. if (!GPBWire::writeFixed32($output, $value)) {
  496. return false;
  497. }
  498. break;
  499. case GPBType::FIXED64:
  500. if (!GPBWire::writeFixed64($output, $value)) {
  501. return false;
  502. }
  503. break;
  504. case GPBType::BOOL:
  505. if (!GPBWire::writeBool($output, $value)) {
  506. return false;
  507. }
  508. break;
  509. case GPBType::STRING:
  510. if (!GPBWire::writeString($output, $value)) {
  511. return false;
  512. }
  513. break;
  514. // case GPBType::GROUP:
  515. // echo "GROUP\xA";
  516. // trigger_error("Not implemented.", E_ERROR);
  517. // break;
  518. case GPBType::MESSAGE:
  519. if (!GPBWire::writeMessage($output, $value)) {
  520. return false;
  521. }
  522. break;
  523. case GPBType::BYTES:
  524. if (!GPBWire::writeBytes($output, $value)) {
  525. return false;
  526. }
  527. break;
  528. case GPBType::UINT32:
  529. if (PHP_INT_SIZE === 8 && $value < 0) {
  530. $value += 4294967296;
  531. }
  532. if (!GPBWire::writeUint32($output, $value)) {
  533. return false;
  534. }
  535. break;
  536. case GPBType::ENUM:
  537. if (!GPBWire::writeInt32($output, $value)) {
  538. return false;
  539. }
  540. break;
  541. case GPBType::SFIXED32:
  542. if (!GPBWire::writeSfixed32($output, $value)) {
  543. return false;
  544. }
  545. break;
  546. case GPBType::SFIXED64:
  547. if (!GPBWire::writeSfixed64($output, $value)) {
  548. return false;
  549. }
  550. break;
  551. case GPBType::SINT32:
  552. if (!GPBWire::writeSint32($output, $value)) {
  553. return false;
  554. }
  555. break;
  556. case GPBType::SINT64:
  557. if (!GPBWire::writeSint64($output, $value)) {
  558. return false;
  559. }
  560. break;
  561. default:
  562. user_error("Unsupported type.");
  563. return false;
  564. }
  565. return true;
  566. }
  567. }