/src/pocketmine/utils/Binary.php

https://gitlab.com/wesleyvanneck/ImagicalMine · PHP · 596 lines · 286 code · 80 blank · 230 comment · 27 complexity · ae190f6de2cb985b1ab86751942b4f14 MD5 · raw file

  1. <?php
  2. /**
  3. * src/pocketmine/utils/Binary.php
  4. *
  5. * @package default
  6. */
  7. /*
  8. *
  9. * _ _ _ __ __ _
  10. * (_) (_) | | \/ (_)
  11. * _ _ __ ___ __ _ __ _ _ ___ __ _| | \ / |_ _ __ ___
  12. * | | '_ ` _ \ / _` |/ _` | |/ __/ _` | | |\/| | | '_ \ / _ \
  13. * | | | | | | | (_| | (_| | | (_| (_| | | | | | | | | | __/
  14. * |_|_| |_| |_|\__,_|\__, |_|\___\__,_|_|_| |_|_|_| |_|\___|
  15. * __/ |
  16. * |___/
  17. *
  18. * This program is a third party build by ImagicalMine.
  19. *
  20. * PocketMine is free software: you can redistribute it and/or modify
  21. * it under the terms of the GNU Lesser General Public License as published by
  22. * the Free Software Foundation, either version 3 of the License, or
  23. * (at your option) any later version.
  24. *
  25. * @author ImagicalMine Team
  26. * @link http://forums.imagicalcorp.ml/
  27. *
  28. *
  29. */
  30. /**
  31. * Various Utilities used around the code
  32. */
  33. namespace pocketmine\utils;
  34. use pocketmine\entity\Entity;
  35. class Binary
  36. {
  37. const BIG_ENDIAN = 0x00;
  38. const LITTLE_ENDIAN = 0x01;
  39. /**
  40. * Reads a 3-byte big-endian number
  41. *
  42. *
  43. * @param unknown $str
  44. * @return mixed
  45. */
  46. public static function readTriad($str)
  47. {
  48. return unpack("N", "\x00" . $str)[1];
  49. }
  50. /**
  51. * Writes a 3-byte big-endian number
  52. *
  53. *
  54. * @param unknown $value
  55. * @return string
  56. */
  57. public static function writeTriad($value)
  58. {
  59. return substr(pack("N", $value), 1);
  60. }
  61. /**
  62. * Reads a 3-byte little-endian number
  63. *
  64. *
  65. * @param unknown $str
  66. * @return mixed
  67. */
  68. public static function readLTriad($str)
  69. {
  70. return unpack("V", $str . "\x00")[1];
  71. }
  72. /**
  73. * Writes a 3-byte little-endian number
  74. *
  75. *
  76. * @param unknown $value
  77. * @return string
  78. */
  79. public static function writeLTriad($value)
  80. {
  81. return substr(pack("V", $value), 0, -1);
  82. }
  83. /**
  84. * Writes a coded metadata string
  85. *
  86. *
  87. * @param array $data
  88. * @return string
  89. */
  90. public static function writeMetadata(array $data)
  91. {
  92. $m = "";
  93. foreach ($data as $bottom => $d) {
  94. $m .= chr(($d[0] << 5) | ($bottom & 0x1F));
  95. switch ($d[0]) {
  96. case Entity::DATA_TYPE_BYTE:
  97. $m .= self::writeByte($d[1]);
  98. break;
  99. case Entity::DATA_TYPE_SHORT:
  100. $m .= self::writeLShort($d[1]);
  101. break;
  102. case Entity::DATA_TYPE_INT:
  103. $m .= self::writeLInt($d[1]);
  104. break;
  105. case Entity::DATA_TYPE_FLOAT:
  106. $m .= self::writeLFloat($d[1]);
  107. break;
  108. case Entity::DATA_TYPE_STRING:
  109. $m .= self::writeLShort(strlen($d[1])) . $d[1];
  110. break;
  111. case Entity::DATA_TYPE_SLOT:
  112. $m .= self::writeLShort($d[1][0]);
  113. $m .= self::writeByte($d[1][1]);
  114. $m .= self::writeLShort($d[1][2]);
  115. break;
  116. case Entity::DATA_TYPE_POS:
  117. $m .= self::writeLInt($d[1][0]);
  118. $m .= self::writeLInt($d[1][1]);
  119. $m .= self::writeLInt($d[1][2]);
  120. break;
  121. case Entity::DATA_TYPE_LONG:
  122. $m .= self::writeLLong($d[1]);
  123. break;
  124. }
  125. }
  126. $m .= "\x7f";
  127. return $m;
  128. }
  129. /**
  130. * Reads a metadata coded string
  131. *
  132. *
  133. * @param unknown $value
  134. * @param bool $types (optional)
  135. * @return array
  136. */
  137. public static function readMetadata($value, $types = false)
  138. {
  139. $offset = 0;
  140. $m = [];
  141. $b = ord($value{$offset});
  142. ++$offset;
  143. while ($b !== 127 and isset($value{$offset})) {
  144. $bottom = $b & 0x1F;
  145. $type = $b >> 5;
  146. switch ($type) {
  147. case Entity::DATA_TYPE_BYTE:
  148. $r = self::readByte($value{$offset});
  149. ++$offset;
  150. break;
  151. case Entity::DATA_TYPE_SHORT:
  152. $r = self::readLShort(substr($value, $offset, 2));
  153. $offset += 2;
  154. break;
  155. case Entity::DATA_TYPE_INT:
  156. $r = self::readLInt(substr($value, $offset, 4));
  157. $offset += 4;
  158. break;
  159. case Entity::DATA_TYPE_FLOAT:
  160. $r = self::readLFloat(substr($value, $offset, 4));
  161. $offset += 4;
  162. break;
  163. case Entity::DATA_TYPE_STRING:
  164. $len = self::readLShort(substr($value, $offset, 2));
  165. $offset += 2;
  166. $r = substr($value, $offset, $len);
  167. $offset += $len;
  168. break;
  169. case Entity::DATA_TYPE_SLOT:
  170. $r = [];
  171. $r[] = self::readLShort(substr($value, $offset, 2));
  172. $offset += 2;
  173. $r[] = ord($value{$offset});
  174. ++$offset;
  175. $r[] = self::readLShort(substr($value, $offset, 2));
  176. $offset += 2;
  177. break;
  178. case Entity::DATA_TYPE_POS:
  179. $r = [];
  180. for ($i = 0; $i < 3; ++$i) {
  181. $r[] = self::readLInt(substr($value, $offset, 4));
  182. $offset += 4;
  183. }
  184. break;
  185. case Entity::DATA_TYPE_LONG:
  186. $r = self::readLLong(substr($value, $offset, 4));
  187. $offset += 8;
  188. break;
  189. default:
  190. return [];
  191. }
  192. if ($types === true) {
  193. $m[$bottom] = [$r, $type];
  194. } else {
  195. $m[$bottom] = $r;
  196. }
  197. $b = ord($value{$offset});
  198. ++$offset;
  199. }
  200. return $m;
  201. }
  202. /**
  203. * Reads a byte boolean
  204. *
  205. *
  206. * @param unknown $b
  207. * @return bool
  208. */
  209. public static function readBool($b)
  210. {
  211. return self::readByte($b, false) === 0 ? false : true;
  212. }
  213. /**
  214. * Writes a byte boolean
  215. *
  216. *
  217. * @param unknown $b
  218. * @return bool|string
  219. */
  220. public static function writeBool($b)
  221. {
  222. return self::writeByte($b === true ? 1 : 0);
  223. }
  224. /**
  225. * Reads an unsigned/signed byte
  226. *
  227. *
  228. * @param string $c
  229. * @param bool $signed (optional)
  230. * @return int
  231. */
  232. public static function readByte($c, $signed = true)
  233. {
  234. $b = ord($c{0});
  235. if ($signed) {
  236. if (PHP_INT_SIZE === 8) {
  237. return $b << 56 >> 56;
  238. } else {
  239. return $b << 24 >> 24;
  240. }
  241. } else {
  242. return $b;
  243. }
  244. }
  245. /**
  246. * Writes an unsigned/signed byte
  247. *
  248. *
  249. * @param unknown $c
  250. * @return string
  251. */
  252. public static function writeByte($c)
  253. {
  254. return chr($c);
  255. }
  256. /**
  257. * Reads a 16-bit unsigned big-endian number
  258. *
  259. *
  260. * @param unknown $str
  261. * @return int
  262. */
  263. public static function readShort($str)
  264. {
  265. return unpack("n", $str)[1];
  266. }
  267. /**
  268. * Reads a 16-bit signed big-endian number
  269. *
  270. *
  271. * @param unknown $str
  272. * @return int
  273. */
  274. public static function readSignedShort($str)
  275. {
  276. if (PHP_INT_SIZE === 8) {
  277. return unpack("n", $str)[1] << 48 >> 48;
  278. } else {
  279. return unpack("n", $str)[1] << 16 >> 16;
  280. }
  281. }
  282. /**
  283. * Writes a 16-bit signed/unsigned big-endian number
  284. *
  285. *
  286. * @param unknown $value
  287. * @return string
  288. */
  289. public static function writeShort($value)
  290. {
  291. return pack("n", $value);
  292. }
  293. /**
  294. * Reads a 16-bit unsigned little-endian number
  295. *
  296. *
  297. * @param unknown $str
  298. * @return int
  299. */
  300. public static function readLShort($str)
  301. {
  302. return unpack("v", $str)[1];
  303. }
  304. /**
  305. * Reads a 16-bit signed little-endian number
  306. *
  307. *
  308. * @param unknown $str
  309. * @return int
  310. */
  311. public static function readSignedLShort($str)
  312. {
  313. if (PHP_INT_SIZE === 8) {
  314. return unpack("v", $str)[1] << 48 >> 48;
  315. } else {
  316. return unpack("v", $str)[1] << 16 >> 16;
  317. }
  318. }
  319. /**
  320. * Writes a 16-bit signed/unsigned little-endian number
  321. *
  322. *
  323. * @param unknown $value
  324. * @return string
  325. */
  326. public static function writeLShort($value)
  327. {
  328. return pack("v", $value);
  329. }
  330. /**
  331. *
  332. * @param unknown $str
  333. * @return unknown
  334. */
  335. public static function readInt($str)
  336. {
  337. if (PHP_INT_SIZE === 8) {
  338. return unpack("N", $str)[1] << 32 >> 32;
  339. } else {
  340. return unpack("N", $str)[1];
  341. }
  342. }
  343. /**
  344. *
  345. * @param unknown $value
  346. * @return unknown
  347. */
  348. public static function writeInt($value)
  349. {
  350. return pack("N", $value);
  351. }
  352. /**
  353. *
  354. * @param unknown $str
  355. * @return unknown
  356. */
  357. public static function readLInt($str)
  358. {
  359. if (PHP_INT_SIZE === 8) {
  360. return unpack("V", $str)[1] << 32 >> 32;
  361. } else {
  362. return unpack("V", $str)[1];
  363. }
  364. }
  365. /**
  366. *
  367. * @param unknown $value
  368. * @return unknown
  369. */
  370. public static function writeLInt($value)
  371. {
  372. return pack("V", $value);
  373. }
  374. /**
  375. *
  376. * @param unknown $str
  377. * @return unknown
  378. */
  379. public static function readFloat($str)
  380. {
  381. return ENDIANNESS === self::BIG_ENDIAN ? unpack("f", $str)[1] : unpack("f", strrev($str))[1];
  382. }
  383. /**
  384. *
  385. * @param unknown $value
  386. * @return unknown
  387. */
  388. public static function writeFloat($value)
  389. {
  390. return ENDIANNESS === self::BIG_ENDIAN ? pack("f", $value) : strrev(pack("f", $value));
  391. }
  392. /**
  393. *
  394. * @param unknown $str
  395. * @return unknown
  396. */
  397. public static function readLFloat($str)
  398. {
  399. return ENDIANNESS === self::BIG_ENDIAN ? unpack("f", strrev($str))[1] : unpack("f", $str)[1];
  400. }
  401. /**
  402. *
  403. * @param unknown $value
  404. * @return unknown
  405. */
  406. public static function writeLFloat($value)
  407. {
  408. return ENDIANNESS === self::BIG_ENDIAN ? strrev(pack("f", $value)) : pack("f", $value);
  409. }
  410. /**
  411. *
  412. * @param unknown $value
  413. * @return unknown
  414. */
  415. public static function printFloat($value)
  416. {
  417. return preg_replace("/(\\.\\d+?)0+$/", "$1", sprintf("%F", $value));
  418. }
  419. /**
  420. *
  421. * @param unknown $str
  422. * @return unknown
  423. */
  424. public static function readDouble($str)
  425. {
  426. return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", $str)[1] : unpack("d", strrev($str))[1];
  427. }
  428. /**
  429. *
  430. * @param unknown $value
  431. * @return unknown
  432. */
  433. public static function writeDouble($value)
  434. {
  435. return ENDIANNESS === self::BIG_ENDIAN ? pack("d", $value) : strrev(pack("d", $value));
  436. }
  437. /**
  438. *
  439. * @param unknown $str
  440. * @return unknown
  441. */
  442. public static function readLDouble($str)
  443. {
  444. return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", strrev($str))[1] : unpack("d", $str)[1];
  445. }
  446. /**
  447. *
  448. * @param unknown $value
  449. * @return unknown
  450. */
  451. public static function writeLDouble($value)
  452. {
  453. return ENDIANNESS === self::BIG_ENDIAN ? strrev(pack("d", $value)) : pack("d", $value);
  454. }
  455. /**
  456. *
  457. * @param unknown $x
  458. * @return unknown
  459. */
  460. public static function readLong($x)
  461. {
  462. if (PHP_INT_SIZE === 8) {
  463. $int = unpack("N*", $x);
  464. return ($int[1] << 32) | $int[2];
  465. } else {
  466. $value = "0";
  467. for ($i = 0; $i < 8; $i += 2) {
  468. $value = bcmul($value, "65536", 0);
  469. $value = bcadd($value, self::readShort(substr($x, $i, 2)), 0);
  470. }
  471. if (bccomp($value, "9223372036854775807") == 1) {
  472. $value = bcadd($value, "-18446744073709551616");
  473. }
  474. return $value;
  475. }
  476. }
  477. /**
  478. *
  479. * @param unknown $value
  480. * @return unknown
  481. */
  482. public static function writeLong($value)
  483. {
  484. if (PHP_INT_SIZE === 8) {
  485. return pack("NN", $value >> 32, $value & 0xFFFFFFFF);
  486. } else {
  487. $x = "";
  488. if (bccomp($value, "0") == -1) {
  489. $value = bcadd($value, "18446744073709551616");
  490. }
  491. $x .= self::writeShort(bcmod(bcdiv($value, "281474976710656"), "65536"));
  492. $x .= self::writeShort(bcmod(bcdiv($value, "4294967296"), "65536"));
  493. $x .= self::writeShort(bcmod(bcdiv($value, "65536"), "65536"));
  494. $x .= self::writeShort(bcmod($value, "65536"));
  495. return $x;
  496. }
  497. }
  498. /**
  499. *
  500. * @param unknown $str
  501. * @return unknown
  502. */
  503. public static function readLLong($str)
  504. {
  505. return self::readLong(strrev($str));
  506. }
  507. /**
  508. *
  509. * @param unknown $value
  510. * @return unknown
  511. */
  512. public static function writeLLong($value)
  513. {
  514. return strrev(self::writeLong($value));
  515. }
  516. }