> 56; }else{ return $b << 24 >> 24; } }else{ return $b; } } /** * Writes an unsigned/signed byte * * @param $c * * @return string */ public static function writeByte($c){ return chr($c); } /** * Reads a 16-bit unsigned big-endian number * * @param $str * * @return int */ public static function readShort($str){ self::checkLength($str, 2); return unpack("n", $str)[1]; } /** * Reads a 16-bit signed big-endian number * * @param $str * * @return int */ public static function readSignedShort($str){ self::checkLength($str, 2); if(PHP_INT_SIZE === 8){ return unpack("n", $str)[1] << 48 >> 48; }else{ return unpack("n", $str)[1] << 16 >> 16; } } /** * Writes a 16-bit signed/unsigned big-endian number * * @param $value * * @return string */ public static function writeShort($value){ return pack("n", $value); } /** * Reads a 16-bit unsigned little-endian number * * @param $str * * @return int */ public static function readLShort($str){ self::checkLength($str, 2); return unpack("v", $str)[1]; } /** * Reads a 16-bit signed little-endian number * * @param $str * * @return int */ public static function readSignedLShort($str){ self::checkLength($str, 2); if(PHP_INT_SIZE === 8){ return unpack("v", $str)[1] << 48 >> 48; }else{ return unpack("v", $str)[1] << 16 >> 16; } } /** * Writes a 16-bit signed/unsigned little-endian number * * @param $value * * @return string */ public static function writeLShort($value){ return pack("v", $value); } public static function readInt($str){ self::checkLength($str, 4); if(PHP_INT_SIZE === 8){ return unpack("N", $str)[1] << 32 >> 32; }else{ return unpack("N", $str)[1]; } } public static function writeInt($value){ return pack("N", $value); } public static function readLInt($str){ self::checkLength($str, 4); if(PHP_INT_SIZE === 8){ return unpack("V", $str)[1] << 32 >> 32; }else{ return unpack("V", $str)[1]; } } public static function writeLInt($value){ return pack("V", $value); } public static function readFloat($str, int $accuracy = -1){ self::checkLength($str, 4); $value = ENDIANNESS === self::BIG_ENDIAN ? unpack("f", $str)[1] : unpack("f", strrev($str))[1]; if($accuracy > -1){ return round($value, $accuracy); }else{ return $value; } } public static function writeFloat($value){ return ENDIANNESS === self::BIG_ENDIAN ? pack("f", $value) : strrev(pack("f", $value)); } public static function readLFloat($str, int $accuracy = -1){ self::checkLength($str, 4); $value = ENDIANNESS === self::BIG_ENDIAN ? unpack("f", strrev($str))[1] : unpack("f", $str)[1]; if($accuracy > -1){ return round($value, $accuracy); }else{ return $value; } } public static function writeLFloat($value){ return ENDIANNESS === self::BIG_ENDIAN ? strrev(pack("f", $value)) : pack("f", $value); } public static function printFloat($value){ return preg_replace("/(\\.\\d+?)0+$/", "$1", sprintf("%F", $value)); } public static function readDouble($str){ self::checkLength($str, 8); return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", $str)[1] : unpack("d", strrev($str))[1]; } public static function writeDouble($value){ return ENDIANNESS === self::BIG_ENDIAN ? pack("d", $value) : strrev(pack("d", $value)); } public static function readLDouble($str){ self::checkLength($str, 8); return ENDIANNESS === self::BIG_ENDIAN ? unpack("d", strrev($str))[1] : unpack("d", $str)[1]; } public static function writeLDouble($value){ return ENDIANNESS === self::BIG_ENDIAN ? strrev(pack("d", $value)) : pack("d", $value); } public static function readLong($x){ self::checkLength($x, 8); if(PHP_INT_SIZE === 8){ $int = unpack("N*", $x); return ($int[1] << 32) | $int[2]; }else{ $value = "0"; for($i = 0; $i < 8; $i += 2){ $value = bcmul($value, "65536", 0); $value = bcadd($value, self::readShort(substr($x, $i, 2)), 0); } if(bccomp($value, "9223372036854775807") == 1){ $value = bcadd($value, "-18446744073709551616"); } return $value; } } public static function writeLong($value){ if(PHP_INT_SIZE === 8){ return pack("NN", $value >> 32, $value & 0xFFFFFFFF); }else{ $x = ""; if(bccomp($value, "0") == -1){ $value = bcadd($value, "18446744073709551616"); } $x .= self::writeShort(bcmod(bcdiv($value, "281474976710656"), "65536")); $x .= self::writeShort(bcmod(bcdiv($value, "4294967296"), "65536")); $x .= self::writeShort(bcmod(bcdiv($value, "65536"), "65536")); $x .= self::writeShort(bcmod($value, "65536")); return $x; } } public static function readLLong($str){ return self::readLong(strrev($str)); } public static function writeLLong($value){ return strrev(self::writeLong($value)); } //TODO: proper varlong support public static function readVarInt($stream){ $shift = PHP_INT_SIZE === 8 ? 63 : 31; $raw = self::readUnsignedVarInt($stream); $temp = ((($raw << $shift) >> $shift) ^ $raw) >> 1; return $temp ^ ($raw & (1 << $shift)); } public static function readUnsignedVarInt($stream){ $value = 0; $i = 0; do{ if($i > 63){ throw new \InvalidArgumentException("Varint did not terminate after 10 bytes!"); } $value |= ((($b = $stream->getByte()) & 0x7f) << $i); $i += 7; }while($b & 0x80); return $value; } public static function writeVarInt($v){ return self::writeUnsignedVarInt(($v << 1) ^ ($v >> (PHP_INT_SIZE === 8 ? 63 : 31))); } public static function writeUnsignedVarInt($value){ $buf = ""; for($i = 0; $i < 10; ++$i){ if(($value >> 7) !== 0){ $buf .= chr($value | 0x80); //Let chr() take the last byte of this, it's faster than adding another & 0x7f. }else{ $buf .= chr($value & 0x7f); return $buf; } $value = (($value >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator } throw new \InvalidArgumentException("Value too large to be encoded as a varint"); } }