Skip to content
Closed
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ jobs:
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
php: ['8.1', '8.2', '8.3', '8.4']


steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@2.32.0
uses: shivammathur/setup-php@2.35.4
with:
php-version: ${{ matrix.php }}
ini-values: xdebug.max_nesting_level=3000
extensions: encoding-pmmp/[email protected]

- name: Cache Composer packages
id: composer-cache
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
"description": "PHP library for working with Named Binary Tags",
"type": "library",
"require": {
"php": "^7.4 || ^8.0",
"php": "^8.1",
"php-64bit": "*",
"pocketmine/binaryutils": "^0.2.0"
"ext-encoding": "~1.0.0"
},
"require-dev": {
"phpstan/phpstan": "2.1.27",
Expand Down
74 changes: 37 additions & 37 deletions src/BaseNbtSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,26 @@

namespace pocketmine\nbt;

use pmmp\encoding\Byte;
use pmmp\encoding\ByteBufferReader;
use pmmp\encoding\ByteBufferWriter;
use pmmp\encoding\DataDecodeException;
use pocketmine\nbt\tag\Tag;
use pocketmine\utils\Binary;
use pocketmine\utils\BinaryDataException;
use pocketmine\utils\BinaryStream;
use function strlen;

/**
* Base Named Binary Tag encoder/decoder
*/
abstract class BaseNbtSerializer implements NbtStreamReader, NbtStreamWriter{
/** @var BinaryStream */
protected $buffer;

public function __construct(){
$this->buffer = new BinaryStream();
}
protected ByteBufferReader $reader;
protected ByteBufferWriter $writer;

/**
* @throws BinaryDataException
* @throws DataDecodeException
* @throws NbtDataException
*/
private function readRoot(int $maxDepth) : TreeRoot{
$type = $this->readByte();
$type = Byte::readUnsigned($this->reader);
if($type === NBT::TAG_End){
throw new NbtDataException("Found TAG_End at the start of buffer");
}
Expand All @@ -62,14 +59,15 @@ private function readRoot(int $maxDepth) : TreeRoot{
* @throws NbtDataException
*/
public function read(string $buffer, int &$offset = 0, int $maxDepth = 0) : TreeRoot{
$this->buffer = new BinaryStream($buffer, $offset);
$this->reader = new ByteBufferReader($buffer);
$this->reader->setOffset($offset);

try{
$data = $this->readRoot($maxDepth);
}catch(BinaryDataException $e){
}catch(DataDecodeException $e){
throw new NbtDataException($e->getMessage(), 0, $e);
}
$offset = $this->buffer->getOffset();
$offset = $this->reader->getOffset();

return $data;
}
Expand All @@ -85,10 +83,11 @@ public function read(string $buffer, int &$offset = 0, int $maxDepth = 0) : Tree
* @throws NbtDataException
*/
public function readHeadless(string $buffer, int $rootType, int &$offset = 0, int $maxDepth = 0) : Tag{
$this->buffer = new BinaryStream($buffer, $offset);
$this->reader = new ByteBufferReader($buffer);
$this->reader->setOffset($offset);

$data = NBT::createTag($rootType, $this, new ReaderTracker($maxDepth));
$offset = $this->buffer->getOffset();
$offset = $this->reader->getOffset();

return $data;
}
Expand All @@ -103,14 +102,15 @@ public function readHeadless(string $buffer, int $rootType, int &$offset = 0, in
* @throws NbtDataException
*/
public function readMultiple(string $buffer, int $maxDepth = 0) : array{
$this->buffer = new BinaryStream($buffer);
$this->reader = new ByteBufferReader($buffer);

$retval = [];

while(!$this->buffer->feof()){
$length = strlen($this->reader->getData());
while($this->reader->getOffset() < $length){
try{
$retval[] = $this->readRoot($maxDepth);
}catch(BinaryDataException $e){
}catch(DataDecodeException $e){
throw new NbtDataException($e->getMessage(), 0, $e);
}
}
Expand All @@ -119,17 +119,17 @@ public function readMultiple(string $buffer, int $maxDepth = 0) : array{
}

private function writeRoot(TreeRoot $root) : void{
$this->writeByte($root->getTag()->getType());
Byte::writeUnsigned($this->writer, $root->getTag()->getType());
$this->writeString($root->getName());
$root->getTag()->write($this);
}

public function write(TreeRoot $data) : string{
$this->buffer = new BinaryStream();
$this->writer = new ByteBufferWriter();

$this->writeRoot($data);

return $this->buffer->getBuffer();
return $this->writer->getData();
}

/**
Expand All @@ -139,53 +139,53 @@ public function write(TreeRoot $data) : string{
* @see BaseNbtSerializer::readHeadless()
*/
public function writeHeadless(Tag $data) : string{
$this->buffer = new BinaryStream();
$this->writer = new ByteBufferWriter();
$data->write($this);
return $this->buffer->getBuffer();
return $this->writer->getData();
}

/**
* @param TreeRoot[] $data
*/
public function writeMultiple(array $data) : string{
$this->buffer = new BinaryStream();
$this->writer = new ByteBufferWriter();
foreach($data as $root){
$this->writeRoot($root);
}
return $this->buffer->getBuffer();
return $this->writer->getData();
}

public function readByte() : int{
return $this->buffer->getByte();
return Byte::readUnsigned($this->reader);
}

public function readSignedByte() : int{
return Binary::signByte($this->buffer->getByte());
return Byte::readSigned($this->reader);
}

public function writeByte(int $v) : void{
$this->buffer->putByte($v);
Byte::writeUnsigned($this->writer, $v);
}

public function readByteArray() : string{
$length = $this->readInt();
if($length < 0){
throw new NbtDataException("Array length cannot be less than zero ($length < 0)");
}
return $this->buffer->get($length);
return $this->reader->readByteArray($length);
}

public function writeByteArray(string $v) : void{
$this->writeInt(strlen($v)); //TODO: overflow
$this->buffer->put($v);
$this->writer->writeByteArray($v);
}

/**
* @throws NbtDataException
*/
protected static function checkReadStringLength(int $len) : int{
if($len > 32767){
throw new NbtDataException("NBT string length too large ($len > 32767)");
if($len > NBT::MAX_STRING_LENGTH){
throw new NbtDataException("NBT string length too large ($len > " . NBT::MAX_STRING_LENGTH . ")");
}
return $len;
}
Expand All @@ -194,21 +194,21 @@ protected static function checkReadStringLength(int $len) : int{
* @throws \InvalidArgumentException
*/
protected static function checkWriteStringLength(int $len) : int{
if($len > 32767){
throw new \InvalidArgumentException("NBT string length too large ($len > 32767)");
if($len > NBT::MAX_STRING_LENGTH){
throw new \InvalidArgumentException("NBT string length too large ($len > " . NBT::MAX_STRING_LENGTH . ")");
}
return $len;
}

public function readString() : string{
return $this->buffer->get(self::checkReadStringLength($this->readShort()));
return $this->reader->readByteArray(self::checkReadStringLength($this->readShort()));
}

/**
* @throws \InvalidArgumentException if the string is too long
*/
public function writeString(string $v) : void{
$this->writeShort(self::checkWriteStringLength(strlen($v)));
$this->buffer->put($v);
$this->writer->writeByteArray($v);
}
}
27 changes: 14 additions & 13 deletions src/BigEndianNbtSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace pocketmine\nbt;

use pmmp\encoding\BE;
use function array_values;
use function assert;
use function count;
Expand All @@ -32,47 +33,47 @@
class BigEndianNbtSerializer extends BaseNbtSerializer{

public function readShort() : int{
return $this->buffer->getShort();
return BE::readUnsignedShort($this->reader);
}

public function readSignedShort() : int{
return $this->buffer->getSignedShort();
return BE::readSignedShort($this->reader);
}

public function writeShort(int $v) : void{
$this->buffer->putShort($v);
BE::writeUnsignedShort($this->writer, $v);
}

public function readInt() : int{
return $this->buffer->getInt();
return BE::readSignedInt($this->reader);
}

public function writeInt(int $v) : void{
$this->buffer->putInt($v);
BE::writeSignedInt($this->writer, $v);
}

public function readLong() : int{
return $this->buffer->getLong();
return BE::readSignedLong($this->reader);
}

public function writeLong(int $v) : void{
$this->buffer->putLong($v);
BE::writeSignedLong($this->writer, $v);
}

public function readFloat() : float{
return $this->buffer->getFloat();
return BE::readFloat($this->reader);
}

public function writeFloat(float $v) : void{
$this->buffer->putFloat($v);
BE::writeFloat($this->writer, $v);
}

public function readDouble() : float{
return $this->buffer->getDouble();
return BE::readDouble($this->reader);
}

public function writeDouble(float $v) : void{
$this->buffer->putDouble($v);
BE::writeDouble($this->writer, $v);
}

public function readIntArray() : array{
Expand All @@ -81,13 +82,13 @@ public function readIntArray() : array{
throw new NbtDataException("Array length cannot be less than zero ($len < 0)");
}
/** @var array<int>|false $unpacked */
$unpacked = unpack("N*", $this->buffer->get($len * 4));
$unpacked = unpack("N*", $this->reader->readByteArray($len * 4));
assert($unpacked !== false, "The formatting string is valid, and we gave a multiple of 4 bytes");
return array_values($unpacked);
}

public function writeIntArray(array $array) : void{
$this->writeInt(count($array));
$this->buffer->put(pack("N*", ...$array));
$this->writer->writeByteArray(pack("N*", ...$array));
}
}
Loading