PocketMine-MP 5.39.3 git-9a46a8bd745880ddf8eebaf28cda326bb97d2efa
Loading...
Searching...
No Matches
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 & 0xff);
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 $bits = $remaining & 0x7f;
438 if(($remaining >> 7) !== 0){
439 $buf .= chr($bits | 0x80);
440 }else{
441 $buf .= chr($bits & 0x7f);
442 return $buf;
443 }
444
445 $remaining = (($remaining >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
446 }
447
448 throw new InvalidArgumentException("Value too large to be encoded as a VarInt");
449 }
450
458 public static function readVarLong(string $buffer, int &$offset) : int{
459 $raw = self::readUnsignedVarLong($buffer, $offset);
460 $temp = ((($raw << 63) >> 63) ^ $raw) >> 1;
461 return $temp ^ ($raw & (1 << 63));
462 }
463
471 public static function readUnsignedVarLong(string $buffer, int &$offset) : int{
472 $value = 0;
473 for($i = 0; $i <= 63; $i += 7){
474 if(!isset($buffer[$offset])){
475 throw new BinaryDataException("No bytes left in buffer");
476 }
477 $b = ord($buffer[$offset++]);
478 $value |= (($b & 0x7f) << $i);
479
480 if(($b & 0x80) === 0){
481 return $value;
482 }
483 }
484
485 throw new BinaryDataException("VarLong did not terminate after 10 bytes!");
486 }
487
491 public static function writeVarLong(int $v) : string{
492 return self::writeUnsignedVarLong(($v << 1) ^ ($v >> 63));
493 }
494
498 public static function writeUnsignedVarLong(int $value) : string{
499 $buf = "";
500 $remaining = $value;
501 for($i = 0; $i < 10; ++$i){
502 $bits = $remaining & 0x7f;
503 if(($remaining >> 7) !== 0){
504 $buf .= chr($bits | 0x80);
505 }else{
506 $buf .= chr($bits & 0x7f);
507 return $buf;
508 }
509
510 $remaining = (($remaining >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
511 }
512
513 throw new InvalidArgumentException("Value too large to be encoded as a VarLong");
514 }
515}
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:498
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:491
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:471
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:458
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