<?php declare(strict_types=1); /** * @author Pavel Djundik * * @link https://xpaw.me * @link 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; /** * Class Buffer * * @package xPaw\SourceQuery * * @uses 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; } /** * Gets data from buffer * * @param int $Length Bytes to read */ public function Get(int $Length = -1): string { if ($Length === 0) { return ''; } $Remaining = $this->Remaining(); if ($Length === -1) { $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 */ 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)); return (int)$Data[ 1 ]; } /** * Get long from buffer */ 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)); return (int)$Data[ 1 ]; } /** * Get float from buffer */ 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)); return (float)$Data[ 1 ]; } /** * Get unsigned long from buffer */ 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)); 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 ($ZeroBytePosition === false) { return ''; } $String = $this->Get($ZeroBytePosition - $this->Position); $this->Position++; return $String; } }