You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Test-Miroir/SourceQuery/Buffer.php

194 lines
4.0 KiB

<?php
declare(strict_types=1);
/**
* @author Pavel Djundik
*
* @see https://xpaw.me
* @see https://github.com/xPaw/PHP-Source-Query
*
* @license GNU Lesser General Public License, version 2.1
*
* @internal
*/
namespace xPaw\SourceQuery;
use xPaw\SourceQuery\Exception\InvalidPacketException;
final class Buffer
{
/**
* Buffer.
*/
private string $buffer = '';
/**
* Buffer length.
*/
private int $length = 0;
/**
* Current position in buffer.
*/
private int $position = 0;
/**
* Sets buffer.
*/
public function set(string $buffer): void
{
$this->buffer = $buffer;
$this->length = strlen($buffer);
$this->position = 0;
}
/**
* Get remaining bytes.
*
* @return int Remaining bytes in buffer
*/
public function remaining(): int
{
return $this->length - $this->position;
}
public function isEmpty(): bool
{
return $this->remaining() <= 0;
}
/**
* Gets data from buffer.
*
* @param int $length Bytes to read
*/
public function get(int $length = -1): string
{
if (0 === $length) {
return '';
}
$remaining = $this->remaining();
if (-1 === $length) {
$length = $remaining;
} elseif ($length > $remaining) {
return '';
}
$data = substr($this->buffer, $this->position, $length);
$this->position += $length;
return $data;
}
/**
* Get byte from buffer.
*/
public function getByte(): int
{
return ord($this->get(1));
}
/**
* Get short from buffer.
*
* @throws InvalidPacketException
*/
public function getShort(): int
{
if ($this->remaining() < 2) {
throw new InvalidPacketException('Not enough data to unpack a short.', InvalidPacketException::BUFFER_EMPTY);
}
$data = unpack('v', $this->get(2));
if (!$data) {
throw new InvalidPacketException('Empty data from packet.');
}
return (int) $data[1];
}
/**
* Get long from buffer.
*
* @throws InvalidPacketException
*/
public function getLong(): int
{
if ($this->remaining() < 4) {
throw new InvalidPacketException('Not enough data to unpack a long.', InvalidPacketException::BUFFER_EMPTY);
}
$data = unpack('l', $this->get(4));
if (!$data) {
throw new InvalidPacketException('Empty data from packet.');
}
return (int) $data[1];
}
/**
* Get float from buffer.
*
* @throws InvalidPacketException
*/
public function getFloat(): float
{
if ($this->remaining() < 4) {
throw new InvalidPacketException('Not enough data to unpack a float.', InvalidPacketException::BUFFER_EMPTY);
}
$data = unpack('f', $this->get(4));
if (!$data) {
throw new InvalidPacketException('Empty data from packet.');
}
return (float) $data[1];
}
/**
* Get unsigned long from buffer.
*
* @throws InvalidPacketException
*/
public function getUnsignedLong(): int
{
if ($this->remaining() < 4) {
throw new InvalidPacketException('Not enough data to unpack an usigned long.', InvalidPacketException::BUFFER_EMPTY);
}
$data = unpack('V', $this->get(4));
if (!$data) {
throw new InvalidPacketException('Empty data from packet.');
}
return (int) $data[1];
}
/**
* Read one string from buffer ending with null byte.
*/
public function getString(): string
{
$zeroBytePosition = strpos($this->buffer, "\0", $this->position);
if (false === $zeroBytePosition) {
return '';
}
$string = $this->get($zeroBytePosition - $this->position);
++$this->position;
return $string;
}
}