PocketMine-MP 5.17.1 git-df4ada81e5d74a14046f27cf44a37dcee69d657e
Binary.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20*/
21
22declare(strict_types=1);
23
27namespace pocketmine\utils;
28
29use InvalidArgumentException;
30use function chr;
31use function ord;
32use function pack;
33use function preg_replace;
34use function round;
35use function sprintf;
36use function strlen;
37use function substr;
38use function unpack;
39use const PHP_INT_MAX;
40
41class Binary{
42 private const SIZEOF_SHORT = 2;
43 private const SIZEOF_INT = 4;
44 private const SIZEOF_LONG = 8;
45
46 private const SIZEOF_FLOAT = 4;
47 private const SIZEOF_DOUBLE = 8;
48
49 public static function signByte(int $value) : int{
50 return $value << 56 >> 56;
51 }
52
53 public static function unsignByte(int $value) : int{
54 return $value & 0xff;
55 }
56
57 public static function signShort(int $value) : int{
58 return $value << 48 >> 48;
59 }
60
61 public static function unsignShort(int $value) : int{
62 return $value & 0xffff;
63 }
64
65 public static function signInt(int $value) : int{
66 return $value << 32 >> 32;
67 }
68
69 public static function unsignInt(int $value) : int{
70 return $value & 0xffffffff;
71 }
72
73 public static function flipShortEndianness(int $value) : int{
74 return self::readLShort(self::writeShort($value));
75 }
76
77 public static function flipIntEndianness(int $value) : int{
78 return self::readLInt(self::writeInt($value));
79 }
80
81 public static function flipLongEndianness(int $value) : int{
82 return self::readLLong(self::writeLong($value));
83 }
84
89 private static function safeUnpack(string $formatCode, string $bytes, int $needLength) : array{
90 $haveLength = strlen($bytes);
91 if($haveLength < $needLength){
92 throw new BinaryDataException("Not enough bytes: need $needLength, have $haveLength");
93 }
94 //unpack SUCKS SO BADLY. We really need an extension to replace this garbage :(
95 $result = unpack($formatCode, $bytes);
96 if($result === false){
97 //this should never happen; we checked the length above
98 throw new \AssertionError("unpack() failed for unknown reason");
99 }
100 return $result;
101 }
102
106 public static function readBool(string $b) : bool{
107 return $b[0] !== "\x00";
108 }
109
113 public static function writeBool(bool $b) : string{
114 return $b ? "\x01" : "\x00";
115 }
116
122 public static function readByte(string $c) : int{
123 if($c === ""){
124 throw new BinaryDataException("Expected a string of length 1");
125 }
126 return ord($c[0]);
127 }
128
134 public static function readSignedByte(string $c) : int{
135 if($c === ""){
136 throw new BinaryDataException("Expected a string of length 1");
137 }
138 return self::signByte(ord($c[0]));
139 }
140
144 public static function writeByte(int $c) : string{
145 return chr($c);
146 }
147
153 public static function readShort(string $str) : int{
154 return self::safeUnpack("n", $str, self::SIZEOF_SHORT)[1];
155 }
156
162 public static function readSignedShort(string $str) : int{
163 return self::signShort(self::safeUnpack("n", $str, self::SIZEOF_SHORT)[1]);
164 }
165
169 public static function writeShort(int $value) : string{
170 return pack("n", $value);
171 }
172
178 public static function readLShort(string $str) : int{
179 return self::safeUnpack("v", $str, self::SIZEOF_SHORT)[1];
180 }
181
187 public static function readSignedLShort(string $str) : int{
188 return self::signShort(self::safeUnpack("v", $str, self::SIZEOF_SHORT)[1]);
189 }
190
194 public static function writeLShort(int $value) : string{
195 return pack("v", $value);
196 }
197
203 public static function readTriad(string $str) : int{
204 return self::safeUnpack("N", "\x00" . $str, self::SIZEOF_INT)[1];
205 }
206
210 public static function writeTriad(int $value) : string{
211 return substr(pack("N", $value), 1);
212 }
213
219 public static function readLTriad(string $str) : int{
220 return self::safeUnpack("V", $str . "\x00", self::SIZEOF_INT)[1];
221 }
222
226 public static function writeLTriad(int $value) : string{
227 return substr(pack("V", $value), 0, -1);
228 }
229
235 public static function readInt(string $str) : int{
236 return self::signInt(self::safeUnpack("N", $str, self::SIZEOF_INT)[1]);
237 }
238
242 public static function writeInt(int $value) : string{
243 return pack("N", $value);
244 }
245
251 public static function readLInt(string $str) : int{
252 return self::signInt(self::safeUnpack("V", $str, self::SIZEOF_INT)[1]);
253 }
254
258 public static function writeLInt(int $value) : string{
259 return pack("V", $value);
260 }
261
267 public static function readFloat(string $str) : float{
268 return self::safeUnpack("G", $str, self::SIZEOF_FLOAT)[1];
269 }
270
276 public static function readRoundedFloat(string $str, int $accuracy) : float{
277 return round(self::readFloat($str), $accuracy);
278 }
279
283 public static function writeFloat(float $value) : string{
284 return pack("G", $value);
285 }
286
292 public static function readLFloat(string $str) : float{
293 return self::safeUnpack("g", $str, self::SIZEOF_FLOAT)[1];
294 }
295
301 public static function readRoundedLFloat(string $str, int $accuracy) : float{
302 return round(self::readLFloat($str), $accuracy);
303 }
304
308 public static function writeLFloat(float $value) : string{
309 return pack("g", $value);
310 }
311
315 public static function printFloat(float $value) : string{
316 return preg_replace("/(\\.\\d+?)0+$/", "$1", sprintf("%F", $value));
317 }
318
324 public static function readDouble(string $str) : float{
325 return self::safeUnpack("E", $str, self::SIZEOF_DOUBLE)[1];
326 }
327
331 public static function writeDouble(float $value) : string{
332 return pack("E", $value);
333 }
334
340 public static function readLDouble(string $str) : float{
341 return self::safeUnpack("e", $str, self::SIZEOF_DOUBLE)[1];
342 }
343
347 public static function writeLDouble(float $value) : string{
348 return pack("e", $value);
349 }
350
356 public static function readLong(string $str) : int{
357 return self::safeUnpack("J", $str, self::SIZEOF_LONG)[1];
358 }
359
363 public static function writeLong(int $value) : string{
364 return pack("J", $value);
365 }
366
372 public static function readLLong(string $str) : int{
373 return self::safeUnpack("P", $str, self::SIZEOF_LONG)[1];
374 }
375
379 public static function writeLLong(int $value) : string{
380 return pack("P", $value);
381 }
382
390 public static function readVarInt(string $buffer, int &$offset) : int{
391 $raw = self::readUnsignedVarInt($buffer, $offset);
392 $temp = ((($raw << 63) >> 63) ^ $raw) >> 1;
393 return $temp ^ ($raw & (1 << 63));
394 }
395
403 public static function readUnsignedVarInt(string $buffer, int &$offset) : int{
404 $value = 0;
405 for($i = 0; $i <= 28; $i += 7){
406 if(!isset($buffer[$offset])){
407 throw new BinaryDataException("No bytes left in buffer");
408 }
409 $b = ord($buffer[$offset++]);
410 $value |= (($b & 0x7f) << $i);
411
412 if(($b & 0x80) === 0){
413 return $value;
414 }
415 }
416
417 throw new BinaryDataException("VarInt did not terminate after 5 bytes!");
418 }
419
423 public static function writeVarInt(int $v) : string{
424 $v = ($v << 32 >> 32);
425 return self::writeUnsignedVarInt(($v << 1) ^ ($v >> 31));
426 }
427
433 public static function writeUnsignedVarInt(int $value) : string{
434 $buf = "";
435 $remaining = $value & 0xffffffff;
436 for($i = 0; $i < 5; ++$i){
437 if(($remaining >> 7) !== 0){
438 $buf .= chr($remaining | 0x80);
439 }else{
440 $buf .= chr($remaining & 0x7f);
441 return $buf;
442 }
443
444 $remaining = (($remaining >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
445 }
446
447 throw new InvalidArgumentException("Value too large to be encoded as a VarInt");
448 }
449
457 public static function readVarLong(string $buffer, int &$offset) : int{
458 $raw = self::readUnsignedVarLong($buffer, $offset);
459 $temp = ((($raw << 63) >> 63) ^ $raw) >> 1;
460 return $temp ^ ($raw & (1 << 63));
461 }
462
470 public static function readUnsignedVarLong(string $buffer, int &$offset) : int{
471 $value = 0;
472 for($i = 0; $i <= 63; $i += 7){
473 if(!isset($buffer[$offset])){
474 throw new BinaryDataException("No bytes left in buffer");
475 }
476 $b = ord($buffer[$offset++]);
477 $value |= (($b & 0x7f) << $i);
478
479 if(($b & 0x80) === 0){
480 return $value;
481 }
482 }
483
484 throw new BinaryDataException("VarLong did not terminate after 10 bytes!");
485 }
486
490 public static function writeVarLong(int $v) : string{
491 return self::writeUnsignedVarLong(($v << 1) ^ ($v >> 63));
492 }
493
497 public static function writeUnsignedVarLong(int $value) : string{
498 $buf = "";
499 $remaining = $value;
500 for($i = 0; $i < 10; ++$i){
501 if(($remaining >> 7) !== 0){
502 $buf .= chr($remaining | 0x80); //Let chr() take the last byte of this, it's faster than adding another & 0x7f.
503 }else{
504 $buf .= chr($remaining & 0x7f);
505 return $buf;
506 }
507
508 $remaining = (($remaining >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
509 }
510
511 throw new InvalidArgumentException("Value too large to be encoded as a VarLong");
512 }
513}
static readRoundedLFloat(string $str, int $accuracy)
Definition: Binary.php:301
static writeShort(int $value)
Definition: Binary.php:169
static readShort(string $str)
Definition: Binary.php:153
static readDouble(string $str)
Definition: Binary.php:324
static readLLong(string $str)
Definition: Binary.php:372
static writeUnsignedVarInt(int $value)
Definition: Binary.php:433
static writeLDouble(float $value)
Definition: Binary.php:347
static writeUnsignedVarLong(int $value)
Definition: Binary.php:497
static readLong(string $str)
Definition: Binary.php:356
static writeDouble(float $value)
Definition: Binary.php:331
static readFloat(string $str)
Definition: Binary.php:267
static readUnsignedVarInt(string $buffer, int &$offset)
Definition: Binary.php:403
static writeTriad(int $value)
Definition: Binary.php:210
static readInt(string $str)
Definition: Binary.php:235
static readSignedShort(string $str)
Definition: Binary.php:162
static writeLLong(int $value)
Definition: Binary.php:379
static writeFloat(float $value)
Definition: Binary.php:283
static writeVarInt(int $v)
Definition: Binary.php:423
static writeLTriad(int $value)
Definition: Binary.php:226
static writeVarLong(int $v)
Definition: Binary.php:490
static writeLShort(int $value)
Definition: Binary.php:194
static writeLFloat(float $value)
Definition: Binary.php:308
static readLTriad(string $str)
Definition: Binary.php:219
static readUnsignedVarLong(string $buffer, int &$offset)
Definition: Binary.php:470
static writeLInt(int $value)
Definition: Binary.php:258
static writeBool(bool $b)
Definition: Binary.php:113
static readLInt(string $str)
Definition: Binary.php:251
static writeByte(int $c)
Definition: Binary.php:144
static printFloat(float $value)
Definition: Binary.php:315
static readSignedByte(string $c)
Definition: Binary.php:134
static readRoundedFloat(string $str, int $accuracy)
Definition: Binary.php:276
static readByte(string $c)
Definition: Binary.php:122
static readVarLong(string $buffer, int &$offset)
Definition: Binary.php:457
static writeInt(int $value)
Definition: Binary.php:242
static readLDouble(string $str)
Definition: Binary.php:340
static readVarInt(string $buffer, int &$offset)
Definition: Binary.php:390
static writeLong(int $value)
Definition: Binary.php:363
static readLFloat(string $str)
Definition: Binary.php:292
static readSignedLShort(string $str)
Definition: Binary.php:187
static readLShort(string $str)
Definition: Binary.php:178
static readTriad(string $str)
Definition: Binary.php:203
static readBool(string $b)
Definition: Binary.php:106